pax_global_header00006660000000000000000000000064141231750470014516gustar00rootroot0000000000000052 comment=5b1bcd366855c349dad12f9ac6cc59ae9bf23201 miragejs-0.1.42/000077500000000000000000000000001412317504700134035ustar00rootroot00000000000000miragejs-0.1.42/.dependabot/000077500000000000000000000000001412317504700155665ustar00rootroot00000000000000miragejs-0.1.42/.dependabot/config.yml000066400000000000000000000003301412317504700175520ustar00rootroot00000000000000version: 1 update_configs: - package_manager: "javascript" directory: "/" update_schedule: "daily" automerged_updates: - match: dependency_type: "all" update_type: "in_range" miragejs-0.1.42/.env000066400000000000000000000000171412317504700141720ustar00rootroot00000000000000NODE_PATH=lib/ miragejs-0.1.42/.eslintignore000066400000000000000000000001021412317504700160770ustar00rootroot00000000000000# compiled output /dist/ /tmp/ # misc /coverage/ # types /types miragejs-0.1.42/.eslintrc.js000066400000000000000000000024061412317504700156440ustar00rootroot00000000000000module.exports = { root: true, parser: "babel-eslint", plugins: ["import"], extends: [ "eslint:recommended", "plugin:import/errors", "plugin:prettier/recommended", ], env: { es6: true, node: true, browser: true, }, rules: { camelcase: 0, "object-curly-spacing": 0, quotes: 0, "array-bracket-spacing": 0, "no-var": 0, "object-shorthand": 0, "arrow-parens": 0, "no-unused-vars": ["error", { args: "none" }], "import/no-extraneous-dependencies": [ "error", { devDependencies: ["__tests__", "*.config.js"] }, ], }, overrides: [ { files: [ "jest.config.js", "babel.config.js", "rollup.config.js", "rollup.test.config.js", ], env: { browser: false, node: true, }, }, { files: ["__tests__/**"], plugins: ["jest"], env: { "jest/globals": true, }, extends: ["plugin:jest/recommended", "plugin:jest/style"], rules: { "jest/no-conditional-expect": "off", }, }, ], settings: { "import/resolver": { alias: [ ["@lib", "./lib"], ["miragejs", "./index"], ], node: { extensions: ["js"], }, }, }, }; miragejs-0.1.42/.gitignore000066400000000000000000000004161412317504700153740ustar00rootroot00000000000000# See https://help.github.com/ignore-files/ for more about ignoring files. # compiled output /dist/ /tmp/ # dependencies /node_modules/ # misc /.vscode /.sass-cache /connect.lock /coverage/ /libpeerconnection.log /npm-debug.log* /yarn-error.log # IDE /.idea/ /*.iml miragejs-0.1.42/.npmignore000066400000000000000000000002461412317504700154040ustar00rootroot00000000000000# misc /.eslintignore /.eslintrc.js /.gitignore /.watchmanconfig /.travis.yml /tmp **/.gitkeep /__tests__/ /tests/ /yarn.lock .gitkeep /.sass-cache /jekyll-tmp *.md miragejs-0.1.42/.prettierignore000066400000000000000000000000051412317504700164410ustar00rootroot00000000000000/distmiragejs-0.1.42/.travis.yml000066400000000000000000000027561412317504700155260ustar00rootroot00000000000000--- language: node_js node_js: - "12" sudo: false dist: trusty addons: chrome: stable cache: yarn: true install: - yarn install --no-lockfile --non-interactive notifications: email: false # Identifies `a.b.c-xxx.n` tags as pre-releases, and `a.b.c` as stable releases before_deploy: | function npm_dist_tag() { if [[ "$TRAVIS_TAG" = *"-"* ]]; then echo "next" else echo "latest" fi } jobs: fail_fast: true include: - stage: tests env: NAME=tests install: yarn install script: yarn ci - stage: npm release script: skip deploy: skip_cleanup: true provider: npm tag: $(npm_dist_tag) email: sam.selikoff@gmail.com api_key: secure: opUbyx91tWudkYlFmysdGjNLS3hcyUwL9nquwt4Xtel7w1ylenoBeiclwtwfRaVJpOkevFmycdGo7f3XjUwJypAfLx0+qMHc8P99hBn1rHJGNjGm5/oi3zuCwBDGsHALBqzu99l6CKNbMYcGIxrsjshL5EOvMAkLgZjuEJ1+hsyVaasG9qbDNkEz0PfJCPJYpHCAmEnYK6gL4ZZHlvje4CUgg5SjJKKvC7OhW03IyDjvCziHIVDxAB4BBEZmlC3nHSNKhe/LJrB/+HWY/SqVMFm1reF099G3G8zr+wyStVKqW8gO2ZejiDrw73N62iqrPcSkq72Nym1+TSz0yRjaPUu3JuQbzzCnJROrnWuD7ItlxwbPSOWTPMMSxlg/yrU5qVXNjHSTvYSn0VJBz7fy/MxiTSuz5+Ua2xOU7KpEP6RhVo0qHssDKm2wQ6rce4kNKXvKTkJ2dYTIBsojk8tELIupvas4ck8Dpt8yAxy6nJkEU+2skuM0JgqME32J1in2rQ/Ip/aa2RnTYgiiNZtxvqZBoM50sXiHFKZXOQsNL09/OvpYXNIDD10sALXLqfz3hUHqaMNmmEWSM7Xzz6/3duB/BqvGWXdetnf/KhTH+IlQVM5j/JYC/lT3M2aGWIpS0iwfMaSUgzuuNoccmlauaYOXnwNeDT6RTx1oMA0+PW0= on: tags: true repo: miragejs/miragejs miragejs-0.1.42/.watchmanconfig000066400000000000000000000000451412317504700163730ustar00rootroot00000000000000{ "ignore_dirs": ["tmp", "dist"] } miragejs-0.1.42/CHANGELOG.md000066400000000000000000000002351412317504700152140ustar00rootroot00000000000000# Mirage Change log Releases (along with upgrade instructions) are documented on the Github [Releases](https://github.com/miragejs/miragejs/releases) page. miragejs-0.1.42/LICENSE.md000066400000000000000000000020521412317504700150060ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. miragejs-0.1.42/README.md000066400000000000000000000005771412317504700146730ustar00rootroot00000000000000# Mirage JS [![npm version](https://badge.fury.io/js/miragejs.svg)](https://badge.fury.io/js/miragejs) [![Build Status](https://travis-ci.com/miragejs/miragejs.svg?branch=master)](https://travis-ci.com/github/miragejs/miragejs) A client-side server to develop, test and prototype your JavaScript app. ## Documentation Visit [miragejs.com](https://miragejs.com) to read the docs. miragejs-0.1.42/__tests__/000077500000000000000000000000001412317504700153415ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/000077500000000000000000000000001412317504700171635ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/browser-only/000077500000000000000000000000001412317504700216255ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/browser-only/fetch-sanity-check-test.js000066400000000000000000000052641412317504700266200ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External |Browser only | Fetch sanity check", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { contact: Model, }, }); }); afterEach(() => { server.shutdown(); }); test("mirage responds to get", async () => { expect.assertions(1); server.get("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "GET" }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); test("mirage responds to post", async () => { expect.assertions(1); server.post("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "POST", }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); test("mirage responds to put", async () => { expect.assertions(1); server.put("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "PUT", url: "/contacts", }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); test("mirage responds to delete", async () => { expect.assertions(1); server.delete("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "DELETE", url: "/contacts", }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); test("mirage responds to patch", async () => { expect.assertions(1); server.patch("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "PATCH", }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); test("mirage responds to resource", async () => { expect.assertions(1); server.resource("contacts"); let res = await fetch("/contacts", { method: "GET" }); let data = await res.json(); expect(data).toEqual({ contacts: [] }); }); test("response code can be customized", async () => { expect.assertions(1); server.get("/contacts", {}, 404); let res = await fetch("/contacts", { method: "GET", }); expect(res.status).toEqual(404); }); test("mirage responds to options", async () => { expect.assertions(1); server.options("/contacts", function () { return { some: "data" }; }); let res = await fetch("/contacts", { method: "OPTIONS", }); let data = await res.json(); expect(data).toEqual({ some: "data" }); }); }); miragejs-0.1.42/__tests__/external/browser-only/passthrough-test.js000066400000000000000000000124741412317504700255170ustar00rootroot00000000000000import { Server } from "miragejs"; describe("External | Browser only | Passthrough", () => { let server, originalError; beforeEach(() => { server = new Server({ environment: "test", }); /* Waiting to hear back on this: https://stackoverflow.com/questions/57227095/how-can-i-catch-or-suppress-a-rejected-network-request-from-jest For now, suppress console error messages */ originalError = console.error; console.error = () => {}; }); afterEach(() => { server.shutdown(); console.error = originalError; }); test("it can passthrough individual paths", async () => { expect.assertions(2); server.loadConfig(function () { this.get("/contacts", function () { return 123; }); this.passthrough("/addresses"); }); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual(123); await expect(fetch("/addresses")).rejects.toThrow(`Network request failed`); }); test("it can passthrough certain verbs for individual paths", async () => { expect.assertions(3); server.loadConfig(function () { this.get("/contacts", function () { return 123; }); this.passthrough("/addresses", ["post"]); }); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual(123); await expect(fetch("/addresses")).rejects.toThrow( `Mirage: Your app tried to GET '/addresses', but there was no route defined to handle this request` ); await expect(fetch("/addresses", { method: "POST" })).rejects.toThrow( `Network request failed` ); }); test("it can passthrough all verbs by default", async () => { let verbs = ["GET", "HEAD", "PUT", "POST", "PATCH", "DELETE", "OPTIONS"]; expect.assertions(7); server.loadConfig(function () { this.passthrough("/addresses"); }); for (let method of verbs) { await expect(fetch("/addresses", { method })).rejects.toThrow( "Network request failed" ); } }); test("it can passthrough multiple paths in a single call", async () => { expect.assertions(2); server.loadConfig(function () { this.get("/contacts", function () { return 123; }); this.passthrough("/contacts", "/addresses"); }); await expect(fetch("/contacts")).rejects.toThrow("Network request failed"); await expect(fetch("/addresses")).rejects.toThrow("Network request failed"); }); test("user can call passthrough multiple times", async () => { expect.assertions(2); server.loadConfig(function () { this.passthrough("/contacts"); this.passthrough("/addresses", ["post"]); }); await expect(fetch("/contacts")).rejects.toThrow("Network request failed"); await expect(fetch("/addresses", { method: "POST" })).rejects.toThrow( "Network request failed" ); }); test("passthrough without args allows all paths on the current domain to passthrough", async () => { expect.assertions(2); server.loadConfig(function () { this.get("/contacts", function () { return 123; }); this.passthrough(); }); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual(123); await expect(fetch("/addresses")).rejects.toThrow("Network request failed"); }); test("passthrough without args allows index route on current domain to passthrough", async () => { expect.assertions(2); server.loadConfig(function () { this.get("/contacts", function () { return 123; }); this.passthrough(); }); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual(123); await expect(fetch("/")).rejects.toThrow("Network request failed"); }); test("it can passthrough other-origin hosts", async () => { expect.assertions(1); server.loadConfig(function () { this.passthrough("http://api.foo.bar/**"); }); await expect(fetch("http://api.foo.bar/addresses")).rejects.toThrow( "Network request failed" ); }); test("it can take a function", async () => { server.config({ routes() { this.passthrough((request) => { return request.url.match(/users/); }); }, }); await expect(fetch("/users?test=withQueryParams")).rejects.toThrow( "Network request failed" ); await expect(fetch("/movies")).rejects.toThrow( `Mirage: Your app tried to GET '/movies'` ); }); test("it passes through common build tool-related paths", async () => { await expect(fetch("/abc.hot-update.json")).rejects.toThrow( "Network request failed" ); await expect(fetch("/movies")).rejects.toThrow( `Mirage: Your app tried to GET '/movies'` ); await expect(fetch("/def.hot-update.json")).rejects.toThrow( "Network request failed" ); await expect(fetch("/movies")).rejects.toThrow( `Mirage: Your app tried to GET '/movies'` ); }); }); test("a new server created with useDefaultPassthroughs set to false ignores default passthrougsh", async () => { let server = new Server({ useDefaultPassthroughs: false, }); await expect(fetch("/abc.hot-update.json")).rejects.toThrow( "Mirage: Your app tried to GET '/abc.hot-update.json'" ); server.shutdown(); }); miragejs-0.1.42/__tests__/external/node-only/000077500000000000000000000000001412317504700210675ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/node-only/interceptor-test.js000066400000000000000000000007011412317504700247360ustar00rootroot00000000000000import { Server } from "miragejs"; describe("External |Node only | Interceptor", () => { test("newing a server with various interceptor config works in node", () => { let server = new Server({ environment: "test", routes() { this.namespace = "api"; this.resource("user"); this.passthrough(); }, }); server.timing = 1000; expect(server).toBeTruthy(); server.shutdown(); }); }); miragejs-0.1.42/__tests__/external/shared/000077500000000000000000000000001412317504700204315ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/factories/000077500000000000000000000000001412317504700224105ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/factories/after-create-test.js000066400000000000000000000025661412317504700262760ustar00rootroot00000000000000import { Model, Factory, belongsTo, Server } from "miragejs"; describe("External | Shared | Factories | afterCreate", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { author: Model, post: Model.extend({ author: belongsTo(), }), comment: Model.extend({ post: belongsTo(), }), }, factories: { author: Factory.extend({ afterCreate(author, server) { author.update({ name: "Sam" }); server.create("post", { author }); }, }), post: Factory.extend({ title: "Lorem ipsum", afterCreate(post, server) { server.create("comment", { post }); }, }), comment: Factory.extend({ text: "Yo soy el nino", }), }, }); }); afterEach(() => { server.shutdown(); }); test("it works for models", () => { let author = server.create("author"); expect(author.name).toEqual("Sam"); expect(server.db.posts).toHaveLength(1); expect(server.db.posts[0]).toEqual({ id: "1", title: "Lorem ipsum", authorId: "1", }); expect(server.db.comments).toHaveLength(1); expect(server.db.comments[0]).toEqual({ id: "1", text: "Yo soy el nino", postId: "1", }); }); }); miragejs-0.1.42/__tests__/external/shared/factories/create-and-create-list-test.js000066400000000000000000000124671412317504700301520ustar00rootroot00000000000000import { Server, Model, Factory, hasMany, belongsTo } from "miragejs"; import { inflections, pluralize, singularize } from "inflected"; // eslint-disable-next-line no-console let originalWarn = console.warn; function expectNoWarning() { // eslint-disable-next-line no-console console.warn = () => { expect(true).toBeFalsy(); }; } describe("External | Shared | Factories | create and createList", function () { let server, Contact, AmazingContact, Post, Author, Data; beforeEach(function () { inflections("en", (inflect) => { inflect.uncountable("data"); }); Contact = Model.extend(); AmazingContact = Model.extend(); Post = Model.extend({ author: belongsTo(), }); Author = Model.extend({ posts: hasMany(), }); Data = Model.extend(); server = new Server({ environment: "test", inflector: { pluralize, singularize }, models: { contact: Contact, amazingContact: AmazingContact, post: Post, author: Author, data: Data, }, factories: { contact: Factory.extend({ name: "Yehuda", }), amazingContact: Factory, }, }); }); afterEach(function () { server.shutdown(); // eslint-disable-next-line no-console console.warn = originalWarn; }); test("create throws when passing in an undefined model", () => { expectNoWarning(); expect(() => { server.create("foo"); }).toThrow( `You called server.create('foo') but no model or factory was found.` ); }); // This used to be deprecated behavior, but now it errors. So we test it separately from the nonsense test above. test("create throws when passing in a pluralized version of a model", () => { expect.assertions(1); expect(() => { server.create("contacts"); }).toThrow( `You called server.create('contacts') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name` ); }); test("create returns a Model if one is defined", () => { expectNoWarning(); let contact = server.create("contact"); expect(contact instanceof Contact).toBeTruthy(); expect(contact.name).toEqual("Yehuda"); }); test("create returns a Model instance if the Model name is uncountable", () => { expectNoWarning(); let data = server.create("data"); expect(data instanceof Data).toBeTruthy(); }); test("createList throws when passing in an undefined model", () => { expectNoWarning(); expect(() => { server.createList("foo", 1); }).toThrow( `You called server.createList('foo') but no model or factory was found.` ); }); // This used to be deprecated behavior, but now it errors. So we test it separately from the nonsense test above. test("createList throws when passing in a pluralized version of a model", () => { expect.assertions(1); expect(() => { server.createList("contacts", 1); }).toThrow( `You called server.createList('contacts') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name.` ); }); test("createList returns Models if one is defined", () => { expectNoWarning(); let contacts = server.createList("contact", 1); expect(contacts[0] instanceof Contact).toBeTruthy(); expect(contacts[0].name).toEqual("Yehuda"); }); test("createList returns Models if the model name is uncountable", () => { expectNoWarning(); let data = server.createList("data", 1); expect(data[0] instanceof Data).toBeTruthy(); }); test("create returns a Model if one is defined, when using a compound name", () => { expectNoWarning(); let contact = server.create("amazing-contact"); expect(contact instanceof AmazingContact).toBeTruthy(); }); test("createList returns Models if one is defined, when using a compound name", () => { expectNoWarning(); let contacts = server.createList("amazing-contact", 1); expect(contacts[0] instanceof AmazingContact).toBeTruthy(); }); test("create falls back to a model if no factory is defined", () => { expectNoWarning(); let post = server.create("post"); expect(post instanceof Post).toBeTruthy(); expect(post.id).toEqual("1"); }); test("createList falls back to a model if no factory is defined", () => { expectNoWarning(); let posts = server.createList("post", 2); expect(posts[0] instanceof Post).toBeTruthy(); expect(posts).toHaveLength(2); expect(posts[0].id).toEqual("1"); }); test("create sets up the db correctly when passing in fks", () => { expectNoWarning(); let author = server.create("author"); let post = server.create("post", { authorId: author.id, }); author.reload(); expect(author.posts.models).toHaveLength(1); expect(post.author.attrs).toEqual(author.attrs); expect(server.db.posts[0].authorId).toEqual(author.id); }); test("create sets up the db correctly when passing in models", () => { expectNoWarning(); let author = server.create("author"); let post = server.create("post", { author, }); expect(author.posts.models).toHaveLength(1); expect(post.author.attrs).toEqual(author.attrs); expect(server.db.posts[0].authorId).toEqual(author.id); }); }); miragejs-0.1.42/__tests__/external/shared/factories/helpers-test.js000066400000000000000000000067341412317504700253770ustar00rootroot00000000000000import { Model, Server, Factory, belongsTo, hasMany, trait, association, } from "miragejs"; describe("Eternal | Shared | Factories | helpers", () => { let server; afterEach(() => { server.shutdown(); }); test('it creates associations with "association" helper in a dasherized factory', () => { server = new Server({ environment: "test", models: { author: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ author: belongsTo(), }), }, factories: { author: Factory.extend({ name: "Sam", }), blogPost: Factory.extend({ title: "Lorem ipsum", author: association(), }), }, }); let blogPost = server.create("blog-post"); expect(blogPost.author).toBeTruthy(); let { db } = server; expect(db.authors).toHaveLength(1); expect(db.authors[0]).toEqual({ id: "1", name: "Sam", blogPostIds: ["1"], }); }); test('it creates associations with "association" helper combininig with traits', () => { server = new Server({ environment: "test", models: { author: Model.extend({ posts: hasMany(), }), category: Model.extend({ posts: hasMany("post", { inverse: "kind" }), }), post: Model.extend({ author: belongsTo(), kind: belongsTo("category"), }), }, factories: { author: Factory.extend({ name: "Sam", }), category: Factory.extend({ name: "awesome software", }), post: Factory.extend({ title: "Lorem ipsum", author: association(), withCategory: trait({ kind: association(), }), }), }, }); let post = server.create("post", "withCategory"); expect(post.kind).toBeTruthy(); expect(post.author).toBeTruthy(); let { db } = server; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", title: "Lorem ipsum", authorId: "1", kindId: "1", }); expect(db.authors).toHaveLength(1); expect(db.authors[0]).toEqual({ id: "1", name: "Sam", postIds: ["1"], }); expect(db.categories).toHaveLength(1); expect(db.categories[0]).toEqual({ id: "1", name: "awesome software", postIds: ["1"], }); }); test("it throws if using the association helper on a self-referential belongsTo relationship", () => { server = new Server({ environment: "test", models: { page: Model.extend({ parentPage: belongsTo("page", { inverse: "childPages" }), childPages: hasMany("page", { inverse: "parentPage" }), }), }, factories: { page: Factory.extend({ parentPage: association(), }), }, }); expect(() => { server.create("page"); }).toThrow(); }); test("it throws if using the association helper with polymorphic relationship", () => { server = new Server({ environment: "test", models: { author: Model.extend({ anyPost: belongsTo("base-post", { polymorphic: true }), }), basePost: Model.extend({}), }, factories: { author: Factory.extend({ anyPost: association(), }), }, }); expect(() => { server.create("author"); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/fixtures-and-factories-test.js000066400000000000000000000014261412317504700263350ustar00rootroot00000000000000import { Server, Model, Factory } from "miragejs"; describe("External | Shared | Fixtures and factories", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { author: Model, }, factories: { author: Factory, }, seeds() {}, fixtures: { authors: [{ id: 1, name: "Zelda" }], }, }); }); afterEach(function () { server.shutdown(); }); test(`[regression] When loaded, fixture files correctly update the database's autoincrement id`, () => { server.loadFixtures(); server.schema.authors.create({}); let authors = server.db.authors; expect(authors).toHaveLength(2); expect(authors.map((a) => a.id)).toEqual(["1", "2"]); }); }); miragejs-0.1.42/__tests__/external/shared/identity-manager-test.js000066400000000000000000000035571412317504700252170ustar00rootroot00000000000000import { Model, hasMany, belongsTo, Server, IdentityManager as DefaultIdentityManager, } from "miragejs"; const CustomIdentityManager = class { constructor() { this.wasCalled = false; } fetch() { if (this.wasCalled) { throw new Error( "IdentityManager used for test only supports one call to fetch" ); } this.wasCalled = true; return "custom-id"; } set(id) { throw new Error("Not implemented for test."); } reset() { throw new Error("Not implemented for test."); } }; describe("External | Shared | Identity manager", function () { let server; afterEach(() => { server.shutdown(); }); test("it uses identity managers defined by config", () => { server = new Server({ environment: "test", identityManagers: { post: DefaultIdentityManager, author: CustomIdentityManager, }, models: { author: Model.extend({ posts: hasMany(), }), comment: Model.extend({ post: belongsTo(), }), post: Model.extend({ author: belongsTo(), }), }, }); let author = server.create("author"); let comment = server.create("comment"); let post = server.create("post"); expect(author.id).toEqual("custom-id"); expect(post.id).toEqual("1"); expect(comment.id).toEqual("1"); }); test("identity managers can use record data in their fetch method", () => { let IdentityManagerForTest = class { fetch(data) { return `${data.ssn}`; } }; server = new Server({ environment: "test", identityManagers: { application: IdentityManagerForTest, }, models: { user: Model.extend(), }, }); let ryan = server.create("user", { name: "Ryan", ssn: 123456789 }); expect(ryan.id).toEqual("123456789"); }); }); miragejs-0.1.42/__tests__/external/shared/importable-test.js000066400000000000000000000001721412317504700241020ustar00rootroot00000000000000import { Server } from "miragejs"; test("Server is importable in node", async () => { expect(Server).toBeTruthy(); }); miragejs-0.1.42/__tests__/external/shared/orm/000077500000000000000000000000001412317504700212265ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/all-test.js000066400000000000000000000020361412317504700233120ustar00rootroot00000000000000import { Server, Model, Collection } from "miragejs"; describe("External | Shared | ORM | #all", function () { let User; let server; beforeEach(() => { User = Model.extend(); server = new Server({ environment: "test", models: { user: User, }, }); }); afterEach(() => { server.shutdown(); }); test("it can return all models", () => { server.db.loadData({ users: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], }); let users = server.schema.users.all(); expect(users instanceof Collection).toBeTruthy(); expect(users.models[0] instanceof User).toBeTruthy(); expect(users.models).toHaveLength(2); expect(users.models[1].attrs).toEqual({ id: "2", name: "Zelda" }); }); test("it returns an empty array when no models exist", () => { let users = server.schema.users.all(); expect(users instanceof Collection).toBeTruthy(); expect(users.modelName).toEqual("user"); expect(users.models).toHaveLength(0); }); }); miragejs-0.1.42/__tests__/external/shared/orm/assertions-test.js000066400000000000000000000033261412317504700247370ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; describe("External | Shared | ORM | assertions", () => { let server; beforeEach(() => { server = new Server({ models: { user: Model.extend({ posts: hasMany(), }), post: Model.extend({ author: belongsTo("user"), }), }, }); }); afterEach(() => { server.shutdown(); }); test("it errors when passing in the wrong type for a HasMany association", () => { expect(() => { server.schema.users.create({ name: "Sam", posts: [1], }); }).toThrow(); }); test(`it doesn't error when passing in an empty array`, () => { server.schema.users.create({ name: "Sam", posts: [], }); expect(true).toBeTruthy(); }); test("it errors when passing in the wrong type for a HasMany association foreign key", () => { expect(() => { server.schema.users.create({ name: "Sam", postIds: "foo", }); }).toThrow(); }); test("it errors when passing in a missing foreign key for a HasMany association foreign key", () => { expect(() => { server.schema.users.create({ name: "Sam", postIds: [2], }); }).toThrow(); }); test("it errors when passing in the wrong type for a BelongsTo association", () => { expect(() => { server.schema.posts.create({ title: "Post 1", author: "sam", }); }).toThrow(); }); test("it errors when passing in a missing foreign key for a BelongsTo association foreign key", () => { expect(() => { server.schema.posts.create({ title: "Post 1", authorId: 1, }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/associations-for-test.js000066400000000000000000000026101412317504700260230ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; describe("External | Shared | ORM | associationsFor", function () { let server; beforeEach(() => { server = new Server({ environment: "test" }); }); afterEach(() => { server.shutdown(); }); test("it returns an empty object for a model with no relationships", () => { server.config({ models: { user: Model, }, }); expect(server.schema.associationsFor("user")).toEqual({}); }); test("it returns an object containing all a model's relationships", () => { server.config({ models: { user: Model, article: Model.extend({ fineAuthor: belongsTo("user"), comments: hasMany(), }), comment: Model, }, }); let associations = server.schema.associationsFor("article"); expect(Object.keys(associations)).toEqual(["fineAuthor", "comments"]); let fineAuthorAssociation = associations.fineAuthor; expect(fineAuthorAssociation.type).toEqual("belongsTo"); expect(fineAuthorAssociation.modelName).toEqual("user"); expect(fineAuthorAssociation.name).toEqual("fineAuthor"); let commentsAssociation = associations.comments; expect(commentsAssociation.type).toEqual("hasMany"); expect(commentsAssociation.modelName).toEqual("comment"); expect(commentsAssociation.name).toEqual("comments"); }); }); miragejs-0.1.42/__tests__/external/shared/orm/associations-test.js000066400000000000000000000027661412317504700252530ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; describe("External | Shared | ORM | associations", function () { let server; let fineAuthorAssociation; let commentsAssociation; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, post: Model.extend({ fineAuthor: belongsTo("user"), comments: hasMany(), }), comment: Model, }, }); let associations = server.schema.associationsFor("post"); fineAuthorAssociation = associations.fineAuthor; commentsAssociation = associations.comments; }); afterEach(() => { server.shutdown(); }); test("name returns the property used to define the association", function () { expect(fineAuthorAssociation.name).toEqual("fineAuthor"); expect(commentsAssociation.name).toEqual("comments"); }); test("modelName returns the modelName of the associated model", function () { expect(fineAuthorAssociation.modelName).toEqual("user"); expect(commentsAssociation.modelName).toEqual("comment"); }); test("type returns the type of association", function () { expect(fineAuthorAssociation.type).toEqual("belongsTo"); expect(commentsAssociation.type).toEqual("hasMany"); }); test("foreignKey returns the name used for the association's foreign key", function () { expect(fineAuthorAssociation.foreignKey).toEqual("fineAuthorId"); expect(commentsAssociation.foreignKey).toEqual("commentIds"); }); }); miragejs-0.1.42/__tests__/external/shared/orm/attrs-test.js000066400000000000000000000017741412317504700237070ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | attrs", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, }, }); server.db.loadData({ users: [{ id: 1, name: "Link", evil: false }], }); }); afterEach(() => { server.shutdown(); }); test("attrs returns the models attributes", () => { let user = server.schema.users.find(1); expect(user.attrs).toEqual({ id: "1", name: "Link", evil: false }); }); test("attributes can be read via plain property access", () => { let user = server.schema.users.find(1); expect(user.name).toEqual("Link"); }); test("toJSON should return a copy of attrs so they cannot be mutated", () => { let user = server.schema.users.find(1); let json = user.toJSON(); expect(json).toEqual({ id: "1", name: "Link", evil: false }); json.name = "Young Link"; expect(user.name).toEqual("Link"); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/000077500000000000000000000000001412317504700232775ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/000077500000000000000000000000001412317504700245165ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/_helper.js000066400000000000000000000047351412317504700265030ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { author: Model.extend(), post: Model.extend({ author: belongsTo(), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return [this.schema.posts.find(insertedPost.id), undefined]; } savedChildNewParent() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); let post = this.schema.posts.find(insertedPost.id); let author = this.schema.authors.new({ name: "Bob" }); post.author = author; return [post, author]; } savedChildSavedParent() { let insertedAuthor = this.db.authors.insert({ name: "Bob" }); let insertedPost = this.db.posts.insert({ title: "Lorem", authorId: insertedAuthor.id, }); let post = this.schema.posts.find(insertedPost.id); let author = this.schema.authors.find(insertedAuthor.id); return [post, author]; } newChildNoParent() { return [this.schema.posts.new({ title: "Lorem" }), undefined]; } newChildNewParent() { let post = this.schema.posts.new({ title: "Lorem" }); let newAuthor = this.schema.authors.new({ name: "Bob" }); post.author = newAuthor; return [post, newAuthor]; } newChildSavedParent() { let insertedAuthor = this.db.authors.insert({ name: "Bob" }); let post = this.schema.posts.new({ title: "Lorem" }); let savedAuthor = this.schema.authors.find(insertedAuthor.id); post.author = savedAuthor; return [post, savedAuthor]; } // Just a saved unassociated parent. savedParent() { let insertedAuthor = this.db.authors.insert({ name: "Bob" }); return this.schema.authors.find(insertedAuthor.id); } newParent() { return this.schema.authors.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/_regressions-test.js000066400000000000000000000012101412317504700305250ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; describe("External | Shared | ORM | Belongs To | Basic | regressions", function () { test("belongsTo accessors works when foreign key is present but falsy", () => { let server = new Server({ environment: "test", models: { author: Model.extend(), post: Model.extend({ author: belongsTo(), }), }, }); server.db.loadData({ posts: [{ id: 1, authorId: 0, name: "some post" }], authors: [{ id: 0, name: "Foo" }], }); let post = server.schema.posts.find(1); expect(post.author.name).toEqual("Foo"); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/accessor-test.js000066400000000000000000000011271412317504700276340ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [post, author] = helper[state](); expect(post.author).toEqual(author ? author : null); expect(post.authorId).toEqual(author ? author.id : null); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/association-create-test.js000066400000000000000000000013511412317504700316060ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [post] = helper[state](); let ganon = post.createAuthor({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(post.author.attrs).toEqual(ganon.attrs); expect(post.authorId).toEqual(ganon.id); expect(helper.schema.posts.find(post.id).authorId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/association-new-test.js000066400000000000000000000013721412317504700311370ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [post] = helper[state](); let ganon = post.newAuthor({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(post.author).toEqual(ganon); expect(post.authorId).toBeNil(); post.save(); expect(ganon.id).toBeTruthy(); expect(post.authorId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/association-set-id-test.js000066400000000000000000000017571412317504700315420ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [post] = helper[state](); let savedAuthor = helper.savedParent(); post.authorId = savedAuthor.id; expect(post.authorId).toEqual(savedAuthor.id); expect(post.author.attrs).toEqual(savedAuthor.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [post] = helper[state](); post.authorId = null; expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/association-set-test.js000066400000000000000000000022221412317504700311340ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [post] = helper[state](); let savedAuthor = helper.savedParent(); post.author = savedAuthor; expect(post.authorId).toEqual(savedAuthor.id); expect(post.author).toEqual(savedAuthor); }); test(`a ${state} can update its association to a new parent`, () => { let [post] = helper[state](); let newAuthor = helper.newParent(); post.author = newAuthor; expect(post.authorId).toBeNil(); expect(post.author).toEqual(newAuthor); }); test(`a ${state} can update its association to a null parent`, () => { let [post] = helper[state](); post.author = null; expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/create-test.js000066400000000000000000000036741412317504700273060ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Basic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let author = helper.schema.create("author"); let post = helper.schema.create("post", { authorId: author.id, }); expect(post.authorId).toEqual(author.id); expect(post.author.attrs).toEqual(author.attrs); expect(helper.schema.db.authors).toHaveLength(1); expect(helper.schema.db.authors[0]).toEqual({ id: "1" }); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1", authorId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let author = helper.schema.create("author"); let post = helper.schema.create("post", { author, }); expect(post.authorId).toEqual(author.id); expect(post.author.attrs).toEqual(author.attrs); expect(helper.schema.db.authors).toHaveLength(1); expect(helper.schema.db.authors[0]).toEqual({ id: "1" }); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1", authorId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("post", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/delete-test.js000066400000000000000000000010731412317504700272740ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [post, author] = helper[state](); if (author) { author.destroy(); post.reload(); } expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/1-basic/instantiating-test.js000066400000000000000000000047561412317504700307210ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Basic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let author = helper.savedParent(); let post = schema.posts.new({ authorId: author.id }); expect(post.authorId).toEqual(author.id); expect(post.author).toEqual(author); expect(post.attrs).toEqual({ authorId: author.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.posts.new({ authorId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let post = schema.posts.new({ authorId: null }); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a saved parent model", () => { let author = helper.savedParent(); let post = schema.posts.new({ author }); expect(post.authorId).toEqual("1"); expect(post.author).toEqual(author); }); test("the child accepts a new parent model", () => { let zelda = schema.authors.new({ name: "Zelda" }); let post = schema.posts.new({ author: zelda }); expect(post.authorId).toBeNil(); expect(post.author).toEqual(zelda); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a null parent model", () => { let post = schema.posts.new({ author: null }); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a parent model and id", () => { let author = helper.savedParent(); let post = schema.posts.new({ author, authorId: author.id }); expect(post.authorId).toEqual("1"); expect(post.author).toEqual(author); expect(post.attrs).toEqual({ authorId: author.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let post = schema.posts.new({}); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts no reference to a parent id or model", () => { let post = schema.posts.new(); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphic/000077500000000000000000000000001412317504700300405ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphic/_helper.js000066400000000000000000000050731412317504700320210ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { post: Model.extend({ comment: belongsTo(), }), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }, }); this.db = this.server.db; this.loadData = this.db.loadData.bind(this.db); this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedComment = this.db.comments.insert({ text: "Lorem" }); return [this.schema.comments.find(insertedComment.id), undefined]; } savedChildNewParent() { let comment = this.schema.comments.create({ text: "Lorem" }); let post = this.schema.posts.new({ title: "Post 1" }); comment.commentable = post; return [comment, post]; } savedChildSavedParent() { this.loadData({ posts: [{ id: "1", title: "Post 1", commentId: "1" }], comments: [ { id: "1", text: "Lorem", commentableId: { id: "1", type: "post" } }, ], }); let comment = this.schema.comments.find(1); let post = this.schema.posts.find(1); return [comment, post]; } newChildNoParent() { return [this.schema.comments.new({ text: "Lorem" }), undefined]; } newChildNewParent() { let post = this.schema.posts.new({ title: "Post 1" }); let comment = this.schema.comments.new({ text: "Lorem" }); comment.commentable = post; return [comment, post]; } newChildSavedParent() { let insertedPost = this.db.posts.insert({ title: "Post 1" }); let comment = this.schema.comments.new({ text: "Lorem" }); let savedProfile = this.schema.posts.find(insertedPost.id); comment.commentable = savedProfile; return [comment, savedProfile]; } // Just a saved unassociated parent. savedParent() { let insertedPost = this.db.posts.insert({ title: "Post 1" }); return this.schema.posts.find(insertedPost.id); } newParent() { return this.schema.posts.new({ title: "Post 1" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphic/accessor-test.js000066400000000000000000000021031412317504700331510ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [comment, post] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (post) { expect(comment.commentable.attrs).toEqual(post.attrs); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); } else { expect(comment.commentable).toBeNil(); expect(comment.commentableId).toBeNil(); } // If there's a post in this state, make sure the inverse association is correct if (post) { expect(post.comment.attrs).toEqual(comment.attrs); expect(post.commentId).toEqual(comment.id); } }); }); }); association-create-test.js000066400000000000000000000016401412317504700350520ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [comment] = helper[state](); let post = comment.createCommentable("post", { title: "Lorem" }); expect(post.id).toBeTruthy(); expect(comment.commentable.attrs).toEqual(post.attrs); expect(post.comment.attrs).toEqual(comment.attrs); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(helper.schema.comments.find(comment.id).commentableId).toEqual({ type: "post", id: post.id, }); }); }); }); association-new-test.js000066400000000000000000000017031412317504700344000ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [comment] = helper[state](); let post = comment.newCommentable("post", { age: 300 }); expect(!post.id).toBeTruthy(); expect(comment.commentable).toEqual(post); expect(comment.commentableId).toEqual({ type: "post", id: undefined }); expect(post.comment).toEqual(comment); expect(post.commentId).toEqual(comment.id); comment.save(); expect(post.id).toBeTruthy(); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); }); }); }); association-set-id-test.js000066400000000000000000000023361412317504700347770ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [comment] = helper[state](); let post = helper.savedParent(); comment.commentableId = { type: "post", id: post.id }; expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); comment.save(); post.reload(); expect(post.commentId).toEqual(comment.id); expect(post.comment.attrs).toEqual(comment.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [comment] = helper[state](); comment.commentableId = null; expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); }); }); }); association-set-test.js000066400000000000000000000027551412317504700344120ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [comment] = helper[state](); let post = helper.savedParent(); comment.commentable = post; expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(post.commentId).toEqual(comment.id); expect(post.comment.attrs).toEqual(comment.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [comment] = helper[state](); let post = helper.newParent(); comment.commentable = post; expect(comment.commentableId).toEqual({ type: "post", id: undefined }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(post.commentId).toEqual(comment.id); expect(post.comment.attrs).toEqual(comment.attrs); }); test(`a ${state} can update its association to a null parent`, () => { let [comment] = helper[state](); comment.commentable = null; expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphic/create-test.js000066400000000000000000000044421412317504700326220ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let post = schema.create("post"); let comment = schema.create("comment", { commentableId: { type: "post", id: post.id }, }); post.reload(); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(post.comment.attrs).toEqual(comment.attrs); expect(schema.db.comments).toHaveLength(1); expect(schema.db.posts).toHaveLength(1); expect(schema.db.comments[0]).toEqual({ id: "1", commentableId: { type: "post", id: "1" }, }); expect(schema.db.posts[0]).toEqual({ id: "1", commentId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let post = schema.create("post"); let comment = schema.create("comment", { commentable: post, }); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(post.comment.attrs).toEqual(comment.attrs); expect(schema.db.comments).toHaveLength(1); expect(schema.db.posts).toHaveLength(1); expect(schema.db.comments[0]).toEqual({ id: "1", commentableId: { type: "post", id: "1" }, }); expect(schema.db.posts[0]).toEqual({ id: "1", commentId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("comment", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("comment", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphic/delete-test.js000066400000000000000000000011341412317504700326140ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [comment, post] = helper[state](); if (post) { post.destroy(); comment.reload(); } expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); }); }); }); instantiating-test.js000066400000000000000000000061661412317504700341610ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/10-one-to-one-polymorphicimport Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | One-to-one Polymorphic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentableId: { type: "post", id: post.id }, }); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(comment.attrs).toEqual({ commentableId: { type: "post", id: post.id }, }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.comments.new({ commentableId: { type: "post", id: 2 } }); }).toThrow(); }); test("the child accepts a null parent id", () => { let comment = schema.comments.new({ commentableId: null }); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a saved parent model", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentable: post }); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(comment.attrs).toEqual({ commentableId: null }); // this would update when saved }); test("the child accepts a new parent model", () => { let post = schema.posts.new({ age: 300 }); let comment = schema.comments.new({ commentable: post }); expect(comment.commentableId).toEqual({ type: "post", id: undefined }); expect(comment.commentable).toEqual(post); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a null parent model", () => { let comment = schema.comments.new({ commentable: null }); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a parent model and id", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentable: post, commentableId: { type: "post", id: post.id }, }); expect(comment.commentableId).toEqual({ type: "post", id: "1" }); expect(comment.commentable).toEqual(post); expect(comment.attrs).toEqual({ commentableId: { type: "post", id: post.id }, }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let comment = schema.comments.new({}); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts no reference to a parent id or model", () => { let comment = schema.comments.new(); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); }); 11-named-one-way-reflexive-self-referential/000077500000000000000000000000001412317504700333145ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to_helper.js000066400000000000000000000033601412317504700352720ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ representative: belongsTo("user", { inverse: null }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let link = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(link.id), undefined]; } savedChildSavedParent() { let linkDbRecord = this.db.users.insert({ name: "Link" }); this.db.users.update(linkDbRecord.id, { representativeId: linkDbRecord.id, }); let link = this.schema.users.find(linkDbRecord.id); return [link, link]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let link = this.schema.users.new({ name: "Link" }); link.representative = link; return [link, link]; } // Just a saved unassociated parent. // savedParent() { // let insertedParent = this.db.users.insert({ name: 'Bob' }); // // return this.schema.users.find(insertedParent.id); // } // // newParent() { // return this.schema.users.new({ name: 'Bob' }); // } } export const states = [ "savedChildNoParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", ]; accessor-test.js000066400000000000000000000016031412317504700364310ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named one-way reflexive self referential | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, representative] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (representative) { expect(user.representative.attrs).toEqual(representative.attrs); expect(user.representativeId).toEqual(representative.id); } else { expect(user.representative).toBeNil(); expect(user.representativeId).toBeNil(); } }); }); }); association-create-test.js000066400000000000000000000014741412317504700404120ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named one-way reflexive self referential | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let ganon = user.createRepresentative({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(user.representative.attrs).toEqual(ganon.attrs); expect(user.representativeId).toEqual(ganon.id); expect(helper.schema.users.find(user.id).representativeId).toEqual( ganon.id ); }); }); }); association-new-test.js000066400000000000000000000014751412317504700377410ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named one-way reflexive self referential | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let ganon = user.newRepresentative({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(user.representative).toEqual(ganon); expect(user.representativeId).toBeNil(); user.save(); expect(ganon.id).toBeTruthy(); expect(user.representativeId).toEqual(ganon.id); }); }); }); association-set-id-test.js000066400000000000000000000024141412317504700403270ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Named one-way reflexive self referential | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ ["savedChildNoParent", "savedChildSavedParent"].forEach((state) => { test(`a ${state} can update its association to itself via parentId`, () => { let [user] = helper[state](); user.representativeId = user.id; expect(user.representativeId).toEqual(user.id); expect(user.representative.attrs).toEqual(user.attrs); user.save(); expect(user.representativeId).toEqual(user.id); expect(user.representative.attrs).toEqual(user.attrs); }); }); ["savedChildSavedParent", "newChildNewParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.representativeId = null; expect(user.representativeId).toBeNil(); expect(user.representative).toBeNil(); user.save(); expect(user.representativeId).toBeNil(); expect(user.representative).toBeNil(); }); }); }); association-set-test.js000066400000000000000000000022101412317504700377270ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/11-named-one-way-reflexive-self-referentialimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named one-way reflexive self referential | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to itself`, () => { let [user] = helper[state](); user.representative = user; expect(user.representativeId).toEqual(user.id); expect(user.representative.attrs).toEqual(user.attrs); user.save(); expect(user.representativeId).toEqual(user.id); expect(user.representative.attrs).toEqual(user.attrs); }); test(`a ${state} can update its association to a null parent`, () => { let [user] = helper[state](); user.representative = null; expect(user.representativeId).toBeNil(); expect(user.representative).toBeNil(); user.save(); expect(user.representativeId).toBeNil(); expect(user.representative).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/000077500000000000000000000000001412317504700245225ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/_helper.js000066400000000000000000000047171412317504700265070ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend(), post: Model.extend({ author: belongsTo("user"), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return [this.schema.posts.find(insertedPost.id), undefined]; } savedChildNewParent() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); let post = this.schema.posts.find(insertedPost.id); let author = this.schema.users.new({ name: "Bob" }); post.author = author; return [post, author]; } savedChildSavedParent() { let insertedAuthor = this.db.users.insert({ name: "Bob" }); let insertedPost = this.db.posts.insert({ title: "Lorem", authorId: insertedAuthor.id, }); let post = this.schema.posts.find(insertedPost.id); let author = this.schema.users.find(insertedAuthor.id); return [post, author]; } newChildNoParent() { return [this.schema.posts.new({ title: "Lorem" }), undefined]; } newChildNewParent() { let post = this.schema.posts.new({ title: "Lorem" }); let newAuthor = this.schema.users.new({ name: "Bob" }); post.author = newAuthor; return [post, newAuthor]; } newChildSavedParent() { let insertedAuthor = this.db.users.insert({ name: "Bob" }); let post = this.schema.posts.new({ title: "Lorem" }); let savedAuthor = this.schema.users.find(insertedAuthor.id); post.author = savedAuthor; return [post, savedAuthor]; } // Just a saved unassociated parent. savedParent() { let insertedAuthor = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedAuthor.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/accessor-test.js000066400000000000000000000011271412317504700276400ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [post, author] = helper[state](); expect(post.author).toEqual(author ? author : null); expect(post.authorId).toEqual(author ? author.id : null); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/association-create-test.js000066400000000000000000000013511412317504700316120ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [post] = helper[state](); let ganon = post.createAuthor({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(post.author.attrs).toEqual(ganon.attrs); expect(post.authorId).toEqual(ganon.id); expect(helper.schema.posts.find(post.id).authorId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/association-new-test.js000066400000000000000000000013721412317504700311430ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [post] = helper[state](); let ganon = post.newAuthor({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(post.author).toEqual(ganon); expect(post.authorId).toBeNil(); post.save(); expect(ganon.id).toBeTruthy(); expect(post.authorId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/association-set-id-test.js000066400000000000000000000017431412317504700315410ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [post] = helper[state](); let savedAuthor = helper.savedParent(); post.authorId = savedAuthor.id; expect(post.authorId).toEqual(savedAuthor.id); expect(post.author).toEqual(savedAuthor); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [post] = helper[state](); post.authorId = null; expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/association-set-test.js000066400000000000000000000022221412317504700311400ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [post] = helper[state](); let savedAuthor = helper.savedParent(); post.author = savedAuthor; expect(post.authorId).toEqual(savedAuthor.id); expect(post.author).toEqual(savedAuthor); }); test(`a ${state} can update its association to a new parent`, () => { let [post] = helper[state](); let newAuthor = helper.newParent(); post.author = newAuthor; expect(post.authorId).toBeNil(); expect(post.author).toEqual(newAuthor); }); test(`a ${state} can update its association to a null parent`, () => { let [post] = helper[state](); post.author = null; expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/create-test.js000066400000000000000000000036601412317504700273050ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Named | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let author = helper.schema.create("user"); let post = helper.schema.create("post", { authorId: author.id, }); expect(post.authorId).toEqual(author.id); expect(post.author.attrs).toEqual(author.attrs); expect(helper.schema.db.users).toHaveLength(1); expect(helper.schema.db.users[0]).toEqual({ id: "1" }); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1", authorId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let author = helper.schema.create("user"); let post = helper.schema.create("post", { author, }); expect(post.authorId).toEqual(author.id); expect(post.author.attrs).toEqual(author.attrs); expect(helper.schema.db.users).toHaveLength(1); expect(helper.schema.db.users[0]).toEqual({ id: "1" }); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1", authorId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("post", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/delete-test.js000066400000000000000000000010651412317504700273010ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [post, user] = helper[state](); if (user) { user.destroy(); post.reload(); } expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/2-named/instantiating-test.js000066400000000000000000000047531412317504700307220ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Named | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let author = helper.savedParent(); let post = schema.posts.new({ authorId: author.id }); expect(post.authorId).toEqual(author.id); expect(post.author).toEqual(author); expect(post.attrs).toEqual({ authorId: author.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.posts.new({ authorId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let post = schema.posts.new({ authorId: null }); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a saved parent model", () => { let author = helper.savedParent(); let post = schema.posts.new({ author }); expect(post.authorId).toEqual("1"); expect(post.author).toEqual(author); }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let post = schema.posts.new({ author: zelda }); expect(post.authorId).toBeNil(); expect(post.author).toEqual(zelda); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a null parent model", () => { let post = schema.posts.new({ author: null }); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts a parent model and id", () => { let author = helper.savedParent(); let post = schema.posts.new({ author, authorId: author.id }); expect(post.authorId).toEqual("1"); expect(post.author).toEqual(author); expect(post.attrs).toEqual({ authorId: author.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let post = schema.posts.new({}); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); test("the child accepts no reference to a parent id or model", () => { let post = schema.posts.new(); expect(post.authorId).toBeNil(); expect(post.author).toBeNil(); expect(post.attrs).toEqual({ authorId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/000077500000000000000000000000001412317504700254305ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/_helper.js000066400000000000000000000046561412317504700274170ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ user: belongsTo(), // implicit inverse }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let user = this.schema.users.create({ name: "Link" }); let friend = this.schema.users.new({ name: "Bob" }); user.user = friend; return [user, friend]; } savedChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let insertedUser = this.db.users.insert({ name: "Link", userId: insertedFriend.id, }); this.db.users.update(insertedFriend.id, { userId: insertedUser.id }); let user = this.schema.users.find(insertedUser.id); let friend = this.schema.users.find(insertedFriend.id); return [user, friend]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let friend = this.schema.users.new({ name: "Link" }); let user = this.schema.users.new({ name: "Bob" }); user.user = friend; return [user, friend]; } newChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let user = this.schema.users.new({ name: "Link" }); let savedFriend = this.schema.users.find(insertedFriend.id); user.user = savedFriend; return [user, savedFriend]; } // Just a saved unassociated parent. savedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedParent.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/accessor-test.js000066400000000000000000000017711412317504700305530ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, friend] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (friend) { expect(user.user.attrs).toEqual(friend.attrs); expect(user.userId).toEqual(friend.id); } else { expect(user.user).toBeNil(); expect(user.userId).toBeNil(); } // If there's a friend in this state, make sure the inverse association is correct if (friend) { expect(friend.user.attrs).toEqual(user.attrs); expect(friend.userId).toEqual(user.id); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/association-create-test.js000066400000000000000000000017051412317504700325230ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user, originalUser] = helper[state](); let ganon = user.createUser({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(user.user.attrs).toEqual(ganon.attrs); expect(ganon.user.attrs).toEqual(user.attrs); expect(user.userId).toEqual(ganon.id); expect(ganon.userId).toEqual(user.id); expect(helper.schema.users.find(user.id).userId).toEqual(ganon.id); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/association-new-test.js000066400000000000000000000016351412317504700320530ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user, originalUser] = helper[state](); let ganon = user.newUser({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(user.user).toEqual(ganon); expect(user.userId).toBeNil(); expect(ganon.user).toEqual(user); user.save(); expect(ganon.id).toBeTruthy(); expect(user.userId).toEqual(ganon.id); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/association-set-id-test.js000066400000000000000000000023671412317504700324520ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user, originalUser] = helper[state](); let friend = helper.savedParent(); user.userId = friend.id; expect(user.userId).toEqual(friend.id); expect(user.user.attrs).toEqual(friend.attrs); user.save(); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [user, originalUser] = helper[state](); user.userId = null; expect(user.userId).toBeNil(); expect(user.user).toBeNil(); user.save(); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/association-set-test.js000066400000000000000000000030651412317504700320540ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [user, originalUser] = helper[state](); let friend = helper.savedParent(); user.user = friend; expect(user.userId).toEqual(friend.id); expect(user.user.attrs).toEqual(friend.attrs); user.save(); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); test(`a ${state} can update its association to a new parent`, () => { let [user, originalUser] = helper[state](); let friend = helper.newParent(); user.user = friend; expect(user.userId).toBeNil(); expect(user.user.attrs).toEqual(friend.attrs); user.save(); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); test(`a ${state} can update its association to a null parent`, () => { let [user, originalUser] = helper[state](); user.user = null; expect(user.userId).toBeNil(); expect(user.user).toBeNil(); user.save(); if (originalUser) { originalUser.reload(); expect(originalUser.userId).toBeNil(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/create-test.js000066400000000000000000000035501412317504700302110ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { userId: friend.id, }); friend.reload(); expect(user.userId).toEqual(friend.id); expect(user.user.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", userId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", userId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { user: friend, }); expect(user.userId).toEqual(friend.id); expect(user.user.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", userId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", userId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/delete-test.js000066400000000000000000000011071412317504700302040ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, targetUser] = helper[state](); if (targetUser) { targetUser.destroy(); user.reload(); } expect(user.userId).toBeNil(); expect(user.user).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/3-reflexive/instantiating-test.js000066400000000000000000000050531412317504700316220ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Reflexive | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let friend = helper.savedParent(); let user = schema.users.new({ userId: friend.id }); expect(user.userId).toEqual(friend.id); expect(user.user.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ userId: friend.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ userId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let user = schema.users.new({ userId: null }); expect(user.userId).toBeNil(); expect(user.user).toBeNil(); expect(user.attrs).toEqual({ userId: null }); }); test("the child accepts a saved parent model", () => { let friend = helper.savedParent(); let user = schema.users.new({ user: friend }); expect(user.userId).toEqual("1"); expect(user.user.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ userId: null }); // this would update when saved }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let user = schema.users.new({ user: zelda }); expect(user.userId).toBeNil(); expect(user.user).toEqual(zelda); expect(user.attrs).toEqual({ userId: null }); }); test("the child accepts a null parent model", () => { let user = schema.users.new({ user: null }); expect(user.userId).toBeNil(); expect(user.user).toBeNil(); expect(user.attrs).toEqual({ userId: null }); }); test("the child accepts a parent model and id", () => { let friend = helper.savedParent(); let user = schema.users.new({ user: friend, userId: friend.id }); expect(user.userId).toEqual("1"); expect(user.user).toEqual(friend); expect(user.attrs).toEqual({ userId: friend.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let user = schema.users.new({}); expect(user.userId).toBeNil(); expect(user.user).toBeNil(); expect(user.attrs).toEqual({ userId: null }); }); test("the child accepts no reference to a parent id or model", () => { let user = schema.users.new(); expect(user.userId).toBeNil(); expect(user.user).toBeNil(); expect(user.attrs).toEqual({ userId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/000077500000000000000000000000001412317504700265135ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/_helper.js000066400000000000000000000047301412317504700304730ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ bestFriend: belongsTo("user"), // implicit inverse }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let user = this.schema.users.create({ name: "Link" }); let friend = this.schema.users.new({ name: "Bob" }); user.bestFriend = friend; return [user, friend]; } savedChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let insertedUser = this.db.users.insert({ name: "Link", bestFriendId: insertedFriend.id, }); this.db.users.update(insertedFriend.id, { bestFriendId: insertedUser.id }); let user = this.schema.users.find(insertedUser.id); let friend = this.schema.users.find(insertedFriend.id); return [user, friend]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let friend = this.schema.users.new({ name: "Link" }); let user = this.schema.users.new({ name: "Bob" }); user.bestFriend = friend; return [user, friend]; } newChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let user = this.schema.users.new({ name: "Link" }); let savedFriend = this.schema.users.find(insertedFriend.id); user.bestFriend = savedFriend; return [user, savedFriend]; } // Just a saved unassociated parent. savedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedParent.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/accessor-test.js000066400000000000000000000020431412317504700316270ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, friend] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (friend) { expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.bestFriendId).toEqual(friend.id); } else { expect(user.bestFriend).toBeNil(); expect(user.bestFriendId).toBeNil(); } // If there's a friend in this state, make sure the inverse association is correct if (friend) { expect(friend.bestFriend.attrs).toEqual(user.attrs); expect(friend.bestFriendId).toEqual(user.id); } }); }); }); association-create-test.js000066400000000000000000000014031412317504700335220ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let ganon = user.createBestFriend({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(user.bestFriend.attrs).toEqual(ganon.attrs); expect(user.bestFriendId).toEqual(ganon.id); expect(helper.schema.users.find(user.id).bestFriendId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/association-new-test.js000066400000000000000000000014241412317504700331320ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let ganon = user.newBestFriend({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(user.bestFriend).toEqual(ganon); expect(user.bestFriendId).toBeNil(); user.save(); expect(ganon.id).toBeTruthy(); expect(user.bestFriendId).toEqual(ganon.id); }); }); }); association-set-id-test.js000066400000000000000000000017751412317504700334600ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let friend = helper.savedParent(); user.bestFriendId = friend.id; expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.bestFriendId = null; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/association-set-test.js000066400000000000000000000022731412317504700331370ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [user] = helper[state](); let friend = helper.savedParent(); user.bestFriend = friend; expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let friend = helper.newParent(); user.bestFriend = friend; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); test(`a ${state} can update its association to a null parent`, () => { let [user] = helper[state](); user.bestFriend = null; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/create-test.js000066400000000000000000000036521412317504700312770ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Named Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { bestFriendId: friend.id, }); friend.reload(); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", bestFriendId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", bestFriendId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { bestFriend: friend, }); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", bestFriendId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", bestFriendId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/delete-test.js000066400000000000000000000011311412317504700312640ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, bestFriend] = helper[state](); if (bestFriend) { bestFriend.destroy(); user.reload(); } expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/4-named-reflexive/instantiating-test.js000066400000000000000000000054021412317504700327030ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriendId: friend.id }); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ bestFriendId: friend.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ bestFriendId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let user = schema.users.new({ bestFriendId: null }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a saved parent model", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriend: friend }); expect(user.bestFriendId).toEqual("1"); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ bestFriendId: null }); // this would update when saved }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let user = schema.users.new({ bestFriend: zelda }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toEqual(zelda); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a null parent model", () => { let user = schema.users.new({ bestFriend: null }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a parent model and id", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriend: friend, bestFriendId: friend.id, }); expect(user.bestFriendId).toEqual("1"); expect(user.bestFriend).toEqual(friend); expect(user.attrs).toEqual({ bestFriendId: friend.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let user = schema.users.new({}); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts no reference to a parent id or model", () => { let user = schema.users.new(); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverse/000077500000000000000000000000001412317504700320045ustar00rootroot00000000000000_helper.js000066400000000000000000000047371412317504700337140ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ bestFriend: belongsTo("user", { inverse: "bestFriend" }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let user = this.schema.users.create({ name: "Link" }); let friend = this.schema.users.new({ name: "Bob" }); user.bestFriend = friend; return [user, friend]; } savedChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let insertedUser = this.db.users.insert({ name: "Link", bestFriendId: insertedFriend.id, }); this.db.users.update(insertedFriend.id, { bestFriendId: insertedUser.id }); let user = this.schema.users.find(insertedUser.id); let friend = this.schema.users.find(insertedFriend.id); return [user, friend]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let friend = this.schema.users.new({ name: "Link" }); let user = this.schema.users.new({ name: "Bob" }); user.bestFriend = friend; return [user, friend]; } newChildSavedParent() { let insertedFriend = this.db.users.insert({ name: "Bob" }); let user = this.schema.users.new({ name: "Link" }); let savedFriend = this.schema.users.find(insertedFriend.id); user.bestFriend = savedFriend; return [user, savedFriend]; } // Just a saved unassociated parent. savedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedParent.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; accessor-test.js000066400000000000000000000020641412317504700350440ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, friend] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (friend) { expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.bestFriendId).toEqual(friend.id); } else { expect(user.bestFriend).toBeNil(); expect(user.bestFriendId).toBeNil(); } // If there's a friend in this state, make sure the inverse association is correct if (friend) { expect(friend.bestFriend.attrs).toEqual(user.attrs); expect(friend.bestFriendId).toEqual(user.id); } }); }); }); association-create-test.js000066400000000000000000000014241412317504700370160ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let ganon = user.createBestFriend({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(user.bestFriend.attrs).toEqual(ganon.attrs); expect(user.bestFriendId).toEqual(ganon.id); expect(helper.schema.users.find(user.id).bestFriendId).toEqual(ganon.id); }); }); }); association-new-test.js000066400000000000000000000014451412317504700363470ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let ganon = user.newBestFriend({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(user.bestFriend).toEqual(ganon); expect(user.bestFriendId).toBeNil(); user.save(); expect(ganon.id).toBeTruthy(); expect(user.bestFriendId).toEqual(ganon.id); }); }); }); association-set-id-test.js000066400000000000000000000020161412317504700367360ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let friend = helper.savedParent(); user.bestFriendId = friend.id; expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.bestFriendId = null; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); association-set-test.js000066400000000000000000000023141412317504700363450ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [user] = helper[state](); let friend = helper.savedParent(); user.bestFriend = friend; expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let friend = helper.newParent(); user.bestFriend = friend; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend.attrs).toEqual(friend.attrs); }); test(`a ${state} can update its association to a null parent`, () => { let [user] = helper[state](); user.bestFriend = null; expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); create-test.js000066400000000000000000000036731412317504700345140ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { bestFriendId: friend.id, }); friend.reload(); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", bestFriendId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", bestFriendId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let friend = schema.create("user"); let user = schema.create("user", { bestFriend: friend, }); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", bestFriendId: "2" }); expect(schema.db.users[1]).toEqual({ id: "2", bestFriendId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); delete-test.js000066400000000000000000000011521412317504700345010ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, bestFriend] = helper[state](); if (bestFriend) { bestFriend.destroy(); user.reload(); } expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); }); }); }); instantiating-test.js000066400000000000000000000054231412317504700361200ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/5-named-reflexive-explicit-inverseimport Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Named Reflexive Explicit Inverse | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriendId: friend.id }); expect(user.bestFriendId).toEqual(friend.id); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ bestFriendId: friend.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ bestFriendId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let user = schema.users.new({ bestFriendId: null }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a saved parent model", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriend: friend }); expect(user.bestFriendId).toEqual("1"); expect(user.bestFriend.attrs).toEqual(friend.attrs); expect(user.attrs).toEqual({ bestFriendId: null }); // this would update when saved }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let user = schema.users.new({ bestFriend: zelda }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toEqual(zelda); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a null parent model", () => { let user = schema.users.new({ bestFriend: null }); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts a parent model and id", () => { let friend = helper.savedParent(); let user = schema.users.new({ bestFriend: friend, bestFriendId: friend.id, }); expect(user.bestFriendId).toEqual("1"); expect(user.bestFriend).toEqual(friend); expect(user.attrs).toEqual({ bestFriendId: friend.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let user = schema.users.new({}); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); test("the child accepts no reference to a parent id or model", () => { let user = schema.users.new(); expect(user.bestFriendId).toBeNil(); expect(user.bestFriend).toBeNil(); expect(user.attrs).toEqual({ bestFriendId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/000077500000000000000000000000001412317504700270105ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/_helper.js000066400000000000000000000045661412317504700307770ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ user: belongsTo("user", { inverse: null }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let child = this.schema.users.create({ name: "Link" }); let parent = this.schema.users.new({ name: "Bob" }); child.user = parent; return [child, parent]; } savedChildSavedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); let insertedChild = this.db.users.insert({ name: "Link", userId: insertedParent.id, }); let child = this.schema.users.find(insertedChild.id); let parent = this.schema.users.find(insertedParent.id); return [child, parent]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let parent = this.schema.users.new({ name: "Link" }); let child = this.schema.users.new({ name: "Bob" }); child.user = parent; return [child, parent]; } newChildSavedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); let child = this.schema.users.new({ name: "Link" }); let savedParent = this.schema.users.find(insertedParent.id); child.user = savedParent; return [child, savedParent]; } // Just a saved unassociated parent. savedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedParent.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/accessor-test.js000066400000000000000000000013761412317504700321340ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, parent] = helper[state](); // We use .attrs here to avoid infinite recursion if (parent) { expect(user.user.attrs).toEqual(parent.attrs); expect(user.userId).toEqual(parent.id); } else { expect(user.user).toBeNil(); expect(user.userId).toBeNil(); } }); }); }); association-create-test.js000066400000000000000000000013621412317504700340230ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [child] = helper[state](); let ganon = child.createUser({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(child.user.attrs).toEqual(ganon.attrs); expect(child.userId).toEqual(ganon.id); expect(helper.schema.users.find(child.id).userId).toEqual(ganon.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/association-new-test.js000066400000000000000000000014041412317504700334250ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [child] = helper[state](); let ganon = child.newUser({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(child.user).toEqual(ganon); expect(child.userId).toBeNil(); child.save(); expect(ganon.id).toBeTruthy(); expect(child.userId).toEqual(ganon.id); }); }); }); association-set-id-test.js000066400000000000000000000017671412317504700337560ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [child] = helper[state](); let savedParent = helper.savedParent(); child.userId = savedParent.id; expect(child.userId).toEqual(savedParent.id); expect(child.user.attrs).toEqual(savedParent.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [child] = helper[state](); child.userId = null; expect(child.userId).toBeNil(); expect(child.user).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/association-set-test.js000066400000000000000000000022441412317504700334320ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [child] = helper[state](); let savedParent = helper.savedParent(); child.user = savedParent; expect(child.userId).toEqual(savedParent.id); expect(child.user.attrs).toEqual(savedParent.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [child] = helper[state](); let newParent = helper.newParent(); child.user = newParent; expect(child.userId).toBeNil(); expect(child.user).toEqual(newParent); }); test(`a ${state} can update its association to a null parent`, () => { let [child] = helper[state](); child.user = null; expect(child.userId).toBeNil(); expect(child.user).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/create-test.js000066400000000000000000000035421412317504700315720ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let parent = schema.create("user"); let child = schema.create("user", { userId: parent.id, }); expect(child.userId).toEqual(parent.id); expect(child.user.attrs).toEqual(parent.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", userId: null }); expect(schema.db.users[1]).toEqual({ id: "2", userId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let parent = schema.create("user"); let child = schema.create("user", { user: parent, }); expect(child.userId).toEqual(parent.id); expect(child.user.attrs).toEqual(parent.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", userId: null }); expect(schema.db.users[1]).toEqual({ id: "2", userId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/delete-test.js000066400000000000000000000011171412317504700315650ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, targetUser] = helper[state](); if (targetUser) { targetUser.destroy(); user.reload(); } expect(user.userId).toBeNil(); expect(user.user).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/6-one-way-reflexive/instantiating-test.js000066400000000000000000000050141412317504700331770ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | One-Way Reflexive | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let parent = helper.savedParent(); let child = schema.users.new({ userId: parent.id }); expect(child.userId).toEqual(parent.id); expect(child.user.attrs).toEqual(parent.attrs); expect(child.attrs).toEqual({ userId: parent.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ userId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let child = schema.users.new({ userId: null }); expect(child.userId).toBeNil(); expect(child.user).toBeNil(); expect(child.attrs).toEqual({ userId: null }); }); test("the child accepts a saved parent model", () => { let parent = helper.savedParent(); let child = schema.users.new({ user: parent }); expect(child.userId).toEqual("1"); expect(child.user.attrs).toEqual(parent.attrs); }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let child = schema.users.new({ user: zelda }); expect(child.userId).toBeNil(); expect(child.user).toEqual(zelda); expect(child.attrs).toEqual({ userId: null }); }); test("the child accepts a null parent model", () => { let child = schema.users.new({ user: null }); expect(child.userId).toBeNil(); expect(child.user).toBeNil(); expect(child.attrs).toEqual({ userId: null }); }); test("the child accepts a parent model and id", () => { let parent = helper.savedParent(); let child = schema.users.new({ user: parent, userId: parent.id }); expect(child.userId).toEqual("1"); expect(child.user.attrs).toEqual(parent.attrs); expect(child.attrs).toEqual({ userId: parent.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let child = schema.users.new({}); expect(child.userId).toBeNil(); expect(child.user).toBeNil(); expect(child.attrs).toEqual({ userId: null }); }); test("the child accepts no reference to a parent id or model", () => { let child = schema.users.new(); expect(child.userId).toBeNil(); expect(child.user).toBeNil(); expect(child.attrs).toEqual({ userId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexive/000077500000000000000000000000001412317504700300735ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexive/_helper.js000066400000000000000000000046001412317504700320470ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ parent: belongsTo("user", { inverse: null }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let child = this.schema.users.create({ name: "Link" }); let parent = this.schema.users.new({ name: "Bob" }); child.parent = parent; return [child, parent]; } savedChildSavedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); let insertedChild = this.db.users.insert({ name: "Link", parentId: insertedParent.id, }); let child = this.schema.users.find(insertedChild.id); let parent = this.schema.users.find(insertedParent.id); return [child, parent]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let parent = this.schema.users.new({ name: "Link" }); let child = this.schema.users.new({ name: "Bob" }); child.parent = parent; return [child, parent]; } newChildSavedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); let child = this.schema.users.new({ name: "Link" }); let savedParent = this.schema.users.find(insertedParent.id); child.parent = savedParent; return [child, savedParent]; } // Just a saved unassociated parent. savedParent() { let insertedParent = this.db.users.insert({ name: "Bob" }); return this.schema.users.find(insertedParent.id); } newParent() { return this.schema.users.new({ name: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexive/accessor-test.js000066400000000000000000000014141412317504700332100ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, parent] = helper[state](); // We use .attrs here to avoid infinite recursion if (parent) { expect(user.parent.attrs).toEqual(parent.attrs); expect(user.parentId).toEqual(parent.id); } else { expect(user.parent).toBeNil(); expect(user.parentId).toBeNil(); } }); }); }); association-create-test.js000066400000000000000000000014001412317504700350770ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [child] = helper[state](); let ganon = child.createParent({ name: "Ganon" }); expect(ganon.id).toBeTruthy(); expect(child.parent.attrs).toEqual(ganon.attrs); expect(child.parentId).toEqual(ganon.id); expect(helper.schema.users.find(child.id).parentId).toEqual(ganon.id); }); }); }); association-new-test.js000066400000000000000000000014221412317504700344310ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [child] = helper[state](); let ganon = child.newParent({ name: "Ganon" }); expect(!ganon.id).toBeTruthy(); expect(child.parent).toEqual(ganon); expect(child.parentId).toBeNil(); child.save(); expect(ganon.id).toBeTruthy(); expect(child.parentId).toEqual(ganon.id); }); }); }); association-set-id-test.js000066400000000000000000000020111412317504700350200ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [child] = helper[state](); let savedParent = helper.savedParent(); child.parentId = savedParent.id; expect(child.parentId).toEqual(savedParent.id); expect(child.parent.attrs).toEqual(savedParent.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [child] = helper[state](); child.parentId = null; expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); }); }); }); association-set-test.js000066400000000000000000000022741412317504700344410ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [child] = helper[state](); let savedParent = helper.savedParent(); child.parent = savedParent; expect(child.parentId).toEqual(savedParent.id); expect(child.parent.attrs).toEqual(savedParent.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [child] = helper[state](); let newParent = helper.newParent(); child.parent = newParent; expect(child.parentId).toBeNil(); expect(child.parent).toEqual(newParent); }); test(`a ${state} can update its association to a null parent`, () => { let [child] = helper[state](); child.parent = null; expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexive/create-test.js000066400000000000000000000035641412317504700326610ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let parent = schema.create("user"); let child = schema.create("user", { parentId: parent.id, }); expect(child.parentId).toEqual(parent.id); expect(child.parent.attrs).toEqual(parent.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", parentId: null }); expect(schema.db.users[1]).toEqual({ id: "2", parentId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let parent = schema.create("user"); let child = schema.create("user", { parent, }); expect(child.parentId).toEqual(parent.id); expect(child.parent.attrs).toEqual(parent.attrs); expect(schema.db.users).toHaveLength(2); expect(schema.db.users[0]).toEqual({ id: "1", parentId: null }); expect(schema.db.users[1]).toEqual({ id: "2", parentId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexive/delete-test.js000066400000000000000000000011151412317504700326460ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, parent] = helper[state](); if (parent) { parent.destroy(); user.reload(); } expect(user.parentId).toBeNil(); expect(user.parent).toBeNil(); }); }); }); instantiating-test.js000066400000000000000000000051001412317504700341770ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/7-named-one-way-reflexiveimport Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | Named One-Way Reflexive | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let parent = helper.savedParent(); let child = schema.users.new({ parentId: parent.id }); expect(child.parentId).toEqual(parent.id); expect(child.parent.attrs).toEqual(parent.attrs); expect(child.attrs).toEqual({ parentId: parent.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ parentId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let child = schema.users.new({ parentId: null }); expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); expect(child.attrs).toEqual({ parentId: null }); }); test("the child accepts a saved parent model", () => { let parent = helper.savedParent(); let child = schema.users.new({ parent }); expect(child.parentId).toEqual("1"); expect(child.parent.attrs).toEqual(parent.attrs); }); test("the child accepts a new parent model", () => { let zelda = schema.users.new({ name: "Zelda" }); let child = schema.users.new({ parent: zelda }); expect(child.parentId).toBeNil(); expect(child.parent).toEqual(zelda); expect(child.attrs).toEqual({ parentId: null }); }); test("the child accepts a null parent model", () => { let child = schema.users.new({ parent: null }); expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); expect(child.attrs).toEqual({ parentId: null }); }); test("the child accepts a parent model and id", () => { let parent = helper.savedParent(); let child = schema.users.new({ parent, parentId: parent.id }); expect(child.parentId).toEqual("1"); expect(child.parent.attrs).toEqual(parent.attrs); expect(child.attrs).toEqual({ parentId: parent.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let child = schema.users.new({}); expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); expect(child.attrs).toEqual({ parentId: null }); }); test("the child accepts no reference to a parent id or model", () => { let child = schema.users.new(); expect(child.parentId).toBeNil(); expect(child.parent).toBeNil(); expect(child.attrs).toEqual({ parentId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/000077500000000000000000000000001412317504700254245ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/_helper.js000066400000000000000000000050211412317504700273760ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ profile: belongsTo(), }), profile: Model.extend({ user: belongsTo(), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(insertedUser.id), undefined]; } savedChildNewParent() { let user = this.schema.users.create({ name: "Link" }); let profile = this.schema.profiles.new({ age: 300 }); user.profile = profile; return [user, profile]; } savedChildSavedParent() { let insertedProfile = this.db.profiles.insert({ age: 300 }); let insertedUser = this.db.users.insert({ name: "Link", profileId: insertedProfile.id, }); this.db.profiles.update(insertedProfile.id, { userId: insertedUser.id }); let user = this.schema.users.find(insertedUser.id); let profile = this.schema.profiles.find(insertedProfile.id); return [user, profile]; } newChildNoParent() { return [this.schema.users.new({ name: "Link" }), undefined]; } newChildNewParent() { let profile = this.schema.profiles.new({ age: 300 }); let user = this.schema.users.new({ name: "Link" }); user.profile = profile; return [user, profile]; } newChildSavedParent() { let insertedProfile = this.db.profiles.insert({ age: 300 }); let user = this.schema.users.new({ name: "Link" }); let savedProfile = this.schema.profiles.find(insertedProfile.id); user.profile = savedProfile; return [user, savedProfile]; } // Just a saved unassociated parent. savedParent() { let insertedProfile = this.db.profiles.insert({ age: 300 }); return this.schema.profiles.find(insertedProfile.id); } newParent() { return this.schema.profiles.new({ age: 300 }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/accessor-test.js000066400000000000000000000020161412317504700305400ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, profile] = helper[state](); // We use .attrs here because otherwise deepEqual goes on infinite recursive comparison if (profile) { expect(user.profile.attrs).toEqual(profile.attrs); expect(user.profileId).toEqual(profile.id); } else { expect(user.profile).toBeNil(); expect(user.profileId).toBeNil(); } // If there's a profile in this state, make sure the inverse association is correct if (profile) { expect(profile.user.attrs).toEqual(user.attrs); expect(profile.userId).toEqual(user.id); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/association-create-test.js000066400000000000000000000014551412317504700325210ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let profile = user.createProfile({ age: 300 }); expect(profile.id).toBeTruthy(); expect(user.profile.attrs).toEqual(profile.attrs); expect(profile.user.attrs).toEqual(user.attrs); expect(user.profileId).toEqual(profile.id); expect(helper.schema.users.find(user.id).profileId).toEqual(profile.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/association-new-test.js000066400000000000000000000015411412317504700320430ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let profile = user.newProfile({ age: 300 }); expect(!profile.id).toBeTruthy(); expect(user.profile).toEqual(profile); expect(user.profileId).toBeNil(); expect(profile.user).toEqual(user); expect(profile.userId).toEqual(user.id); user.save(); expect(profile.id).toBeTruthy(); expect(user.profileId).toEqual(profile.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/association-set-id-test.js000066400000000000000000000015071412317504700324410ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let profile = helper.savedParent(); user.profileId = profile.id; expect(user.profileId).toEqual(profile.id); expect(user.profile.attrs).toEqual(profile.attrs); user.save(); profile.reload(); expect(profile.userId).toEqual(user.id); expect(profile.user.attrs).toEqual(user.attrs); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/association-set-test.js000066400000000000000000000025551412317504700320530ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [user] = helper[state](); let profile = helper.savedParent(); user.profile = profile; expect(user.profileId).toEqual(profile.id); expect(user.profile.attrs).toEqual(profile.attrs); expect(profile.userId).toEqual(user.id); expect(profile.user.attrs).toEqual(user.attrs); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let profile = helper.newParent(); user.profile = profile; expect(user.profileId).toBeNil(); expect(user.profile.attrs).toEqual(profile.attrs); expect(profile.userId).toEqual(user.id); expect(profile.user.attrs).toEqual(user.attrs); }); test(`a ${state} can update its association to a null parent`, () => { let [user] = helper[state](); user.profile = null; expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/create-test.js000066400000000000000000000041241412317504700302030ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | One To One | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let profile = schema.create("profile"); let user = schema.create("user", { profileId: profile.id, }); profile.reload(); expect(user.profileId).toEqual(profile.id); expect(user.profile.attrs).toEqual(profile.attrs); expect(profile.user.attrs).toEqual(user.attrs); expect(schema.db.users).toHaveLength(1); expect(schema.db.profiles).toHaveLength(1); expect(schema.db.users[0]).toEqual({ id: "1", profileId: "1" }); expect(schema.db.profiles[0]).toEqual({ id: "1", userId: "1" }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let profile = schema.create("profile"); let user = schema.create("user", { profile, }); expect(user.profileId).toEqual(profile.id); expect(user.profile.attrs).toEqual(profile.attrs); expect(profile.user.attrs).toEqual(user.attrs); expect(schema.db.users).toHaveLength(1); expect(schema.db.profiles).toHaveLength(1); expect(schema.db.users[0]).toEqual({ id: "1", profileId: "1" }); expect(schema.db.profiles[0]).toEqual({ id: "1", userId: "1" }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/delete-test.js000066400000000000000000000011051412317504700301760ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [user, profile] = helper[state](); if (profile) { profile.destroy(); user.reload(); } expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/8-one-to-one/instantiating-test.js000066400000000000000000000052021412317504700316120ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | One To One | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let profile = helper.savedParent(); let user = schema.users.new({ profileId: profile.id }); expect(user.profileId).toEqual(profile.id); expect(user.profile.attrs).toEqual(profile.attrs); expect(user.attrs).toEqual({ profileId: profile.id }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.users.new({ profileId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let user = schema.users.new({ profileId: null }); expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); expect(user.attrs).toEqual({ profileId: null }); }); test("the child accepts a saved parent model", () => { let profile = helper.savedParent(); let user = schema.users.new({ profile }); expect(user.profileId).toEqual("1"); expect(user.profile.attrs).toEqual(profile.attrs); expect(user.attrs).toEqual({ profileId: null }); // this would update when saved }); test("the child accepts a new parent model", () => { let profile = schema.profiles.new({ age: 300 }); let user = schema.users.new({ profile }); expect(user.profileId).toBeNil(); expect(user.profile).toEqual(profile); expect(user.attrs).toEqual({ profileId: null }); }); test("the child accepts a null parent model", () => { let user = schema.users.new({ profile: null }); expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); expect(user.attrs).toEqual({ profileId: null }); }); test("the child accepts a parent model and id", () => { let profile = helper.savedParent(); let user = schema.users.new({ profile, profileId: profile.id }); expect(user.profileId).toEqual("1"); expect(user.profile).toEqual(profile); expect(user.attrs).toEqual({ profileId: profile.id }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let user = schema.users.new({}); expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); expect(user.attrs).toEqual({ profileId: null }); }); test("the child accepts no reference to a parent id or model", () => { let user = schema.users.new(); expect(user.profileId).toBeNil(); expect(user.profile).toBeNil(); expect(user.attrs).toEqual({ profileId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/000077500000000000000000000000001412317504700273675ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/_helper.js000066400000000000000000000051021412317504700313410ustar00rootroot00000000000000import { Server, Model, belongsTo } from "miragejs"; /* A model with a belongsTo association can be in six states with respect to its association. This helper class returns a child (and its association) in these various states. The return value is an array of the form [ child, parent ] where the parent may be undefined. */ export default class BelongsToHelper { constructor() { this.server = new Server({ environment: "test", models: { post: Model.extend(), comment: Model.extend({ commentable: belongsTo("commentable", { polymorphic: true }), }), }, }); this.db = this.server.db; this.loadData = this.db.loadData.bind(this.db); this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let insertedComment = this.db.comments.insert({ text: "Lorem" }); return [this.schema.comments.find(insertedComment.id), undefined]; } savedChildNewParent() { this.loadData({ comments: [{ id: "1", text: "Lorem" }], }); let comment = this.schema.comments.find(1); let post = this.schema.posts.new({ title: "Bob" }); comment.commentable = post; return [comment, post]; } savedChildSavedParent() { this.loadData({ posts: [{ id: "1", title: "Lorem ipsum" }], comments: [ { id: "1", text: "Trolling", commentableId: { id: "1", type: "post" } }, ], }); let comment = this.schema.comments.find(1); let post = this.schema.posts.find(1); return [comment, post]; } newChildNoParent() { return [this.schema.comments.new({ text: "Lorem" }), undefined]; } newChildNewParent() { let comment = this.schema.comments.new({ text: "Lorem" }); let newPost = this.schema.posts.new({ title: "Bob" }); comment.commentable = newPost; return [comment, newPost]; } newChildSavedParent() { this.loadData({ posts: [{ id: "1", title: "Lorem ipsum" }], }); let comment = this.schema.comments.new({ text: "Lorem" }); let savedPost = this.schema.posts.find(1); comment.commentable = savedPost; return [comment, savedPost]; } // Just a saved unassociated parent. savedParent() { let insertedPost = this.db.posts.insert({ title: "Bob" }); return this.schema.posts.find(insertedPost.id); } newParent() { return this.schema.posts.new({ title: "Bob" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/accessor-test.js000066400000000000000000000012241412317504700325030ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [comment, post] = helper[state](); expect(comment.commentable).toEqual(post ? post : null); expect(comment.commentableId).toEqual( post ? { id: post.id, type: "post" } : null ); }); }); }); association-create-test.js000066400000000000000000000014411412317504700344000ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [comment] = helper[state](); let post = comment.createCommentable("post", { title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(comment.commentable.attrs).toEqual(post.attrs); expect(comment.commentableId).toEqual({ id: post.id, type: "post" }); expect(helper.db.posts.find(post.id)).toBeTruthy(); }); }); }); association-new-test.js000066400000000000000000000015551412317504700337340ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [comment] = helper[state](); let post = comment.newCommentable("post", { title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(comment.commentable).toEqual(post); expect(comment.commentableId).toEqual({ id: undefined, type: "post" }); comment.save(); expect(post.id).toBeTruthy(); expect(comment.commentableId).toEqual({ id: post.id, type: "post" }); }); }); }); association-set-id-test.js000066400000000000000000000021271412317504700343240ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | association #setId", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [comment] = helper[state](); let savedPost = helper.savedParent(); comment.commentableId = { id: savedPost.id, type: "post" }; expect(comment.commentableId).toEqual({ id: savedPost.id, type: "post" }); expect(comment.commentable.attrs).toEqual(savedPost.attrs); }); }); ["savedChildSavedParent", "newChildSavedParent"].forEach((state) => { test(`a ${state} can clear its association via a null parentId`, () => { let [comment] = helper[state](); comment.commentableId = null; expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); }); }); }); association-set-test.js000066400000000000000000000024301412317504700337270ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [comment] = helper[state](); let savedPost = helper.savedParent(); comment.commentable = savedPost; expect(comment.commentableId).toEqual({ id: savedPost.id, type: "post" }); expect(comment.commentable).toEqual(savedPost); }); test(`a ${state} can update its association to a new parent`, () => { let [comment] = helper[state](); let newPost = helper.newParent(); comment.commentable = newPost; expect(comment.commentableId).toEqual({ id: undefined, type: "post" }); expect(comment.commentable).toEqual(newPost); }); test(`a ${state} can update its association to a null parent`, () => { let [comment] = helper[state](); comment.commentable = null; expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/create-test.js000066400000000000000000000031551412317504700321510ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let comment = helper.schema.create("comment", { commentableId: { id: post.id, type: "post" }, }); expect(comment.commentableId).toEqual({ id: post.id, type: "post" }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1" }); expect(helper.schema.db.comments).toHaveLength(1); expect(helper.schema.db.comments[0]).toEqual({ id: "1", commentableId: { id: "1", type: "post" }, }); }); test("it sets up associations correctly when passing in the association itself", () => { let post = helper.schema.create("post"); let comment = helper.schema.create("comment", { commentable: post, }); expect(comment.commentableId).toEqual({ id: post.id, type: "post" }); expect(comment.commentable.attrs).toEqual(post.attrs); expect(helper.schema.db.posts).toHaveLength(1); expect(helper.schema.db.posts[0]).toEqual({ id: "1" }); expect(helper.schema.db.comments).toHaveLength(1); expect(helper.schema.db.comments[0]).toEqual({ id: "1", commentableId: { id: "1", type: "post" }, }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/delete-test.js000066400000000000000000000011221412317504700321400ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting the parent updates the child's foreign key for a ${state}`, () => { let [comment, post] = helper[state](); if (post) { post.destroy(); comment.reload(); } expect(comment.commentableId).toBeNil(); expect(comment.post).toBeNil(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/9-one-way-polymorphic/instantiating-test.js000066400000000000000000000060021412317504700335540ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Belongs To | One-way Polymorphic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentableId: { id: post.id, type: "post" }, }); expect(comment.commentableId).toEqual({ id: post.id, type: "post" }); expect(comment.commentable).toEqual(post); expect(comment.attrs).toEqual({ commentableId: { id: post.id, type: "post" }, }); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.comments.new({ commentableId: { type: "post", id: 2 } }); }).toThrow(); }); test("the child accepts a null parent id", () => { let comment = schema.comments.new({ commentableId: null }); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a saved parent model", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentable: post }); expect(comment.commentableId).toEqual({ type: "post", id: post.id }); expect(comment.commentable).toEqual(post); }); test("the child accepts a new parent model", () => { let post = schema.posts.new({ text: "foo" }); let comment = schema.comments.new({ commentable: post }); expect(comment.commentableId).toEqual({ type: "post", id: undefined }); expect(comment.commentable).toEqual(post); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a null parent model", () => { let comment = schema.comments.new({ commentable: null }); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts a parent model and id", () => { let post = helper.savedParent(); let comment = schema.comments.new({ commentable: post, commentableId: { type: "post", id: post.id }, }); expect(comment.commentableId).toEqual({ type: "post", id: "1" }); expect(comment.commentable).toEqual(post); expect(comment.attrs).toEqual({ commentableId: { type: "post", id: post.id }, }); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let comment = schema.comments.new({}); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); test("the child accepts no reference to a parent id or model", () => { let comment = schema.comments.new(); expect(comment.commentableId).toBeNil(); expect(comment.commentable).toBeNil(); expect(comment.attrs).toEqual({ commentableId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/notes.md000066400000000000000000000016421412317504700247540ustar00rootroot00000000000000A belongsTo relationship has the following possible schemas. For each schema, the child model can be in six states with respect to its parent: - the child can be saved and the parent can be one of: undefined, new or saved - the child can be new and the parent can be one of: undefined, new or saved This is how the tests in this directory are organized. # belongsTo Given Post, Author models For the Post model ## basic author: belongsTo() ## named writer: belongsTo('author') ## reflexive, one-way post: belongsTo() ## named reflexive childPost: belongsTo('post') ## inverse (implicit) author: belongsTo() (author) posts: hasMany() ## inverse (explicit) author: belongsTo('author', { inverse: 'redPosts' }) (author) posts: hasMany('post', { inverse: 'author' }) drafts: hasMany('post') ## multiple (conflict) primaryAuthor: belongsTo('author') secondaryAuthor: belongsTo('author') (author) posts: hasMany() miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/regressions/000077500000000000000000000000001412317504700256425ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/regressions/issue-1112-test.js000066400000000000000000000015121412317504700306660ustar00rootroot00000000000000import { Server, Model, belongsTo, hasMany } from "miragejs"; describe("External | Shared | ORM | Belongs To | Regressions | Issue 1112", function () { test(`deleting a record with a polymorphic belongsTo doesn't interfere with other dependents`, () => { let server = new Server({ environment: "test", models: { comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), user: belongsTo("user"), }), post: Model, user: Model.extend({ comments: hasMany("comment"), }), }, }); let user = server.schema.users.create(); let post = server.schema.posts.create(); let comment = server.schema.comments.create({ commentable: post, user }); comment.destroy(); expect(user.reload().commentIds).toBeEmpty(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/belongs-to/regressions/pr-1312-test.js000066400000000000000000000013501412317504700301610ustar00rootroot00000000000000import { Server, Model, belongsTo, hasMany } from "miragejs"; describe("External | Shared | ORM | Belongs To | Regressions | pr-1312", function () { test(`creating and using a record with a polymorphic hasMany and explicit inverse does not fail when accessing the association`, () => { let server = new Server({ environment: "test", models: { comment: Model.extend({ commentable: belongsTo({ polymorphic: true, inverse: "comments" }), }), post: Model.extend({ comments: hasMany("comment", { inverse: "commentable" }), }), }, }); let post = server.schema.posts.create(); post.createComment(); expect(post.comments.models).toHaveLength(1); }); }); miragejs-0.1.42/__tests__/external/shared/orm/collection-test.js000066400000000000000000000055011412317504700246750ustar00rootroot00000000000000import { Server, Model, Collection } from "miragejs"; describe("External | Shared | ORM | collection", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, }, }); server.db.loadData({ users: [ { id: 1, name: "Link", good: true }, { id: 2, name: "Zelda", good: true }, { id: 3, name: "Ganon", good: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("a collection can save its models", () => { let collection = server.schema.users.all(); collection.models[0].name = "Sam"; collection.save(); expect(server.db.users[0]).toEqual({ id: "1", name: "Sam", good: true }); }); test("a collection can reload its models", () => { let collection = server.schema.users.all(); expect(collection.models[0].name).toEqual("Link"); collection.models[0].name = "Sam"; expect(collection.models[0].name).toEqual("Sam"); collection.reload(); expect(collection.models[0].name).toEqual("Link"); }); test("a collection can filter its models", () => { let collection = server.schema.users.all(); expect(collection.models).toHaveLength(3); let newCollection = collection.filter((author) => author.good); expect(newCollection instanceof Collection).toBeTruthy(); expect(newCollection.modelName).toEqual("user"); expect(newCollection.models).toHaveLength(2); }); test("a collection can sort its models", () => { let collection = server.schema.users.all(); expect(collection.models.map((m) => m.name)).toEqual([ "Link", "Zelda", "Ganon", ]); let newCollection = collection.sort((a, b) => { return a.name.localeCompare(b.name); }); expect(newCollection instanceof Collection).toBeTruthy(); expect(newCollection.modelName).toEqual("user"); expect(newCollection.models.map((m) => m.name)).toEqual([ "Ganon", "Link", "Zelda", ]); }); test("a collection can slice its models", () => { let collection = server.schema.users.all(); expect(collection.models.map((m) => m.name)).toEqual([ "Link", "Zelda", "Ganon", ]); let newCollection = collection.slice(-2); expect(newCollection instanceof Collection).toBeTruthy(); expect(newCollection.modelName).toEqual("user"); expect(newCollection.models.map((m) => m.name)).toEqual(["Zelda", "Ganon"]); }); test("a collection can merge with another collection", () => { let goodGuys = server.schema.users.where((user) => user.good); let badGuys = server.schema.users.where((user) => !user.good); expect(goodGuys.models).toHaveLength(2); expect(badGuys.models).toHaveLength(1); goodGuys.mergeCollection(badGuys); expect(goodGuys.models).toHaveLength(3); }); }); miragejs-0.1.42/__tests__/external/shared/orm/create-test.js000066400000000000000000000027461412317504700240150ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | create", () => { let User; let server; beforeEach(() => { User = Model.extend(); server = new Server({ environment: "test", models: { user: User, }, }); }); afterEach(() => { server.shutdown(); }); test("it cannot make new models that havent been registered", () => { expect(function () { server.schema.authors.new({ name: "Link" }); }).toThrow(); }); test("it cannot create models that havent been registered", () => { expect(function () { server.schema.authors.create({ name: "Link" }); }).toThrow(); }); test("it can make new models and then save them", () => { let user = server.schema.users.new({ name: "Link" }); expect(user instanceof User).toBeTruthy(); expect(user.attrs).toEqual({ name: "Link" }); expect(server.db.users).toBeEmpty(); user.save(); expect(user.id).toBeTruthy(); expect(user.attrs).toEqual({ id: "1", name: "Link" }); expect(server.db.users).toIncludeSameMembers([{ id: "1", name: "Link" }]); }); test("it can create new models, saved directly to the db", () => { let user = server.schema.users.create({ name: "Link" }); expect(user instanceof Model).toBeTruthy(); expect(user instanceof User).toBeTruthy(); expect(user.attrs).toEqual({ id: "1", name: "Link" }); expect(server.db.users).toIncludeSameMembers([{ id: "1", name: "Link" }]); }); }); miragejs-0.1.42/__tests__/external/shared/orm/destroy-test.js000066400000000000000000000020571412317504700242360ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | destroy", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, }, }); server.db.loadData({ users: [ { id: 1, name: "Link", evil: false }, { id: 2, name: "Link", location: "Hyrule", evil: false }, { id: 3, name: "Zelda", location: "Hyrule", evil: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("destroying a model removes the associated record from the db", () => { expect(server.db.users).toHaveLength(3); let link = server.schema.users.find(1); link.destroy(); expect(server.db.users.find(1)).toBeNull(); expect(server.db.users).toHaveLength(2); }); test("destroying a collection removes the associated records from the db", () => { expect(server.db.users).toHaveLength(3); let users = server.schema.users.all(); users.destroy(); expect(server.db.users).toBeEmpty(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/find-or-create-by-test.js000066400000000000000000000023001412317504700257430ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | #findOrCreateBy", () => { let User; let server; beforeEach(() => { User = Model; server = new Server({ environment: "test", models: { user: User, }, }); server.db.loadData({ users: [ { id: 1, name: "Link", good: true }, { id: 2, name: "Zelda", good: true }, { id: 3, name: "Ganon", good: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("it returns the first model that matches the attrs", () => { let user = server.schema.users.findOrCreateBy({ good: true }); expect(user instanceof User).toBeTruthy(); expect(user.attrs).toEqual({ id: "1", name: "Link", good: true }); }); test("it creates a model if no existing model with the attrs is found", () => { expect(server.schema.db.users).toHaveLength(3); let newUser = server.schema.users.findOrCreateBy({ name: "Link", good: false, }); expect(server.schema.db.users).toHaveLength(4); expect(newUser instanceof User).toBeTruthy(); expect(newUser.attrs).toEqual({ id: "4", name: "Link", good: false }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/find-test.js000066400000000000000000000024731412317504700234670ustar00rootroot00000000000000import { Server, Model, Collection } from "miragejs"; describe("External | Shared | ORM | #find", () => { let User; let server; beforeEach(() => { User = Model.extend(); server = new Server({ environment: "test", models: { user: User, }, }); server.db.loadData({ users: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], }); }); afterEach(() => { server.shutdown(); }); test("it can find a model by id", () => { let zelda = server.schema.users.find(2); expect(zelda instanceof User).toBeTruthy(); expect(zelda.attrs).toEqual({ id: "2", name: "Zelda" }); }); test("it returns null if no model is found for an id", () => { let user = server.schema.users.find(4); expect(user).toBeNull(); }); test("it can find multiple models by ids", () => { let users = server.schema.users.find([1, 2]); expect(users instanceof Collection).toBeTruthy(); expect(users.models[0] instanceof User).toBeTruthy(); expect(users.models).toHaveLength(2); expect(users.models[1].attrs).toEqual({ id: "2", name: "Zelda" }); }); test("it errors if incorrect number of models are found for an array of ids", () => { expect(function () { server.schema.users.find([1, 6]); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/first-test.js000066400000000000000000000012321412317504700236660ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | #first", () => { let User; let server; beforeEach(() => { User = Model.extend(); server = new Server({ environment: "test", models: { user: User, }, }); server.db.loadData({ users: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], }); }); afterEach(() => { server.shutdown(); }); test("it can find the first model", () => { let user = server.schema.users.first(); expect(user instanceof User).toBeTruthy(); expect(user.attrs).toEqual({ id: "1", name: "Link" }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/000077500000000000000000000000001412317504700227435ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/000077500000000000000000000000001412317504700241625ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/_helper.js000066400000000000000000000061701412317504700261420ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ posts: hasMany(), }), post: Model, }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.posts = [post1, post2]; user.save(); return [user, [post1, post2]]; } savedParentMixedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/accessor-test.js000066400000000000000000000014361412317504700273030ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.posts.models).toHaveLength(posts.length); expect(user.postIds).toHaveLength(posts.length); posts.forEach((post, i) => { expect(user.posts.models[i]).toEqual(posts[i]); if (post.isSaved()) { expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); } }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/association-create-test.js000066400000000000000000000015441412317504700312560ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.posts.models.length; let post = user.createPost({ title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.posts.models).toHaveLength(initialCount + 1); expect(user.posts.includes(post)).toBeTruthy(); expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); expect(user.attrs.postIds.indexOf(post.id) > -1).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/association-new-test.js000066400000000000000000000017631412317504700306070ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.posts.models.length; let post = user.newPost({ title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.posts.models).toHaveLength(initialCount + 1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum" }); expect(user.posts.models).toHaveLength(initialCount + 1); expect(user.posts.models.filter((a) => a.id === post.id)[0]).toEqual( post ); expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/association-set-ids-test.js000066400000000000000000000016521412317504700313630ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.postIds = [savedPost.id]; expect(user.posts.models[0].attrs).toEqual(savedPost.attrs); expect(user.postIds).toEqual([savedPost.id]); }); test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.postIds = null; expect(user.posts.models).toBeEmpty(); expect(user.postIds).toBeEmpty(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/association-set-test.js000066400000000000000000000026761412317504700306150ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.posts = [savedPost]; expect(user.posts.models.indexOf(savedPost) > -1).toBeTruthy(); expect(user.postIds.indexOf(savedPost.id) > -1).toBeTruthy(); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let newPost = helper.newChild(); user.posts = [newPost]; expect(user.postIds).toEqual([undefined]); expect(user.posts.models[0]).toEqual(newPost); }); test(`a ${state} can clear its association via an empty list`, () => { let [user] = helper[state](); user.posts = []; expect(user.postIds).toBeEmpty(); expect(user.posts.models).toHaveLength(0); }); test(`a ${state} can clear its association via an empty list`, () => { let [user] = helper[state](); user.posts = null; expect(user.postIds).toBeEmpty(); expect(user.posts.models).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/create-test.js000066400000000000000000000055011412317504700267410ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Basic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { postIds: [post.id], }); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { posts: [post], }); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { posts: helper.schema.posts.all(), }); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/delete-test.js000066400000000000000000000011411412317504700267340ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [user, posts] = helper[state](); if (posts && posts.length) { posts.forEach((p) => p.destroy()); user.reload(); } expect(user.posts).toHaveLength(0); expect(user.postIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/1-basic/instantiating-test.js000066400000000000000000000046531412317504700303610ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Basic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ postIds: [post.id], }); expect(user.postIds).toEqual([post.id]); expect(user.posts.models[0]).toEqual(post); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ postIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ postIds: null }); expect(user.posts.models).toHaveLength(0); expect(user.postIds).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ posts: [post] }); expect(user.postIds).toEqual([post.id]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ posts: [post] }); expect(user.postIds).toEqual([undefined]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts null children", () => { let user = schema.users.new({ posts: null }); expect(user.posts.models).toHaveLength(0); expect(user.postIds).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ posts: [post], postIds: [post.id] }); expect(user.postIds).toEqual([post.id]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.postIds).toBeEmpty(); expect(user.posts.models).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.postIds).toBeEmpty(); expect(user.posts.models).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphic/000077500000000000000000000000001412317504700300525ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphic/_helper.js000066400000000000000000000072171412317504700320350ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { post: Model.extend({ users: hasMany(), }), user: Model.extend({ commentables: hasMany({ polymorphic: true }), }), }, }); this.db = this.server.db; this.loadData = this.db.loadData.bind(this.db); this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.commentables = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { this.loadData({ posts: [ { id: "1", title: "Lorem", userIds: ["1"] }, { id: "2", title: "Ipsum", userIds: ["1"] }, ], users: [ { id: "1", name: "Link", commentableIds: [ { type: "post", id: "1" }, { type: "post", id: "2" }, ], }, ], }); let user = this.schema.users.find(1); let post1 = this.schema.posts.find(1); let post2 = this.schema.posts.find(2); return [user, [post1, post2]]; } savedParentMixedChildren() { this.loadData({ posts: [{ id: "1", title: "Lorem", userIds: [] }], users: [{ id: "1", name: "Link", commentableIds: [] }], }); let user = this.schema.users.find(1); let post1 = this.schema.posts.find(1); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.commentables = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.commentables = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.commentables = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.commentables = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphic/accessor-test.js000066400000000000000000000016521412317504700331730ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.commentables.models).toHaveLength(posts.length); expect(user.commentableIds).toHaveLength(posts.length); posts.forEach((post, i) => { expect(user.commentables.includes(post)).toBeTruthy(); if (post.isSaved()) { expect(user.commentableIds[i]).toEqual({ type: "post", id: post.id }); } // Check the inverse expect(post.users.includes(user)).toBeTruthy(); }); }); }); }); association-create-test.js000066400000000000000000000022011412317504700350560ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.commentables.models.length; let post = user.createCommentable("post", { title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.commentables.models).toHaveLength(initialCount + 1); expect(user.commentables.includes(post)).toBeTruthy(); expect( user.commentableIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); expect( user.attrs.commentableIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); expect(post.users.includes(user)).toBeTruthy(); }); }); }); association-new-test.js000066400000000000000000000023671412317504700344210ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.commentables.models.length; let post = user.newCommentable("post", { title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.commentables.models).toHaveLength(initialCount + 1); expect(post.users.models).toHaveLength(1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum", userIds: [user.id], }); expect(user.commentables.models).toHaveLength(initialCount + 1); expect(user.commentables.includes(post)).toBeTruthy(); expect( user.commentableIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); expect(post.users.includes(user)).toBeTruthy(); }); }); }); association-set-ids-test.js000066400000000000000000000030211412317504700351640ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.commentableIds = [{ type: "post", id: savedPost.id }]; expect(user.commentables.includes(savedPost)).toBeTruthy(); expect( user.commentableIds.find( ({ id, type }) => id === savedPost.id && type === "post" ) ).toBeTruthy(); user.save(); savedPost.reload(); expect(savedPost.users.includes(user)).toBeTruthy(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.users.includes(user)).toBeFalsy(); } }); }); test(`a ${state} can clear its association via a null ids`, () => { let [user, originalPosts] = helper[state](); user.commentableIds = null; expect(user.commentables.models).toBeEmpty(); expect(user.commentableIds).toBeEmpty(); user.save(); originalPosts.forEach((post) => { post.reload(); expect(post.users.includes(user)).toBeFalsy(); }); }); }); }); association-set-test.js000066400000000000000000000045721412317504700344230ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.commentables = [savedPost]; expect(user.commentables.models.includes(savedPost)).toBeTruthy(); expect( user.commentableIds.find( ({ id, type }) => id === savedPost.id && type === "post" ) ).toBeTruthy(); expect(savedPost.users.includes(user)).toBeTruthy(); user.save(); originalPosts.forEach((post) => { post.reload(); expect(post.users.includes(user)).toBeFalsy(); }); }); test(`a ${state} can update its association to a new parent`, () => { let [user, originalPosts] = helper[state](); let newPost = helper.newChild(); user.commentables = [newPost]; expect(user.commentableIds).toEqual([{ type: "post", id: undefined }]); expect(user.commentables.models[0]).toEqual(newPost); expect(newPost.users.includes(user)).toBeTruthy(); user.save(); originalPosts.forEach((post) => { post.reload(); expect(post.users.includes(user)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [user, originalPosts] = helper[state](); user.commentables = []; expect(user.commentableIds).toBeEmpty(); expect(user.commentables.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { post.reload(); expect(post.users.includes(user)).toBeFalsy(); }); }); test(`a ${state} can clear its association via null`, () => { let [user, originalPosts] = helper[state](); user.commentables = null; expect(user.commentableIds).toBeEmpty(); expect(user.commentables.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { post.reload(); expect(post.users.includes(user)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphic/create-test.js000066400000000000000000000042031412317504700326270ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { commentableIds: [{ type: "post", id: post.id }], }); post.reload(); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(user.commentables.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.users).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1", userIds: ["1"] }); expect(helper.db.users[0]).toEqual({ id: "1", commentableIds: [{ type: "post", id: "1" }], }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { commentables: [post], }); post.reload(); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(post.userIds).toEqual(["1"]); expect(user.attrs.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(post.attrs.userIds).toEqual([user.id]); expect(helper.db.users).toHaveLength(1); expect(helper.db.posts).toHaveLength(1); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { commentables: helper.schema.posts.all(), }); post.reload(); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(post.userIds).toEqual([user.id]); expect(user.attrs.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(post.attrs.userIds).toEqual([user.id]); expect(helper.db.users).toHaveLength(1); expect(helper.db.posts).toHaveLength(1); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphic/delete-test.js000066400000000000000000000012021412317504700326220ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [user, posts] = helper[state](); if (posts && posts.length) { posts.forEach((p) => p.destroy()); user.reload(); } expect(user.commentables).toHaveLength(0); expect(user.commentableIds).toHaveLength(0); }); }); }); instantiating-test.js000066400000000000000000000054751412317504700341750ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/10-many-to-many-polymorphicimport Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Many-to-many Polymorphic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ commentableIds: [{ type: "post", id: post.id }], }); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(user.commentables.includes(post)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ commentableIds: [{ type: "post", id: 2 }] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ commentableIds: null }); expect(user.commentables.models).toHaveLength(0); expect(user.commentableIds).toBeEmpty(); expect(user.attrs).toEqual({ commentableIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ commentables: [post] }); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(user.commentables.includes(post)).toBeTruthy(); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ commentables: [post] }); expect(user.commentableIds).toEqual([{ type: "post", id: undefined }]); expect(user.commentables.includes(post)).toBeTruthy(); }); test("the parent accepts null children", () => { let user = schema.users.new({ commentables: null }); expect(user.commentables.models).toHaveLength(0); expect(user.commentableIds).toBeEmpty(); expect(user.attrs).toEqual({ commentableIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ commentables: [post], commentableIds: [{ type: "post", id: post.id }], }); expect(user.commentableIds).toEqual([{ type: "post", id: post.id }]); expect(user.commentables.includes(post)).toBeTruthy(); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.commentableIds).toBeEmpty(); expect(user.commentables.models).toBeEmpty(); expect(user.attrs).toEqual({ commentableIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.commentableIds).toBeEmpty(); expect(user.commentables.models).toBeEmpty(); expect(user.attrs).toEqual({ commentableIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/000077500000000000000000000000001412317504700241665ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/_helper.js000066400000000000000000000062111412317504700261420ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ blogPosts: hasMany("post"), }), post: Model, }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } savedParentMixedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.blogPosts = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/accessor-test.js000066400000000000000000000014561412317504700273110ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.blogPosts.models).toHaveLength(posts.length); expect(user.blogPostIds).toHaveLength(posts.length); posts.forEach((post, i) => { expect(user.blogPosts.models[i]).toEqual(posts[i]); if (post.isSaved()) { expect(user.blogPostIds.indexOf(post.id) > -1).toBeTruthy(); } }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/association-create-test.js000066400000000000000000000015741412317504700312650ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.blogPosts.models.length; let post = user.createBlogPost({ title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.blogPosts.models).toHaveLength(initialCount + 1); expect(user.blogPosts.includes(post)).toBeTruthy(); expect(user.blogPostIds.indexOf(post.id) > -1).toBeTruthy(); expect(user.attrs.blogPostIds.indexOf(post.id) > -1).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/association-new-test.js000066400000000000000000000020131412317504700306000ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.blogPosts.models.length; let post = user.newBlogPost({ title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.blogPosts.models).toHaveLength(initialCount + 1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum" }); expect(user.blogPosts.models).toHaveLength(initialCount + 1); expect(user.blogPosts.models.filter((a) => a.id === post.id)[0]).toEqual( post ); expect(user.blogPostIds.indexOf(post.id) > -1).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/association-set-ids-test.js000066400000000000000000000017021412317504700313630ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.blogPostIds = [savedPost.id]; expect(user.blogPosts.models[0].attrs).toEqual(savedPost.attrs); expect(user.blogPostIds).toEqual([savedPost.id]); }); test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.blogPostIds = null; expect(user.blogPosts.models).toBeEmpty(); expect(user.blogPostIds).toBeEmpty(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/association-set-test.js000066400000000000000000000027561412317504700306200ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.blogPosts = [savedPost]; expect(user.blogPosts.models.indexOf(savedPost) > -1).toBeTruthy(); expect(user.blogPostIds.indexOf(savedPost.id) > -1).toBeTruthy(); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let newPost = helper.newChild(); user.blogPosts = [newPost]; expect(user.blogPostIds).toEqual([undefined]); expect(user.blogPosts.models[0]).toEqual(newPost); }); test(`a ${state} can clear its association via an empty list`, () => { let [user] = helper[state](); user.blogPosts = []; expect(user.blogPostIds).toBeEmpty(); expect(user.blogPosts.models).toHaveLength(0); }); test(`a ${state} can clear its association via an empty list`, () => { let [user] = helper[state](); user.blogPosts = null; expect(user.blogPostIds).toBeEmpty(); expect(user.blogPosts.models).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/create-test.js000066400000000000000000000055751412317504700267600ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Named | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { blogPostIds: [post.id], }); expect(user.blogPostIds).toEqual([post.id]); expect(user.attrs.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", blogPostIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { blogPosts: [post], }); expect(user.blogPostIds).toEqual([post.id]); expect(user.attrs.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", blogPostIds: ["1"] }); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { blogPosts: helper.schema.posts.all(), }); expect(user.blogPostIds).toEqual([post.id]); expect(user.attrs.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", blogPostIds: ["1"] }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/delete-test.js000066400000000000000000000011711412317504700267430ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [user, blogPosts] = helper[state](); if (blogPosts && blogPosts.length) { blogPosts.forEach((p) => p.destroy()); user.reload(); } expect(user.blogPosts).toHaveLength(0); expect(user.blogPostIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/2-named/instantiating-test.js000066400000000000000000000050541412317504700303610ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Named | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ blogPostIds: [post.id], }); expect(user.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0]).toEqual(post); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ blogPostIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ blogPostIds: null }); expect(user.blogPosts.models).toHaveLength(0); expect(user.blogPostIds).toBeEmpty(); expect(user.attrs).toEqual({ blogPostIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ blogPosts: [post] }); expect(user.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0]).toEqual(post); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ blogPosts: [post] }); expect(user.blogPostIds).toEqual([undefined]); expect(user.blogPosts.models[0]).toEqual(post); }); test("the parent accepts null children", () => { let user = schema.users.new({ blogPosts: null }); expect(user.blogPosts.models).toHaveLength(0); expect(user.blogPostIds).toBeEmpty(); expect(user.attrs).toEqual({ blogPostIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ blogPosts: [post], blogPostIds: [post.id], }); expect(user.blogPostIds).toEqual([post.id]); expect(user.blogPosts.models[0]).toEqual(post); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.blogPostIds).toBeEmpty(); expect(user.blogPosts.models).toBeEmpty(); expect(user.attrs).toEqual({ blogPostIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.blogPostIds).toBeEmpty(); expect(user.blogPosts.models).toBeEmpty(); expect(user.attrs).toEqual({ blogPostIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/000077500000000000000000000000001412317504700250745ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/_helper.js000066400000000000000000000062371412317504700270600ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { tag: Model.extend({ tags: hasMany(), // implicit inverse }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let tag = this.db.tags.insert({ name: "Red" }); return [this.schema.tags.find(tag.id), []]; } savedParentNewChildren() { let tag = this.schema.tags.create({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.tags.insert([ { id: "1", name: "Red", tagIds: ["2", "3"] }, { id: "2", name: "Blue", tagIds: ["1"] }, { id: "3", name: "Green", tagIds: ["1"] }, ]); return [schema.tags.find(1), [schema.tags.find(2), schema.tags.find(3)]]; } savedParentMixedChildren() { this.schema.db.tags.insert([ { id: "1", name: "Red", tagIds: ["2"] }, { id: "2", name: "Blue", tagIds: ["1"] }, ]); let tag = this.schema.tags.find(1); let blueTag = this.schema.tags.find(2); let greenTag = this.schema.tags.new({ name: "Green" }); tag.tags = [blueTag, greenTag]; return [tag, [blueTag, greenTag]]; } newParentNoChildren() { let tag = this.schema.tags.new({ name: "Red" }); return [tag, []]; } newParentNewChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentSavedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.create({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentMixedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedTag = this.db.tags.insert({ name: "Blue" }); return this.schema.tags.find(insertedTag.id); } newChild() { return this.schema.tags.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/accessor-test.js000066400000000000000000000014041412317504700302100ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [tag, tags] = helper[state](); expect(tag.tags.models).toHaveLength(tags.length); expect(tag.tagIds).toHaveLength(tags.length); tags.forEach((t) => { expect(tag.tags.includes(t)).toBeTruthy(); if (t.isSaved()) { expect(tag.tagIds.indexOf(t.id) > -1).toBeTruthy(); } // Check the inverse expect(t.tags.includes(tag)).toBeTruthy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/association-create-test.js000066400000000000000000000025721412317504700321720ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [tag] = helper[state](); let initialCount = tag.tags.models.length; let orangeTag = tag.createTag({ name: "Orange" }); let blueTag = tag.createTag({ name: "Blue" }); expect(orangeTag.id).toBeTruthy(); expect(blueTag.id).toBeTruthy(); expect(tag.tags.models).toHaveLength(initialCount + 2); expect(tag.tags.includes(orangeTag)).toBeTruthy(); expect(tag.tags.includes(blueTag)).toBeTruthy(); expect(tag.tagIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.tagIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(tag.attrs.tagIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.attrs.tagIds.indexOf(blueTag.id) > -1).toBeTruthy(); // Check the inverse expect(orangeTag.tags.models).toHaveLength(1); expect(orangeTag.tags.includes(tag)).toBeTruthy(); expect(blueTag.tags.models).toHaveLength(1); expect(blueTag.tags.includes(tag)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/association-new-test.js000066400000000000000000000021611412317504700315120ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [tag] = helper[state](); let initialCount = tag.tags.models.length; let blueTag = tag.newTag({ name: "Blue" }); expect(!blueTag.id).toBeTruthy(); expect(tag.tags.models).toHaveLength(initialCount + 1); expect(blueTag.tags.models).toHaveLength(1); blueTag.save(); tag.reload(); expect(blueTag.attrs).toEqual({ id: blueTag.id, name: "Blue", tagIds: [tag.id], }); expect(tag.tags.models).toHaveLength(initialCount + 1); expect(tag.tags.includes(blueTag)).toBeTruthy(); expect(tag.tagIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(blueTag.tags.includes(tag)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/association-set-ids-test.js000066400000000000000000000025061412317504700322740ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.tagIds = [savedTag.id]; expect(tag.tags.models[0].attrs).toEqual(savedTag.attrs); expect(tag.tagIds).toEqual([savedTag.id]); tag.save(); savedTag.reload(); expect(savedTag.tags.models[0].attrs).toEqual(tag.attrs); originalTags.forEach((originalTag) => { if (originalTag.isSaved()) { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); } }); }); test(`a ${state} can clear its association via a null childIds`, () => { let [tag, originalTags] = helper[state](); tag.tagIds = null; expect(tag.tags.models).toBeEmpty(); expect(tag.tagIds).toBeEmpty(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/association-set-test.js000066400000000000000000000043031412317504700315140ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.tags = [savedTag]; expect(tag.tags.includes(savedTag)).toBeTruthy(); expect(tag.tagIds[0]).toEqual(savedTag.id); expect(savedTag.tags.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can update its association to a new parent`, () => { let [tag, originalTags] = helper[state](); let newTag = helper.newChild(); tag.tags = [newTag]; expect(tag.tags.includes(newTag)).toBeTruthy(); expect(tag.tagIds[0]).toBeUndefined(); expect(newTag.tags.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.tags = []; expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.tags = null; expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.tags.includes(tag)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/create-test.js000066400000000000000000000053421412317504700276560ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tagIds: [tagA.id], }); tagA.reload(); expect(tagA.tagIds).toEqual([tagB.id]); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.attrs.tagIds).toEqual([tagB.id]); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(tagA.tags.includes(tagB)).toBeTruthy(); expect(tagB.tags.includes(tagA)).toBeTruthy(); expect(helper.db.tags).toHaveLength(2); expect(helper.db.tags[0]).toEqual({ id: "1", tagIds: ["2"] }); expect(helper.db.tags[1]).toEqual({ id: "2", tagIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tags: [tagA], }); tagA.reload(); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.tagIds).toEqual([tagB.id]); expect(tagA.attrs.tagIds).toEqual([tagB.id]); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(helper.db.tags).toHaveLength(2); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tags: schema.tags.all(), }); tagA.reload(); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.tagIds).toEqual([tagB.id]); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(tagA.attrs.tagIds).toEqual([tagB.id]); expect(helper.db.tags).toHaveLength(2); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.tags.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/delete-test.js000066400000000000000000000011331412317504700276470ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [tag, tags] = helper[state](); if (tags && tags.length) { tags.forEach((t) => t.destroy()); tag.reload(); } expect(tag.tags).toHaveLength(0); expect(tag.tagIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/3-reflexive/new-test.js000066400000000000000000000045611412317504700272060ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Reflexive | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tagIds: [tagA.id], }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.includes(tagA)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.tags.new({ tagIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let tag = schema.tags.new({ tagIds: null }); expect(tag.tags.models).toHaveLength(0); expect(tag.tagIds).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts saved children", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tags: [tagA] }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts new children", () => { let tagA = schema.tags.new({ color: "Red" }); let tagB = schema.tags.new({ tags: [tagA] }); expect(tagB.tagIds).toEqual([undefined]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts null children", () => { let tag = schema.tags.new({ tags: null }); expect(tag.tags.models).toHaveLength(0); expect(tag.tagIds).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts children and child ids", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tags: [tagA], tagIds: [tagA.id] }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let tag = schema.tags.new({}); expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let tag = schema.tags.new(); expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/000077500000000000000000000000001412317504700261575ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/_helper.js000066400000000000000000000062721412317504700301420ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { tag: Model.extend({ labels: hasMany("tag"), // implicit inverse }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let tag = this.db.tags.insert({ name: "Red" }); return [this.schema.tags.find(tag.id), []]; } savedParentNewChildren() { let tag = this.schema.tags.create({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2", "3"] }, { id: "2", name: "Blue", labelIds: ["1"] }, { id: "3", name: "Green", labelIds: ["1"] }, ]); return [schema.tags.find(1), [schema.tags.find(2), schema.tags.find(3)]]; } savedParentMixedChildren() { this.schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2"] }, { id: "2", name: "Blue", labelIds: ["1"] }, ]); let tag = this.schema.tags.find(1); let blueTag = this.schema.tags.find(2); let greenTag = this.schema.tags.new({ name: "Green" }); tag.labels = [blueTag, greenTag]; return [tag, [blueTag, greenTag]]; } newParentNoChildren() { let tag = this.schema.tags.new({ name: "Red" }); return [tag, []]; } newParentNewChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentSavedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.create({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentMixedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedTag = this.db.tags.insert({ name: "Blue" }); return this.schema.tags.find(insertedTag.id); } newChild() { return this.schema.tags.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/accessor-test.js000066400000000000000000000014241412317504700312750ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [tag, tags] = helper[state](); expect(tag.labels.models).toHaveLength(tags.length); expect(tag.labelIds).toHaveLength(tags.length); tags.forEach((t) => { expect(tag.labels.includes(t)).toBeTruthy(); if (t.isSaved()) { expect(tag.labelIds.indexOf(t.id) > -1).toBeTruthy(); } // Check the inverse expect(t.labels.includes(tag)).toBeTruthy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/association-create-test.js000066400000000000000000000016721412317504700332550ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let orangeTag = tag.createLabel({ name: "Orange" }); expect(orangeTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(orangeTag)).toBeTruthy(); expect(tag.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.attrs.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(orangeTag.labels.includes(tag)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/association-new-test.js000066400000000000000000000021651412317504700326010ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let blueTag = tag.newLabel({ name: "Blue" }); expect(!blueTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(blueTag.labels.models).toHaveLength(1); blueTag.save(); expect(blueTag.attrs).toEqual({ id: blueTag.id, name: "Blue", labelIds: [tag.id], }); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(blueTag)).toBeTruthy(); expect(tag.labelIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(blueTag.labels.includes(tag)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/association-set-ids-test.js000066400000000000000000000025361412317504700333620ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.labelIds = [savedTag.id]; expect(tag.labels.models[0].attrs).toEqual(savedTag.attrs); expect(tag.labelIds).toEqual([savedTag.id]); tag.save(); savedTag.reload(); expect(savedTag.labels.models[0].attrs).toEqual(tag.attrs); originalTags.forEach((originalTag) => { if (originalTag.isSaved()) { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); } }); }); test(`a ${state} can clear its association via a null childIds`, () => { let [tag, originalTags] = helper[state](); tag.labelIds = null; expect(tag.labels.models).toBeEmpty(); expect(tag.labelIds).toBeEmpty(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/association-set-test.js000066400000000000000000000043551412317504700326060ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.labels = [savedTag]; expect(tag.labels.includes(savedTag)).toBeTruthy(); expect(tag.labelIds[0]).toEqual(savedTag.id); expect(savedTag.labels.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can update its association to a new parent`, () => { let [tag, originalTags] = helper[state](); let newTag = helper.newChild(); tag.labels = [newTag]; expect(tag.labels.includes(newTag)).toBeTruthy(); expect(tag.labelIds[0]).toBeUndefined(); expect(newTag.labels.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.labels = []; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.labels = null; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/create-test.js000066400000000000000000000054361412317504700307450ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Named Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labelIds: [tagA.id], }); tagA.reload(); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.labels.models[0].attrs).toEqual(tagB.attrs); expect(tagB.labels.models[0].attrs).toEqual(tagA.attrs); expect(helper.db.tags).toHaveLength(2); expect(helper.db.tags[0]).toEqual({ id: "1", labelIds: ["2"] }); expect(helper.db.tags[1]).toEqual({ id: "2", labelIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: [tagA], }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(helper.db.tags).toHaveLength(2); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: schema.tags.all(), }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(helper.db.tags).toHaveLength(2); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.tags.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/delete-test.js000066400000000000000000000011551412317504700307360ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [tag, labels] = helper[state](); if (labels && labels.length) { labels.forEach((t) => t.destroy()); tag.reload(); } expect(tag.labels).toHaveLength(0); expect(tag.labelIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/4-named-reflexive/new-test.js000066400000000000000000000046571412317504700302770ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labelIds: [tagA.id], }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.includes(tagA)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.tags.new({ labelIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let tag = schema.tags.new({ labelIds: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts saved children", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts new children", () => { let tagA = schema.tags.new({ color: "Red" }); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([undefined]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts null children", () => { let tag = schema.tags.new({ labels: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts children and child ids", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA], labelIds: [tagA.id] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let tag = schema.tags.new({}); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let tag = schema.tags.new(); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverse/000077500000000000000000000000001412317504700314505ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverse/_helper.js000066400000000000000000000063211412317504700334260ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { tag: Model.extend({ labels: hasMany("tag", { inverse: "labels" }), // implicit inverse }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let tag = this.db.tags.insert({ name: "Red" }); return [this.schema.tags.find(tag.id), []]; } savedParentNewChildren() { let tag = this.schema.tags.create({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2", "3"] }, { id: "2", name: "Blue", labelIds: ["1"] }, { id: "3", name: "Green", labelIds: ["1"] }, ]); return [schema.tags.find(1), [schema.tags.find(2), schema.tags.find(3)]]; } savedParentMixedChildren() { this.schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2"] }, { id: "2", name: "Blue", labelIds: ["1"] }, ]); let tag = this.schema.tags.find(1); let blueTag = this.schema.tags.find(2); let greenTag = this.schema.tags.new({ name: "Green" }); tag.labels = [blueTag, greenTag]; return [tag, [blueTag, greenTag]]; } newParentNoChildren() { let tag = this.schema.tags.new({ name: "Red" }); return [tag, []]; } newParentNewChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentSavedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.create({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentMixedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedTag = this.db.tags.insert({ name: "Blue" }); return this.schema.tags.find(insertedTag.id); } newChild() { return this.schema.tags.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; accessor-test.js000066400000000000000000000014451412317504700345120ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [tag, tags] = helper[state](); expect(tag.labels.models).toHaveLength(tags.length); expect(tag.labelIds).toHaveLength(tags.length); tags.forEach((t) => { expect(tag.labels.includes(t)).toBeTruthy(); if (t.isSaved()) { expect(tag.labelIds.indexOf(t.id) > -1).toBeTruthy(); } // Check the inverse expect(t.labels.includes(tag)).toBeTruthy(); }); }); }); }); association-create-test.js000066400000000000000000000017131412317504700364630ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let orangeTag = tag.createLabel({ name: "Orange" }); expect(orangeTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(orangeTag)).toBeTruthy(); expect(tag.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.attrs.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(orangeTag.labels.includes(tag)).toBeTruthy(); }); }); }); association-new-test.js000066400000000000000000000022061412317504700360070ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let blueTag = tag.newLabel({ name: "Blue" }); expect(!blueTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(blueTag.labels.models).toHaveLength(1); blueTag.save(); expect(blueTag.attrs).toEqual({ id: blueTag.id, name: "Blue", labelIds: [tag.id], }); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(blueTag)).toBeTruthy(); expect(tag.labelIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(blueTag.labels.includes(tag)).toBeTruthy(); }); }); }); association-set-ids-test.js000066400000000000000000000025571412317504700365770ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.labelIds = [savedTag.id]; expect(tag.labels.models[0].attrs).toEqual(savedTag.attrs); expect(tag.labelIds).toEqual([savedTag.id]); tag.save(); savedTag.reload(); expect(savedTag.labels.models[0].attrs).toEqual(tag.attrs); originalTags.forEach((originalTag) => { if (originalTag.isSaved()) { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); } }); }); test(`a ${state} can clear its association via a null childIds`, () => { let [tag, originalTags] = helper[state](); tag.labelIds = null; expect(tag.labels.models).toBeEmpty(); expect(tag.labelIds).toBeEmpty(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); }); }); association-set-test.js000066400000000000000000000043761412317504700360230ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [tag, originalTags] = helper[state](); let savedTag = helper.savedChild(); tag.labels = [savedTag]; expect(tag.labels.includes(savedTag)).toBeTruthy(); expect(tag.labelIds[0]).toEqual(savedTag.id); expect(savedTag.labels.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can update its association to a new parent`, () => { let [tag, originalTags] = helper[state](); let newTag = helper.newChild(); tag.labels = [newTag]; expect(tag.labels.includes(newTag)).toBeTruthy(); expect(tag.labelIds[0]).toBeUndefined(); expect(newTag.labels.includes(tag)).toBeTruthy(); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.labels = []; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag, originalTags] = helper[state](); tag.labels = null; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); originalTags.forEach((originalTag) => { originalTag.reload(); expect(originalTag.labels.includes(tag)).toBeFalsy(); }); }); }); }); create-test.js000066400000000000000000000054571412317504700341620ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labelIds: [tagA.id], }); tagA.reload(); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.labels.models[0].attrs).toEqual(tagB.attrs); expect(tagB.labels.models[0].attrs).toEqual(tagA.attrs); expect(helper.db.tags).toHaveLength(2); expect(helper.db.tags[0]).toEqual({ id: "1", labelIds: ["2"] }); expect(helper.db.tags[1]).toEqual({ id: "2", labelIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: [tagA], }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(helper.db.tags).toHaveLength(2); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: schema.tags.all(), }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toEqual([tagB.id]); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toEqual([tagB.id]); expect(helper.db.tags).toHaveLength(2); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.tags.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); delete-test.js000066400000000000000000000011761412317504700341530ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [tag, labels] = helper[state](); if (labels && labels.length) { labels.forEach((t) => t.destroy()); tag.reload(); } expect(tag.labels).toHaveLength(0); expect(tag.labelIds).toHaveLength(0); }); }); }); new-test.js000066400000000000000000000047001412317504700334760ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/5-named-reflexive-explicit-inverseimport Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Named Reflexive Explicit Inverse | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labelIds: [tagA.id], }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.includes(tagA)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.tags.new({ labelIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let tag = schema.tags.new({ labelIds: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts saved children", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts new children", () => { let tagA = schema.tags.new({ color: "Red" }); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([undefined]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts null children", () => { let tag = schema.tags.new({ labels: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts children and child ids", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA], labelIds: [tagA.id] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let tag = schema.tags.new({}); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let tag = schema.tags.new(); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/000077500000000000000000000000001412317504700264545ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/_helper.js000066400000000000000000000062321412317504700304330ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { tag: Model.extend({ tags: hasMany("tag", { inverse: null }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let tag = this.db.tags.insert({ name: "Red" }); return [this.schema.tags.find(tag.id), []]; } savedParentNewChildren() { let tag = this.schema.tags.create({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.tags.insert([ { id: "1", name: "Red", tagIds: ["2", "3"] }, { id: "2", name: "Blue", tagIds: [] }, { id: "3", name: "Green", tagIds: [] }, ]); return [schema.tags.find(1), [schema.tags.find(2), schema.tags.find(3)]]; } savedParentMixedChildren() { this.schema.db.tags.insert([ { id: "1", name: "Red", tagIds: ["2"] }, { id: "2", name: "Blue", tagIds: [] }, ]); let tag = this.schema.tags.find(1); let blueTag = this.schema.tags.find(2); let greenTag = this.schema.tags.new({ name: "Green" }); tag.tags = [blueTag, greenTag]; return [tag, [blueTag, greenTag]]; } newParentNoChildren() { let tag = this.schema.tags.new({ name: "Red" }); return [tag, []]; } newParentNewChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentSavedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.create({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentMixedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.tags = [tag1, tag2]; return [tag, [tag1, tag2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedTag = this.db.tags.insert({ name: "Blue" }); return this.schema.tags.find(insertedTag.id); } newChild() { return this.schema.tags.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/accessor-test.js000066400000000000000000000012731412317504700315740ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [tag, tags] = helper[state](); expect(tag.tags.models).toHaveLength(tags.length); expect(tag.tagIds).toHaveLength(tags.length); tags.forEach((t) => { expect(tag.tags.includes(t)).toBeTruthy(); if (t.isSaved()) { expect(tag.tagIds.indexOf(t.id) > -1).toBeTruthy(); } }); }); }); }); association-create-test.js000066400000000000000000000016551412317504700334740ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [tag] = helper[state](); let initialCount = tag.tags.models.length; let orangeTag = tag.createTag({ name: "Orange" }); expect(orangeTag.id).toBeTruthy(); expect(tag.tags.models).toHaveLength(initialCount + 1); expect(tag.tags.includes(orangeTag)).toBeTruthy(); expect(tag.tagIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.attrs.tagIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(orangeTag.tags.includes(tag)).toBeFalsy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/association-new-test.js000066400000000000000000000021361412317504700330740ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [tag] = helper[state](); let initialCount = tag.tags.models.length; let blueTag = tag.newTag({ name: "Blue" }); expect(!blueTag.id).toBeTruthy(); expect(tag.tags.models).toHaveLength(initialCount + 1); expect(blueTag.tags.models).toHaveLength(0); blueTag.save(); expect(blueTag.attrs).toEqual({ id: blueTag.id, name: "Blue", tagIds: [], }); expect(tag.tags.models).toHaveLength(initialCount + 1); expect(tag.tags.includes(blueTag)).toBeTruthy(); expect(tag.tagIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(blueTag.tags.includes(tag)).toBeFalsy(); }); }); }); association-set-ids-test.js000066400000000000000000000017171412317504700336000ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [tag] = helper[state](); let savedTag = helper.savedChild(); tag.tagIds = [savedTag.id]; expect(tag.tags.models[0].attrs).toEqual(savedTag.attrs); expect(tag.tagIds).toEqual([savedTag.id]); tag.save(); savedTag.reload(); expect(savedTag.tags.models).toHaveLength(0); }); test(`a ${state} can clear its association via a null childIds`, () => { let [tag] = helper[state](); tag.tagIds = null; expect(tag.tags.models).toBeEmpty(); expect(tag.tagIds).toBeEmpty(); tag.save(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/association-set-test.js000066400000000000000000000031071412317504700330750ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [tag] = helper[state](); let savedTag = helper.savedChild(); tag.tags = [savedTag]; expect(tag.tags.includes(savedTag)).toBeTruthy(); expect(tag.tagIds[0]).toEqual(savedTag.id); expect(savedTag.tags.includes(tag)).toBeFalsy(); tag.save(); }); test(`a ${state} can update its association to a new parent`, () => { let [tag] = helper[state](); let newTag = helper.newChild(); tag.tags = [newTag]; expect(tag.tags.includes(newTag)).toBeTruthy(); expect(tag.tagIds[0]).toBeUndefined(); expect(newTag.tags.includes(tag)).toBeFalsy(); tag.save(); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag] = helper[state](); tag.tags = []; expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toHaveLength(0); tag.save(); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag] = helper[state](); tag.tags = null; expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toHaveLength(0); tag.save(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/create-test.js000066400000000000000000000051471412317504700312410ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tagIds: [tagA.id], }); tagA.reload(); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.tagIds).toBeEmpty(); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(tagB.tags.models[0].attrs).toEqual(tagA.attrs); expect(helper.db.tags).toHaveLength(2); expect(helper.db.tags[0]).toEqual({ id: "1", tagIds: null }); expect(helper.db.tags[1]).toEqual({ id: "2", tagIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tags: [tagA], }); tagA.reload(); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.tagIds).toBeEmpty(); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(tagA.attrs.tagIds).toBeNull(); expect(helper.db.tags).toHaveLength(2); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ tags: schema.tags.all(), }); tagA.reload(); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagA.tagIds).toBeEmpty(); expect(tagB.attrs.tagIds).toEqual([tagA.id]); expect(tagA.attrs.tagIds).toBeNull(); expect(helper.db.tags).toHaveLength(2); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.tags.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/delete-test.js000066400000000000000000000011431412317504700312300ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [tag, tags] = helper[state](); if (tags && tags.length) { tags.forEach((t) => t.destroy()); tag.reload(); } expect(tag.tags).toHaveLength(0); expect(tag.tagIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/6-one-way-reflexive/new-test.js000066400000000000000000000045711412317504700305670ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | One-Way Reflexive | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tagIds: [tagA.id], }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.includes(tagA)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.tags.new({ tagIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let tag = schema.tags.new({ tagIds: null }); expect(tag.tags.models).toHaveLength(0); expect(tag.tagIds).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts saved children", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tags: [tagA] }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts new children", () => { let tagA = schema.tags.new({ color: "Red" }); let tagB = schema.tags.new({ tags: [tagA] }); expect(tagB.tagIds).toEqual([undefined]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts null children", () => { let tag = schema.tags.new({ tags: null }); expect(tag.tags.models).toHaveLength(0); expect(tag.tagIds).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts children and child ids", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ tags: [tagA], tagIds: [tagA.id] }); expect(tagB.tagIds).toEqual([tagA.id]); expect(tagB.tags.models[0]).toEqual(tagA); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let tag = schema.tags.new({}); expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let tag = schema.tags.new(); expect(tag.tagIds).toBeEmpty(); expect(tag.tags.models).toBeEmpty(); expect(tag.attrs).toEqual({ tagIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/000077500000000000000000000000001412317504700275375ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/_helper.js000066400000000000000000000062601412317504700315170ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { tag: Model.extend({ labels: hasMany("tag", { inverse: null }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let tag = this.db.tags.insert({ name: "Red" }); return [this.schema.tags.find(tag.id), []]; } savedParentNewChildren() { let tag = this.schema.tags.create({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2", "3"] }, { id: "2", name: "Blue", labelIds: [] }, { id: "3", name: "Green", labelIds: [] }, ]); return [schema.tags.find(1), [schema.tags.find(2), schema.tags.find(3)]]; } savedParentMixedChildren() { this.schema.db.tags.insert([ { id: "1", name: "Red", labelIds: ["2"] }, { id: "2", name: "Blue", labelIds: [] }, ]); let tag = this.schema.tags.find(1); let blueTag = this.schema.tags.find(2); let greenTag = this.schema.tags.new({ name: "Green" }); tag.labels = [blueTag, greenTag]; return [tag, [blueTag, greenTag]]; } newParentNoChildren() { let tag = this.schema.tags.new({ name: "Red" }); return [tag, []]; } newParentNewChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.new({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentSavedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.create({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } newParentMixedChildren() { let tag = this.schema.tags.new({ name: "Red" }); let tag1 = this.schema.tags.create({ name: "Blue" }); let tag2 = this.schema.tags.new({ name: "Green" }); tag.labels = [tag1, tag2]; return [tag, [tag1, tag2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedTag = this.db.tags.insert({ name: "Blue" }); return this.schema.tags.find(insertedTag.id); } newChild() { return this.schema.tags.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/accessor-test.js000066400000000000000000000013111412317504700326500ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [tag, tags] = helper[state](); expect(tag.labels.models).toHaveLength(tags.length); expect(tag.labelIds).toHaveLength(tags.length); tags.forEach((t) => { expect(tag.labels.includes(t)).toBeTruthy(); if (t.isSaved()) { expect(tag.labelIds.indexOf(t.id) > -1).toBeTruthy(); } }); }); }); }); association-create-test.js000066400000000000000000000017011412317504700345470ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let orangeTag = tag.createLabel({ name: "Orange" }); expect(orangeTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(orangeTag)).toBeTruthy(); expect(tag.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(tag.attrs.labelIds.indexOf(orangeTag.id) > -1).toBeTruthy(); expect(orangeTag.labels.includes(tag)).toBeFalsy(); }); }); }); association-new-test.js000066400000000000000000000021661412317504700341030ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [tag] = helper[state](); let initialCount = tag.labels.models.length; let blueTag = tag.newLabel({ name: "Blue" }); expect(!blueTag.id).toBeTruthy(); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(blueTag.labels.models).toHaveLength(0); blueTag.save(); expect(blueTag.attrs).toEqual({ id: blueTag.id, name: "Blue", labelIds: [], }); expect(tag.labels.models).toHaveLength(initialCount + 1); expect(tag.labels.includes(blueTag)).toBeTruthy(); expect(tag.labelIds.indexOf(blueTag.id) > -1).toBeTruthy(); expect(blueTag.labels.includes(tag)).toBeFalsy(); }); }); }); association-set-ids-test.js000066400000000000000000000017431412317504700346620ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [tag] = helper[state](); let savedTag = helper.savedChild(); tag.labelIds = [savedTag.id]; expect(tag.labels.models[0].attrs).toEqual(savedTag.attrs); expect(tag.labelIds).toEqual([savedTag.id]); tag.save(); savedTag.reload(); expect(savedTag.labels.models).toHaveLength(0); }); test(`a ${state} can clear its association via a null childIds`, () => { let [tag] = helper[state](); tag.labelIds = null; expect(tag.labels.models).toBeEmpty(); expect(tag.labelIds).toBeEmpty(); tag.save(); }); }); }); association-set-test.js000066400000000000000000000031511412317504700341000ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexiveimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [tag] = helper[state](); let savedTag = helper.savedChild(); tag.labels = [savedTag]; expect(tag.labels.includes(savedTag)).toBeTruthy(); expect(tag.labelIds[0]).toEqual(savedTag.id); expect(savedTag.labels.includes(tag)).toBeFalsy(); tag.save(); }); test(`a ${state} can update its association to a new parent`, () => { let [tag] = helper[state](); let newTag = helper.newChild(); tag.labels = [newTag]; expect(tag.labels.includes(newTag)).toBeTruthy(); expect(tag.labelIds[0]).toBeUndefined(); expect(newTag.labels.includes(tag)).toBeFalsy(); tag.save(); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag] = helper[state](); tag.labels = []; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); }); test(`a ${state} can clear its association via an empty list`, () => { let [tag] = helper[state](); tag.labels = null; expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toHaveLength(0); tag.save(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/create-test.js000066400000000000000000000052171412317504700323220ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labelIds: [tagA.id], }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toBeEmpty(); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0].attrs).toEqual(tagA.attrs); expect(helper.db.tags).toHaveLength(2); expect(helper.db.tags[0]).toEqual({ id: "1", labelIds: null }); expect(helper.db.tags[1]).toEqual({ id: "2", labelIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: [tagA], }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toBeEmpty(); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toBeNull(); expect(helper.db.tags).toHaveLength(2); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let tagA = schema.tags.create(); let tagB = schema.tags.create({ labels: schema.tags.all(), }); tagA.reload(); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagA.labelIds).toBeEmpty(); expect(tagB.attrs.labelIds).toEqual([tagA.id]); expect(tagA.attrs.labelIds).toBeNull(); expect(helper.db.tags).toHaveLength(2); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.tags.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.tags.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/delete-test.js000066400000000000000000000011651412317504700323170ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [tag, labels] = helper[state](); if (labels && labels.length) { labels.forEach((t) => t.destroy()); tag.reload(); } expect(tag.labels).toHaveLength(0); expect(tag.labelIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/7-named-one-way-reflexive/new-test.js000066400000000000000000000046671412317504700316600ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Named One-Way Reflexive | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labelIds: [tagA.id], }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.includes(tagA)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.tags.new({ labelIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let tag = schema.tags.new({ labelIds: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts saved children", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts new children", () => { let tagA = schema.tags.new({ color: "Red" }); let tagB = schema.tags.new({ labels: [tagA] }); expect(tagB.labelIds).toEqual([undefined]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts null children", () => { let tag = schema.tags.new({ labels: null }); expect(tag.labels.models).toHaveLength(0); expect(tag.labelIds).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts children and child ids", () => { let tagA = helper.savedChild(); let tagB = schema.tags.new({ labels: [tagA], labelIds: [tagA.id] }); expect(tagB.labelIds).toEqual([tagA.id]); expect(tagB.labels.models[0]).toEqual(tagA); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let tag = schema.tags.new({}); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let tag = schema.tags.new(); expect(tag.labelIds).toBeEmpty(); expect(tag.labels.models).toBeEmpty(); expect(tag.attrs).toEqual({ labelIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/000077500000000000000000000000001412317504700254365ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/_helper.js000066400000000000000000000071051412317504700274150ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { // implicit inverse this.server = new Server({ environment: "test", models: { order: Model.extend({ products: hasMany(), }), product: Model.extend({ orders: hasMany(), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let order = this.db.orders.insert({ name: "Red" }); return [this.schema.orders.find(order.id), []]; } savedParentNewChildren() { let order = this.schema.orders.create({ name: "Red" }); let product1 = this.schema.products.new({ name: "Blue" }); let product2 = this.schema.products.new({ name: "Green" }); order.products = [product1, product2]; return [order, [product1, product2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.orders.insert([{ id: "1", name: "Red", productIds: ["2", "3"] }]); schema.db.products.insert([ { id: "2", name: "Blue", orderIds: ["1"] }, { id: "3", name: "Green", orderIds: ["1"] }, ]); return [ schema.orders.find(1), [schema.products.find(2), schema.products.find(3)], ]; } savedParentMixedChildren() { this.schema.db.orders.insert([{ id: "1", name: "Red", productIds: ["2"] }]); this.schema.db.products.insert([ { id: "2", name: "Blue", orderIds: ["1"] }, ]); let order = this.schema.orders.find(1); let product1 = this.schema.products.find(2); let product2 = this.schema.products.new({ name: "Green" }); order.products = [product1, product2]; return [order, [product1, product2]]; } newParentNoChildren() { let order = this.schema.orders.new({ name: "Red" }); return [order, []]; } newParentNewChildren() { let order = this.schema.orders.new({ name: "Red" }); let product1 = this.schema.products.new({ name: "Blue" }); let product2 = this.schema.products.new({ name: "Green" }); order.products = [product1, product2]; return [order, [product1, product2]]; } newParentSavedChildren() { let order = this.schema.orders.new({ name: "Red" }); let product1 = this.schema.products.create({ name: "Blue" }); let product2 = this.schema.products.create({ name: "Green" }); order.products = [product1, product2]; return [order, [product1, product2]]; } newParentMixedChildren() { let order = this.schema.orders.new({ name: "Red" }); let product1 = this.schema.products.create({ name: "Blue" }); let product2 = this.schema.products.new({ name: "Green" }); order.products = [product1, product2]; return [order, [product1, product2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedProduct = this.db.products.insert({ name: "Blue" }); return this.schema.products.find(insertedProduct.id); } newChild() { return this.schema.products.new({ name: "Blue" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentMixedChildren", "savedParentSavedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/accessor-test.js000066400000000000000000000014651412317504700305610ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [order, products] = helper[state](); expect(order.products.models).toHaveLength(products.length); expect(order.productIds).toHaveLength(products.length); products.forEach((p) => { expect(order.products.includes(p)).toBeTruthy(); if (p.isSaved()) { expect(order.productIds.indexOf(p.id) > -1).toBeTruthy(); } // Check the inverse expect(p.orders.includes(order)).toBeTruthy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/association-create-test.js000066400000000000000000000017731412317504700325360ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated child`, () => { let [order] = helper[state](); let initialCount = order.products.models.length; let orangeProduct = order.createProduct({ name: "Orange" }); expect(orangeProduct.id).toBeTruthy(); expect(order.products.models).toHaveLength(initialCount + 1); expect(order.products.includes(orangeProduct)).toBeTruthy(); expect(order.productIds.indexOf(orangeProduct.id) > -1).toBeTruthy(); expect( order.attrs.productIds.indexOf(orangeProduct.id) > -1 ).toBeTruthy(); expect(orangeProduct.orders.includes(order)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/association-new-test.js000066400000000000000000000022641412317504700320600ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated child`, () => { let [order] = helper[state](); let initialCount = order.products.models.length; let blueProduct = order.newProduct({ name: "Blue" }); expect(!blueProduct.id).toBeTruthy(); expect(order.products.models).toHaveLength(initialCount + 1); expect(blueProduct.orders.models).toHaveLength(1); blueProduct.save(); expect(blueProduct.attrs).toEqual({ id: blueProduct.id, name: "Blue", orderIds: [order.id], }); expect(order.products.models).toHaveLength(initialCount + 1); expect(order.products.includes(blueProduct)).toBeTruthy(); expect(order.productIds.indexOf(blueProduct.id) > -1).toBeTruthy(); expect(blueProduct.orders.includes(order)).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/association-set-ids-test.js000066400000000000000000000025441412317504700326400ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`a ${state} can update its association to include a saved child via childIds`, () => { let [order, originalProducts] = helper[state](); let savedProduct = helper.savedChild(); order.productIds = [savedProduct.id]; expect(order.products.models[0].attrs).toEqual(savedProduct.attrs); expect(order.productIds).toEqual([savedProduct.id]); order.save(); savedProduct.reload(); expect(savedProduct.orders.models[0].attrs).toEqual(order.attrs); originalProducts.forEach((p) => { if (p.isSaved()) { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); } }); }); test(`a ${state} can clear its association via a null childIds`, () => { let [order, originalProducts] = helper[state](); order.productIds = null; expect(order.products.models).toBeEmpty(); expect(order.productIds).toBeEmpty(); order.save(); originalProducts.forEach((p) => { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/association-set-test.js000066400000000000000000000044031412317504700320570ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [order, originalProducts] = helper[state](); let savedProduct = helper.savedChild(); order.products = [savedProduct]; expect(order.products.includes(savedProduct)).toBeTruthy(); expect(order.productIds[0]).toEqual(savedProduct.id); expect(savedProduct.orders.includes(order)).toBeTruthy(); order.save(); originalProducts.forEach((p) => { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); }); }); test(`a ${state} can update its association to a new parent`, () => { let [order, originalProducts] = helper[state](); let newProduct = helper.newChild(); order.products = [newProduct]; expect(order.products.includes(newProduct)).toBeTruthy(); expect(order.productIds[0]).toBeUndefined(); expect(newProduct.orders.includes(order)).toBeTruthy(); order.save(); originalProducts.forEach((p) => { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [order, originalProducts] = helper[state](); order.products = []; expect(order.productIds).toBeEmpty(); expect(order.products.models).toHaveLength(0); order.save(); originalProducts.forEach((p) => { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); }); }); test(`a ${state} can clear its association via an empty list`, () => { let [order, originalProducts] = helper[state](); order.products = null; expect(order.productIds).toBeEmpty(); expect(order.products.models).toHaveLength(0); order.save(); originalProducts.forEach((p) => { p.reload(); expect(p.orders.includes(order)).toBeFalsy(); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/create-test.js000066400000000000000000000060741412317504700302230ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | Many to Many | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let product = schema.products.create(); let order = schema.orders.create({ productIds: [product.id], }); product.reload(); expect(order.productIds).toEqual([product.id]); expect(product.orderIds).toEqual([order.id]); expect(order.attrs.productIds).toEqual([product.id]); expect(product.attrs.orderIds).toEqual([order.id]); expect(order.products.models[0].attrs).toEqual(product.attrs); expect(product.orders.models[0].attrs).toEqual(order.attrs); expect(helper.db.orders).toHaveLength(1); expect(helper.db.products).toHaveLength(1); expect(helper.db.orders[0]).toEqual({ id: "1", productIds: ["1"] }); expect(helper.db.products[0]).toEqual({ id: "1", orderIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let { schema } = helper; let product = schema.products.create(); let order = schema.orders.create({ products: [product], }); product.reload(); expect(order.productIds).toEqual([product.id]); expect(product.orderIds).toEqual([order.id]); expect(order.attrs.productIds).toEqual([product.id]); expect(product.attrs.orderIds).toEqual([order.id]); expect(helper.db.orders).toHaveLength(1); expect(helper.db.products).toHaveLength(1); }); test("it sets up associations correctly when passing in a collection", () => { let { schema } = helper; let product = schema.products.create(); let order = schema.orders.create({ products: schema.products.all(), }); product.reload(); expect(order.productIds).toEqual([product.id]); expect(product.orderIds).toEqual([order.id]); expect(order.attrs.productIds).toEqual([product.id]); expect(product.attrs.orderIds).toEqual([order.id]); expect(helper.db.orders).toHaveLength(1); expect(helper.db.products).toHaveLength(1); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.orders.create({ foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.orders.create({ foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.foos.create(); schema.foos.create(); expect(function () { schema.orders.create({ foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/delete-test.js000066400000000000000000000011761412317504700302200ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [order, products] = helper[state](); if (products && products.length) { products.forEach((t) => t.destroy()); order.reload(); } expect(order.products).toHaveLength(0); expect(order.productIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/8-many-to-many/new-test.js000066400000000000000000000051471412317504700275510ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | Many to Many | new", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let product = helper.savedChild(); let order = schema.orders.new({ productIds: [product.id], }); expect(order.productIds).toEqual([product.id]); expect(order.products.includes(product)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.orders.new({ productIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let order = schema.orders.new({ productIds: null }); expect(order.products.models).toHaveLength(0); expect(order.productIds).toBeEmpty(); expect(order.attrs).toEqual({ productIds: null }); }); test("the parent accepts saved children", () => { let product = helper.savedChild(); let order = schema.orders.new({ products: [product] }); expect(order.productIds).toEqual([product.id]); expect(order.products.models[0]).toEqual(product); }); test("the parent accepts new children", () => { let product = schema.products.new({ color: "Red" }); let order = schema.orders.new({ products: [product] }); expect(order.productIds).toEqual([undefined]); expect(order.products.models[0]).toEqual(product); }); test("the parent accepts null children", () => { let order = schema.orders.new({ products: null }); expect(order.products.models).toHaveLength(0); expect(order.productIds).toBeEmpty(); expect(order.attrs).toEqual({ productIds: null }); }); test("the parent accepts children and child ids", () => { let product = helper.savedChild(); let order = schema.orders.new({ products: [product], productIds: [product.id], }); expect(order.productIds).toEqual([product.id]); expect(order.products.models[0]).toEqual(product); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let order = schema.orders.new({}); expect(order.productIds).toBeEmpty(); expect(order.products.models).toBeEmpty(); expect(order.attrs).toEqual({ productIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let order = schema.orders.new(); expect(order.productIds).toBeEmpty(); expect(order.products.models).toBeEmpty(); expect(order.attrs).toEqual({ productIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/000077500000000000000000000000001412317504700270335ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/_helper.js000066400000000000000000000062351412317504700310150ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ things: hasMany("thing", { polymorphic: true }), }), post: Model, }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.things = [post1, post2]; user.save(); return [user, [post1, post2]]; } savedParentMixedChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/accessor-test.js000066400000000000000000000014671412317504700321600ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.things.models).toHaveLength(posts.length); expect(user.thingIds).toHaveLength(posts.length); posts.forEach((post, i) => { expect(user.things.includes(post)).toBeTruthy(); if (post.isSaved()) { expect(user.thingIds[i]).toEqual({ type: "post", id: post.id }); } }); }); }); }); association-create-test.js000066400000000000000000000020421412317504700340420ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.things.models.length; let post = user.createThing("post", { title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.things.models).toHaveLength(initialCount + 1); expect(user.things.includes(post)).toBeTruthy(); expect( user.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); expect( user.attrs.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/association-new-test.js000066400000000000000000000020641412317504700334530ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.things.models.length; let post = user.newThing("post", { title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.things.models).toHaveLength(initialCount + 1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum" }); expect(user.things.models).toHaveLength(initialCount + 1); expect(user.things.includes(post)).toBeTruthy(); expect( user.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); }); }); }); association-set-ids-test.js000066400000000000000000000020441412317504700341510ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.thingIds = [{ type: "post", id: savedPost.id }]; expect(user.things.includes(savedPost)).toBeTruthy(); expect( user.thingIds.find( ({ id, type }) => id === savedPost.id && type === "post" ) ).toBeTruthy(); }); test(`a ${state} can clear its association via a null parentId`, () => { let [user] = helper[state](); user.thingIds = null; expect(user.things.models).toBeEmpty(); expect(user.thingIds).toBeEmpty(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/association-set-test.js000066400000000000000000000030511412317504700334520ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user] = helper[state](); let savedPost = helper.savedChild(); user.things = [savedPost]; expect(user.things.models.includes(savedPost)).toBeTruthy(); expect( user.thingIds.find( ({ id, type }) => id === savedPost.id && type === "post" ) ).toBeTruthy(); }); test(`a ${state} can update its association to a new parent`, () => { let [user] = helper[state](); let newPost = helper.newChild(); user.things = [newPost]; expect(user.thingIds).toEqual([{ type: "post", id: undefined }]); expect(user.things.models[0]).toEqual(newPost); }); test(`a ${state} can clear its association via an empty list`, () => { let [user] = helper[state](); user.things = []; expect(user.thingIds).toBeEmpty(); expect(user.things.models).toHaveLength(0); }); test(`a ${state} can clear its association via null`, () => { let [user] = helper[state](); user.things = null; expect(user.thingIds).toBeEmpty(); expect(user.things.models).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/create-test.js000066400000000000000000000061351412317504700316160ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { thingIds: [{ type: "post", id: post.id }], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.models[0].attrs).toEqual(post.attrs); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { things: [post], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { things: helper.schema.posts.all(), }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); expect(helper.db.posts).toHaveLength(1); expect(helper.db.posts[0]).toEqual({ id: "1" }); expect(helper.db.users).toHaveLength(1); expect(helper.db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("user", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/delete-test.js000066400000000000000000000011611412317504700316070ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [user, posts] = helper[state](); if (posts && posts.length) { posts.forEach((p) => p.destroy()); user.reload(); } expect(user.things).toHaveLength(0); expect(user.thingIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/9-one-way-polymorphic/instantiating-test.js000066400000000000000000000052201412317504700332210ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Has Many | One-way Polymorphic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ thingIds: [{ type: "post", id: post.id }], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ thingIds: [{ type: "post", id: 2 }] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ thingIds: null }); expect(user.things.models).toHaveLength(0); expect(user.thingIds).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ things: [post] }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ things: [post] }); expect(user.thingIds).toEqual([{ type: "post", id: undefined }]); expect(user.things.includes(post)).toBeTruthy(); }); test("the parent accepts null children", () => { let user = schema.users.new({ things: null }); expect(user.things.models).toHaveLength(0); expect(user.thingIds).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ things: [post], thingIds: [{ type: "post", id: post.id }], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.thingIds).toBeEmpty(); expect(user.things.models).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.thingIds).toBeEmpty(); expect(user.things.models).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/has-many/regressions/000077500000000000000000000000001412317504700253065ustar00rootroot00000000000000many-to-many-inverse-set-bug-test.js000066400000000000000000000016511412317504700341100ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/has-many/regressionsimport { Server, Model, hasMany } from "miragejs"; describe("External | Shared | ORM | Has Many | Regressions | Many to many inverse set bug", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { post: Model.extend({ tags: hasMany(), }), tag: Model.extend({ posts: hasMany(), }), }, }); }); test(`it works`, () => { server.db.loadData({ posts: [ { id: "1", tagIds: ["15", "16"] }, { id: "2", tagIds: ["16"] }, ], tags: [ { id: "15", postIds: ["1"] }, { id: "16", postIds: ["1", "2"] }, ], }); server.schema.posts.find(1).update({ tagIds: ["15"] }); expect(server.db.posts.find(1).tagIds).toEqual(["15"]); expect(server.db.tags.find(15).postIds).toEqual(["1"]); expect(server.db.tags.find(16).postIds).toEqual(["2"]); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/000077500000000000000000000000001412317504700223345ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/000077500000000000000000000000001412317504700246355ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/_helper.js000066400000000000000000000065431412317504700266210ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ posts: hasMany(), }), post: Model.extend({ user: belongsTo(), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.loadData({ users: [{ id: "1", name: "Link", postIds: ["1", "2"] }], posts: [ { id: "1", title: "Lorem", userId: "1" }, { id: "2", title: "Ipsum", userId: "1" }, ], }); return [schema.users.find(1), [schema.posts.find(1), schema.posts.find(2)]]; } savedParentMixedChildren() { this.schema.db.loadData({ users: [{ id: "1", name: "Link", postIds: ["1"] }], posts: [{ id: "1", title: "Lorem", userId: "1" }], }); let user = this.schema.users.find(1); let post1 = this.schema.posts.find(1); let post2 = this.schema.posts.new({ name: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.posts = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/accessor-test.js000066400000000000000000000016371412317504700277610ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.posts.models).toHaveLength(posts.length); expect(user.postIds).toHaveLength(posts.length); posts.forEach((post) => { expect(user.posts.includes(post)).toBeTruthy(); if (post.isSaved()) { expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); } // Check the inverse expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/association-create-test.js000066400000000000000000000017421412317504700317310ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.posts.models.length; let post = user.createPost({ title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.posts.models).toHaveLength(initialCount + 1); expect(user.posts.includes(post)).toBeTruthy(); expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); expect(user.attrs.postIds.indexOf(post.id) > -1).toBeTruthy(); // Check the inverse expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/association-new-test.js000066400000000000000000000017721412317504700312620ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.posts.models.length; let post = user.newPost({ title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.posts.models).toHaveLength(initialCount + 1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum", userId: user.id, }); expect(user.posts.models).toHaveLength(initialCount + 1); expect(user.posts.includes(post)).toBeTruthy(); expect(user.postIds.indexOf(post.id) > -1).toBeTruthy(); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/association-set-ids-test.js000066400000000000000000000027761412317504700320460ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.postIds = [savedPost.id]; expect(user.posts.includes(savedPost)).toBeTruthy(); expect(user.postIds).toEqual([savedPost.id]); user.save(); savedPost.reload(); // Check the inverse expect(savedPost.user.attrs).toEqual(user.attrs); expect(savedPost.userId).toEqual(user.id); // Check old associates originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via a null parentId`, () => { let [user, originalPosts] = helper[state](); user.postIds = null; expect(user.posts.models).toBeEmpty(); expect(user.postIds).toBeEmpty(); user.save(); // Check old associates originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/association-set-test.js000066400000000000000000000042661412317504700312650ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.posts = [savedPost]; expect(user.posts.includes(savedPost)).toBeTruthy(); expect(user.postIds.indexOf(savedPost.id) > -1).toBeTruthy(); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can update its association to a new parent`, () => { let [user, originalPosts] = helper[state](); let newPost = helper.newChild(); user.posts = [newPost]; expect(user.postIds).toEqual([undefined]); expect(user.posts.includes(newPost)).toBeTruthy(); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via an empty list`, () => { let [user, originalPosts] = helper[state](); user.posts = []; expect(user.postIds).toBeEmpty(); expect(user.posts.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via an empty list`, () => { let [user, originalPosts] = helper[state](); user.posts = null; expect(user.postIds).toBeEmpty(); expect(user.posts.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/create-test.js000066400000000000000000000057251412317504700274240ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Mixed | One To Many | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { postIds: [post.id], }); post.reload(); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.includes(post)).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { posts: [post], }); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.includes(post)).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { posts: helper.schema.posts.all(), }); post.reload(); expect(user.postIds).toEqual([post.id]); expect(user.attrs.postIds).toEqual([post.id]); expect(user.posts.includes(post)).toBeTruthy(); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if an array of models is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("user", { foos: [schema.create("foo")], }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/1-one-to-many/instantiating-test.js000066400000000000000000000046621412317504700310340ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ postIds: [post.id], }); expect(user.postIds).toEqual([post.id]); expect(user.posts.includes(post)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ postIds: [2] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ postIds: null }); expect(user.posts.models).toHaveLength(0); expect(user.postIds).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ posts: [post] }); expect(user.postIds).toEqual([post.id]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ posts: [post] }); expect(user.postIds).toEqual([undefined]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts null children", () => { let user = schema.users.new({ posts: null }); expect(user.posts.models).toHaveLength(0); expect(user.postIds).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ posts: [post], postIds: [post.id] }); expect(user.postIds).toEqual([post.id]); expect(user.posts.models[0]).toEqual(post); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.postIds).toBeEmpty(); expect(user.posts.models).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.postIds).toBeEmpty(); expect(user.posts.models).toBeEmpty(); expect(user.attrs).toEqual({ postIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/000077500000000000000000000000001412317504700246365ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/_helper.js000066400000000000000000000043541412317504700266200ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ posts: hasMany(), }), post: Model.extend({ user: belongsTo(), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedChildNoParent() { let post = this.db.posts.insert({ title: "Lorem" }); return [this.schema.posts.find(post.id), null]; } savedChildNewParent() { let post = this.schema.posts.create({ title: "Lorem" }); let user = this.schema.users.new({ name: "Link" }); post.user = user; return [post, user]; } savedChildSavedParent() { let { schema } = this; schema.db.loadData({ posts: [{ id: "1", title: "Lorem", userId: "1" }], users: [{ id: "1", name: "Link", postIds: ["1"] }], }); return [schema.posts.find(1), schema.users.find(1)]; } newChildNoParent() { let post = this.schema.posts.new({ title: "Lorem" }); return [post, null]; } newChildNewParent() { let post = this.schema.posts.new({ title: "Lorem" }); let user = this.schema.users.new({ name: "Link" }); post.user = user; return [post, user]; } newChildSavedParent() { let post = this.schema.posts.create({ title: "Lorem" }); let user = this.schema.users.new({ name: "Link" }); post.user = user; return [post, user]; } // Unassociated models savedParent() { let insertedUser = this.db.users.insert({ name: "Link" }); return this.schema.users.find(insertedUser.id); } newParent() { return this.schema.users.new({ name: "Link" }); } } export const states = [ "savedChildNoParent", "savedChildNewParent", "savedChildSavedParent", "newChildNoParent", "newChildNewParent", "newChildSavedParent", ]; miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/accessor-test.js000066400000000000000000000015521412317504700277560ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | Many To One | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [post, user] = helper[state](); if (post.user) { expect(post.user.equals(user)).toBeTruthy(); } else { expect(post.user).toBeNull(); expect(user).toBeNull(); } expect(post.userId).toEqual(user ? user.id : null); post.save(); // Check the inverse if (user && user.isSaved()) { user.reload(); expect(user.posts.includes(post)).toBeTruthy(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/association-create-test.js000066400000000000000000000016651412317504700317360ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | Many To One | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [post, originalUser] = helper[state](); let user = post.createUser({ name: "Zelda" }); expect(user.id).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); // Check the inverse expect(user.posts.includes(post)).toBeTruthy(); // Ensure old inverse was cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/association-new-test.js000066400000000000000000000021521412317504700312540ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | Many To One | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [post, originalUser] = helper[state](); let user = post.newUser({ name: "Zelda" }); expect(!user.id).toBeTruthy(); expect(post.user).toEqual(user); expect(user.posts.includes(post)).toBeTruthy(); user.save(); post.reload(); expect(user.id).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); // Check the inverse expect(user.posts.includes(post)).toBeTruthy(); // Ensure old inverse was cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/association-set-ids-test.js000066400000000000000000000026421412317504700320370ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | Many To One | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [post, originalUser] = helper[state](); let user = helper.savedParent(); post.userId = user.id; expect(post.userId).toEqual(user.id); expect(post.user.attrs).toEqual(user.attrs); expect(post.user.posts.includes(post)).toBeTruthy(); post.save(); user.reload(); expect(user.posts.includes(post)).toBeTruthy(); // Old inverses were cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); test(`a ${state} can clear its association via a null parentId`, () => { let [post, originalUser] = helper[state](); post.userId = null; expect(post.user).toBeNull(); expect(post.userId).toBeNull(); post.save(); if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/association-set-test.js000066400000000000000000000034071412317504700312620ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | Many To One | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent`, () => { let [post, originalUser] = helper[state](); let savedUser = helper.savedParent(); post.user = savedUser; expect(post.user).toEqual(savedUser); expect(savedUser.posts.includes(post)).toBeTruthy(); post.save(); // Old inverse was cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); test(`a ${state} can update its association to a new parent`, () => { let [post, originalUser] = helper[state](); let newUser = helper.newParent(); post.user = newUser; expect(post.user).toEqual(newUser); expect(newUser.posts.includes(post)).toBeTruthy(); post.save(); // Old inverse was cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); test(`a ${state} can update its association to a null parent`, () => { let [post, originalUser] = helper[state](); post.user = null; expect(post.user).toBeNull(); post.save(); // Old inverse was cleared if (originalUser && originalUser.isSaved()) { originalUser.reload(); expect(originalUser.posts.includes(post)).toBeFalsy(); } }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/create-test.js000066400000000000000000000041521412317504700274160ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Mixed | Many To One | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let { schema } = helper; let user = schema.create("user"); let post = schema.create("post", { userId: user.id, }); user.reload(); expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); expect(user.posts.includes(post)).toBeTruthy(); expect(user.postIds).toEqual([post.id]); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it sets up associations correctly when passing in the association itself", () => { let { schema } = helper; let user = schema.create("user"); let post = schema.create("post", { user, }); expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); expect(user.posts.includes(post)).toBeTruthy(); expect(user.postIds).toEqual([post.id]); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", postIds: ["1"] }); }); test("it throws an error if a model is passed in without a defined relationship", () => { let { schema } = helper; expect(function () { schema.create("post", { foo: schema.create("foo"), }); }).toThrow(); }); test("it throws an error if a collection is passed in without a defined relationship", () => { let { schema } = helper; schema.create("foo"); schema.create("foo"); expect(function () { schema.create("post", { foos: schema.foos.all(), }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/2-many-to-one/instantiating-test.js000066400000000000000000000053701412317504700310320ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the child accepts a saved parent id", () => { let user = helper.savedParent(); let post = schema.posts.new({ userId: user.id }); expect(post.userId).toEqual(user.id); expect(post.user.attrs).toEqual(user.attrs); expect(post.attrs).toEqual({ userId: user.id }); post.save(); user.reload(); expect(user.posts.includes(post)).toBeTruthy(); }); test("the child errors if the parent id doesnt exist", () => { expect(function () { schema.posts.new({ userId: 2 }); }).toThrow(); }); test("the child accepts a null parent id", () => { let post = schema.posts.new({ userId: null }); expect(post.userId).toBeNull(); expect(post.user).toBeNull(); expect(post.attrs).toEqual({ userId: null }); }); test("the child accepts a saved parent model", () => { let user = helper.savedParent(); let post = schema.posts.new({ user }); expect(post.userId).toEqual("1"); expect(post.user.attrs).toEqual(user.attrs); expect(post.attrs).toEqual({ userId: null }); post.save(); user.reload(); expect(user.posts.includes(post)).toBeTruthy(); }); test("the child accepts a new parent model", () => { let user = schema.users.new({ age: 300 }); let post = schema.posts.new({ user }); expect(post.userId).toBeNil(); expect(post.user).toEqual(user); expect(post.attrs).toEqual({ userId: null }); expect(user.posts.includes(post)).toBeTruthy(); }); test("the child accepts a null parent model", () => { let post = schema.posts.new({ user: null }); expect(post.userId).toBeNull(); expect(post.user).toBeNull(); expect(post.attrs).toEqual({ userId: null }); }); test("the child accepts a parent model and id", () => { let user = helper.savedParent(); let post = schema.posts.new({ user, userId: user.id }); expect(post.userId).toEqual("1"); expect(post.user).toEqual(user); expect(post.attrs).toEqual({ userId: user.id }); expect(user.posts.includes(post)).toBeTruthy(); }); test("the child accepts no reference to a parent id or model as empty obj", () => { let post = schema.posts.new({}); expect(post.userId).toBeNull(); expect(post.user).toBeNull(); expect(post.attrs).toEqual({ userId: null }); }); test("the child accepts no reference to a parent id or model", () => { let post = schema.posts.new(); expect(post.userId).toBeNull(); expect(post.user).toBeNull(); expect(post.attrs).toEqual({ userId: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/000077500000000000000000000000001412317504700272025ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/_helper.js000066400000000000000000000070641412317504700311650ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo } from "miragejs"; /* A model with a hasMany association can be in eight states with respect to its association. This helper class returns a parent (and its children) in these various states. The return value is an array of the form [ parent, [child1, child2...] ] where the children array may be empty. */ export default class Helper { constructor() { this.server = new Server({ environment: "test", models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), post: Model.extend({ user: belongsTo({ inverse: "things" }), }), }, }); this.db = this.server.db; this.schema = this.server.schema; } shutdown() { this.server.shutdown(); } savedParentNoChildren() { let user = this.db.users.insert({ name: "Link" }); return [this.schema.users.find(user.id), []]; } savedParentNewChildren() { let user = this.schema.users.create({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } savedParentSavedChildren() { let { schema } = this; schema.db.loadData({ users: [ { id: "1", name: "Link", thingIds: [ { type: "post", id: "1" }, { type: "post", id: "2" }, ], }, ], posts: [ { id: "1", title: "Lorem", userId: "1" }, { id: "2", title: "Ipsum", userId: "1" }, ], }); return [schema.users.find(1), [schema.posts.find(1), schema.posts.find(2)]]; } savedParentMixedChildren() { this.schema.db.loadData({ users: [{ id: "1", name: "Link", thingIds: [{ type: "post", id: "1" }] }], posts: [{ id: "1", title: "Lorem", userId: "1" }], }); let user = this.schema.users.find(1); let post1 = this.schema.posts.find(1); let post2 = this.schema.posts.new({ name: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentNoChildren() { let user = this.schema.users.new({ name: "Link" }); return [user, []]; } newParentNewChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.new({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentSavedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.create({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } newParentMixedChildren() { let user = this.schema.users.new({ name: "Link" }); let post1 = this.schema.posts.create({ title: "Lorem" }); let post2 = this.schema.posts.new({ title: "Ipsum" }); user.things = [post1, post2]; return [user, [post1, post2]]; } // Unassociated child models, used for setting tests savedChild() { let insertedPost = this.db.posts.insert({ title: "Lorem" }); return this.schema.posts.find(insertedPost.id); } newChild() { return this.schema.posts.new({ title: "Lorem" }); } } export const states = [ "savedParentNoChildren", "savedParentNewChildren", "savedParentSavedChildren", "savedParentMixedChildren", "newParentNoChildren", "newParentNewChildren", "newParentSavedChildren", "newParentMixedChildren", ]; miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/accessor-test.js000066400000000000000000000020201412317504700323110ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | accessor", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The reference to a belongs-to association is correct, for all states */ states.forEach((state) => { test(`the references of a ${state} are correct`, () => { let [user, posts] = helper[state](); expect(user.things.models).toHaveLength(posts.length); expect(user.thingIds).toHaveLength(posts.length); posts.forEach((post) => { expect(user.things.includes(post)).toBeTruthy(); if (post.isSaved()) { expect( user.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); } // Check the inverse expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); }); }); }); }); association-create-test.js000066400000000000000000000022361412317504700342160ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | association #create", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can create a has-many association, for all states */ states.forEach((state) => { test(`a ${state} can create an associated parent`, () => { let [user] = helper[state](); let initialCount = user.things.models.length; let post = user.createThing("post", { title: "Lorem ipsum" }); expect(post.id).toBeTruthy(); expect(user.things.models).toHaveLength(initialCount + 1); expect(user.things.includes(post)).toBeTruthy(); expect( user.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); expect( user.attrs.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); // Check the inverse expect(post.user.attrs).toEqual(user.attrs); expect(post.userId).toEqual(user.id); }); }); }); association-new-test.js000066400000000000000000000021451412317504700335430ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | association #new", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can make a new unsaved belongs-to association, for all states */ states.forEach((state) => { test(`a ${state} can build a new associated parent`, () => { let [user] = helper[state](); let initialCount = user.things.models.length; let post = user.newThing("post", { title: "Lorem ipsum" }); expect(!post.id).toBeTruthy(); expect(user.things.models).toHaveLength(initialCount + 1); post.save(); expect(post.attrs).toEqual({ id: post.id, title: "Lorem ipsum", userId: user.id, }); expect(user.things.models).toHaveLength(initialCount + 1); expect(user.things.includes(post)).toBeTruthy(); expect( user.thingIds.find((obj) => { return obj.id === post.id && obj.type === "post"; }) ).toBeTruthy(); }); }); }); association-set-ids-test.js000066400000000000000000000030741412317504700343240ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | association #setIds", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parentId, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a saved parent via parentId`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.thingIds = [{ type: "post", id: savedPost.id }]; expect(user.things.includes(savedPost)).toBeTruthy(); expect(user.thingIds).toEqual([{ type: "post", id: savedPost.id }]); user.save(); savedPost.reload(); // Check the inverse expect(savedPost.user.attrs).toEqual(user.attrs); expect(savedPost.userId).toEqual(user.id); // Check old associates originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via a null parentId`, () => { let [user, originalPosts] = helper[state](); user.thingIds = null; expect(user.things.models).toBeEmpty(); expect(user.thingIds).toBeEmpty(); user.save(); // Check old associates originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); }); }); association-set-test.js000066400000000000000000000044541412317504700335520ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphicimport Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | association #set", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); /* The model can update its association via parent, for all states */ states.forEach((state) => { test(`a ${state} can update its association to a list of saved children`, () => { let [user, originalPosts] = helper[state](); let savedPost = helper.savedChild(); user.things = [savedPost]; expect(user.things.includes(savedPost)).toBeTruthy(); expect( user.thingIds.find( ({ id, type }) => id === savedPost.id && type === "post" ) ).toBeTruthy(); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can update its association to a new parent`, () => { let [user, originalPosts] = helper[state](); let newPost = helper.newChild(); user.things = [newPost]; expect(user.thingIds).toEqual([{ type: "post", id: undefined }]); expect(user.things.includes(newPost)).toBeTruthy(); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via an empty list`, () => { let [user, originalPosts] = helper[state](); user.things = []; expect(user.thingIds).toBeEmpty(); expect(user.things.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); test(`a ${state} can clear its association via an empty list`, () => { let [user, originalPosts] = helper[state](); user.things = null; expect(user.thingIds).toBeEmpty(); expect(user.things.models).toHaveLength(0); user.save(); originalPosts.forEach((post) => { if (post.isSaved()) { post.reload(); expect(post.user).toBeNull(); } }); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/create-test.js000066400000000000000000000047251412317504700317700ustar00rootroot00000000000000import Helper from "./_helper"; import { Model } from "miragejs"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | create", () => { let helper; beforeEach(() => { helper = new Helper(); helper.schema.registerModel("foo", Model); }); afterEach(() => { helper.shutdown(); }); test("it sets up associations correctly when passing in the foreign key", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { thingIds: [{ type: "post", id: post.id }], }); post.reload(); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); test("it sets up associations correctly when passing in an array of models", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { things: [post], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); expect(post.user.attrs).toEqual(user.attrs); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); test("it sets up associations correctly when passing in a collection", () => { let post = helper.schema.create("post"); let user = helper.schema.create("user", { things: helper.schema.posts.all(), }); post.reload(); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.attrs.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); let { db } = helper; expect(db.posts).toHaveLength(1); expect(db.posts[0]).toEqual({ id: "1", userId: "1" }); expect(db.users).toHaveLength(1); expect(db.users[0]).toEqual({ id: "1", thingIds: [{ type: "post", id: "1" }], }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/delete-test.js000066400000000000000000000011621412317504700317570ustar00rootroot00000000000000import Helper, { states } from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | delete", () => { let helper; beforeEach(() => { helper = new Helper(); }); afterEach(() => { helper.shutdown(); }); states.forEach((state) => { test(`deleting children updates the parent's foreign key for a ${state}`, () => { let [user, posts] = helper[state](); if (posts && posts.length) { posts.forEach((p) => p.destroy()); user.reload(); } expect(user.things).toHaveLength(0); expect(user.thingIds).toHaveLength(0); }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/3-one-to-many-polymorphic/instantiating-test.js000066400000000000000000000052051412317504700333730ustar00rootroot00000000000000import Helper from "./_helper"; describe("External | Shared | ORM | Mixed | One To Many Polymorphic | instantiating", () => { let helper, schema; beforeEach(() => { helper = new Helper(); schema = helper.schema; }); afterEach(() => { helper.shutdown(); }); test("the parent accepts a saved child id", () => { let post = helper.savedChild(); let user = schema.users.new({ thingIds: [{ type: "post", id: post.id }], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.includes(post)).toBeTruthy(); }); test("the parent errors if the children ids don't exist", () => { expect(function () { schema.users.new({ thingIds: [{ type: "post", id: 2 }] }); }).toThrow(); }); test("the parent accepts null children foreign key", () => { let user = schema.users.new({ thingIds: null }); expect(user.things.models).toHaveLength(0); expect(user.thingIds).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts saved children", () => { let post = helper.savedChild(); let user = schema.users.new({ things: [post] }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.models[0]).toEqual(post); }); test("the parent accepts new children", () => { let post = schema.posts.new({ title: "Lorem" }); let user = schema.users.new({ things: [post] }); expect(user.thingIds).toEqual([{ type: "post", id: undefined }]); expect(user.things.models[0]).toEqual(post); }); test("the parent accepts null children", () => { let user = schema.users.new({ things: null }); expect(user.things.models).toHaveLength(0); expect(user.thingIds).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts children and child ids", () => { let post = helper.savedChild(); let user = schema.users.new({ things: [post], thingIds: [{ type: "post", id: post.id }], }); expect(user.thingIds).toEqual([{ type: "post", id: post.id }]); expect(user.things.models[0]).toEqual(post); }); test("the parent accepts no reference to children or child ids as empty obj", () => { let user = schema.users.new({}); expect(user.thingIds).toBeEmpty(); expect(user.things.models).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); test("the parent accepts no reference to children or child ids", () => { let user = schema.users.new(); expect(user.thingIds).toBeEmpty(); expect(user.things.models).toBeEmpty(); expect(user.attrs).toEqual({ thingIds: null }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/mixed/regressions/000077500000000000000000000000001412317504700246775ustar00rootroot000000000000001613-two-bidirectional-many-to-many-with-same-target-model-update-bug-test.js000066400000000000000000000022241412317504700427770ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/orm/mixed/regressionsimport { Server, Model, hasMany, belongsTo } from "miragejs"; describe("External | Shared | ORM | Mixed | Regressions | 1613 Two bidirectional one-to-many relationships with same target model update ids bug", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model.extend({ authoredPosts: hasMany("post", { inverse: "author" }), editedPosts: hasMany("post", { inverse: "editor" }), }), post: Model.extend({ author: belongsTo("user", { inverse: "authoredPosts" }), editor: belongsTo("user", { inverse: "editedPosts" }), }), }, }); }); test(`it works, and all inverses are correctly updated`, () => { let user = server.schema.users.create(); let post = server.schema.posts.create(); post.update({ authorId: user.id, editorId: user.id, }); expect(server.db.posts.find(1)).toEqual({ id: "1", authorId: "1", editorId: "1", }); expect(server.db.users.find(1)).toEqual({ id: "1", authoredPostIds: ["1"], editedPostIds: ["1"], }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/model-associations-test.js000066400000000000000000000022131412317504700263340ustar00rootroot00000000000000import { Server, Model, belongsTo, hasMany } from "miragejs"; describe("External | Shared | ORM | Model | associations", () => { let server; let post; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, post: Model.extend({ user: belongsTo(), comments: hasMany(), }), comment: Model, }, }); let peter = server.create("user", { name: "Peter" }); post = server.create("post", { user: peter }); }); afterEach(() => { server.shutdown(); }); test("associations returns a hashmap of the model's associations", function () { let postAssociations = post.associations; expect(Object.keys(postAssociations)).toEqual(["user", "comments"]); expect(postAssociations.user.name).toEqual("user"); expect(postAssociations.user.modelName).toEqual("user"); expect(postAssociations.user.type).toEqual("belongsTo"); expect(postAssociations.comments.name).toEqual("comments"); expect(postAssociations.comments.modelName).toEqual("comment"); expect(postAssociations.comments.type).toEqual("hasMany"); }); }); miragejs-0.1.42/__tests__/external/shared/orm/none-test.js000066400000000000000000000012761412317504700235060ustar00rootroot00000000000000import { Server, Model, Collection } from "miragejs"; describe("External | Shared | ORM | #none", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, }, }); server.db.loadData({ user: [ { id: 1, name: "Link", good: true }, { id: 2, name: "Zelda", good: true }, { id: 3, name: "Ganon", good: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("it returns an empty collection", () => { let users = server.schema.users.none(); expect(users instanceof Collection).toBeTruthy(); expect(users.models).toHaveLength(0); }); }); miragejs-0.1.42/__tests__/external/shared/orm/reinitialize-associations-test.js000066400000000000000000000021211412317504700277220ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; describe("External | Shared | ORM | reinitialize associations", () => { // Model classes are defined statically, just like in a typical app let User = Model.extend({ addresses: hasMany(), }); let Address = Model.extend(); test("Model classes can be reused with multiple servers", () => { let config = { environment: "test", models: { address: Address, user: User, }, }; let server1 = new Server(config); server1.schema.addresses.create({ id: 1, country: "Hyrule" }); server1.schema.users.create({ id: 1, name: "Link", addressIds: [1] }); expect(server1.schema.users.find(1).addresses.models[0].country).toEqual( "Hyrule" ); server1.shutdown(); let server2 = new Server(config); server2.schema.addresses.create({ id: 1, country: "Hyrule" }); server2.schema.users.create({ id: 1, name: "Link", addressIds: [1] }); expect(server2.schema.users.find(1).addresses.models[0].country).toEqual( "Hyrule" ); server2.shutdown(); }); }); miragejs-0.1.42/__tests__/external/shared/orm/update-test.js000066400000000000000000000103671412317504700240320ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | ORM | #update", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { user: Model, }, }); server.db.loadData({ users: [ { id: 1, name: "Link", location: "Hyrule", evil: false }, { id: 2, name: "Zelda", location: "Hyrule", evil: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("a collection can update its models with a key and value", () => { let collection = server.schema.users.all(); collection.update("evil", true); expect(server.db.users).toIncludeSameMembers([ { id: "1", name: "Link", location: "Hyrule", evil: true }, { id: "2", name: "Zelda", location: "Hyrule", evil: true }, ]); expect(collection.models[0].attrs).toEqual({ id: "1", name: "Link", location: "Hyrule", evil: true, }); }); test("it can update its models with a hash of attrs", () => { let collection = server.schema.users.all(); collection.update({ location: "The water temple", evil: true }); expect(server.db.users).toIncludeSameMembers([ { id: "1", name: "Link", location: "The water temple", evil: true }, { id: "2", name: "Zelda", location: "The water temple", evil: true }, ]); expect(collection.models[0].attrs).toEqual({ id: "1", name: "Link", location: "The water temple", evil: true, }); expect(collection.models[1].attrs).toEqual({ id: "2", name: "Zelda", location: "The water temple", evil: true, }); }); test("it can set an attribute and then save the model", () => { let user = server.schema.users.find(1); user.name = "Young link"; expect(user.attrs).toEqual({ id: "1", name: "Young link", location: "Hyrule", evil: false, }); expect(server.db.users.find(1)).toEqual({ id: "1", name: "Link", location: "Hyrule", evil: false, }); user.save(); expect(user.attrs).toEqual({ id: "1", name: "Young link", location: "Hyrule", evil: false, }); expect(server.db.users.find(1)).toEqual({ id: "1", name: "Young link", location: "Hyrule", evil: false, }); }); test("it can update and immediately persist a single attribute", () => { let link = server.schema.users.find(1); link.update("evil", true); expect(link.attrs).toEqual({ id: "1", name: "Link", location: "Hyrule", evil: true, }); expect(server.db.users.find(1)).toEqual({ id: "1", name: "Link", location: "Hyrule", evil: true, }); }); test("it can update a hash of attrs immediately", () => { let link = server.schema.users.find(1); link.update({ name: "Evil link", evil: true }); expect(link.attrs).toEqual({ id: "1", name: "Evil link", location: "Hyrule", evil: true, }); expect(server.db.users.find(1)).toEqual({ id: "1", name: "Evil link", location: "Hyrule", evil: true, }); }); test("it can update a non-existing attribute", () => { let link = server.schema.users.find(1); link.update({ name: "Evil link", evil: true, reallyEvil: "absolutely evil", }); expect(link.attrs).toEqual({ id: "1", name: "Evil link", location: "Hyrule", evil: true, reallyEvil: "absolutely evil", }); expect(server.db.users.find(1)).toEqual({ id: "1", name: "Evil link", location: "Hyrule", evil: true, reallyEvil: "absolutely evil", }); }); test("if users sets incorrectly an attribute without using update, it will still work", () => { let link = server.schema.users.find(1); link.reallyEvil = "absolutely evil"; link.update({ reallyEvil: "a little flower", evil: true }); expect(link.attrs).toEqual({ id: "1", reallyEvil: "a little flower", evil: true, location: "Hyrule", name: "Link", }); expect(server.db.users.find(1)).toEqual({ id: "1", reallyEvil: "a little flower", evil: true, location: "Hyrule", name: "Link", }); }); }); miragejs-0.1.42/__tests__/external/shared/orm/where-test.js000066400000000000000000000031301412317504700236500ustar00rootroot00000000000000import { Server, Model, Collection } from "miragejs"; describe("External | Shared | ORM | #where", () => { let server; let User; beforeEach(() => { User = Model.extend(); server = new Server({ environment: "test", models: { user: User, }, }); server.db.loadData({ users: [ { id: 1, name: "Link", good: true }, { id: 2, name: "Zelda", good: true }, { id: 3, name: "Ganon", good: false }, ], }); }); afterEach(() => { server.shutdown(); }); test("it returns models that match a query with where", () => { let users = server.schema.users.where({ good: false }); expect(users instanceof Collection).toBeTruthy(); expect(users.models).toHaveLength(1); expect(users.models[0] instanceof User).toBeTruthy(); expect(users.models[0].attrs).toEqual({ id: "3", name: "Ganon", good: false, }); }); test("it returns models that match using a query function", () => { let users = server.schema.users.where(function (rec) { return !rec.good; }); expect(users instanceof Collection).toBeTruthy(); expect(users.models).toHaveLength(1); expect(users.models[0] instanceof User).toBeTruthy(); expect(users.models[0].attrs).toEqual({ id: "3", name: "Ganon", good: false, }); }); test("it returns an empty collection if no models match a query", () => { let users = server.schema.users.where({ name: "Link", good: false }); expect(users instanceof Collection).toBeTruthy(); expect(users.models).toHaveLength(0); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/000077500000000000000000000000001412317504700227655ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/active-model-serializer-test.js000066400000000000000000000135541412317504700310300ustar00rootroot00000000000000import { Server, ActiveModelSerializer, Model, hasMany, belongsTo, } from "miragejs"; describe("External | Shared | Serializers | ActiveModelSerializer", () => { let server; afterEach(function () { server.shutdown(); }); describe("with serializeIds as included", () => { beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), comments: hasMany(), }), user: Model.extend({ contactInfos: hasMany(), }), contactInfo: Model.extend({ user: belongsTo(), }), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }, serializers: { application: ActiveModelSerializer, wordSmith: ActiveModelSerializer.extend({ serializeIds: "included", attrs: ["id", "name"], include: ["blogPosts"], }), blogPost: ActiveModelSerializer.extend({ serializeIds: "included", include: ["wordSmith", "comments"], }), comment: ActiveModelSerializer.extend({ serializeIds: "included", include: ["commentable"], }), contactInfo: ActiveModelSerializer.extend({ serializeIds: "included", include: ["user"], }), user: ActiveModelSerializer.extend({ serializeIds: "included", attrs: ["id", "name"], include: ["contactInfos"], embed: true, }), }, }); let link = server.schema.wordSmiths.create({ name: "Link", age: 123 }); let post1 = link.createBlogPost({ title: "Lorem" }); link.createBlogPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ name: "Zelda", age: 230 }); let user = server.schema.users.create({ name: "John Peach", age: 123 }); user.createContactInfo({ email: "peach@bb.me" }); user.createContactInfo({ email: "john3000@mail.com" }); server.schema.users.create({ name: "Pine Apple", age: 230 }); server.schema.comments.create({ text: "Hi there", commentable: post1 }); }); test("it sideloads associations and snake-cases relationships and attributes correctly for a model", () => { let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ word_smith: { id: "1", name: "Link", blog_post_ids: ["1", "2"], }, blog_posts: [ { id: "1", title: "Lorem", word_smith_id: "1", comment_ids: ["1"], }, { id: "2", title: "Ipsum", word_smith_id: "1", comment_ids: [], }, ], comments: [ { id: "1", text: "Hi there", commentable_id: "1", commentable_type: "blog-post", }, ], }); }); test("it sideloads associations and snake-cases relationships and attributes correctly for a collection", () => { let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ word_smiths: [ { id: "1", name: "Link", blog_post_ids: ["1", "2"], }, { id: "2", name: "Zelda", blog_post_ids: [], }, ], blog_posts: [ { id: "1", title: "Lorem", word_smith_id: "1", comment_ids: ["1"], }, { id: "2", title: "Ipsum", word_smith_id: "1", comment_ids: [], }, ], comments: [ { id: "1", text: "Hi there", commentable_id: "1", commentable_type: "blog-post", }, ], }); }); test("it embeds associations and snake-cases relationships and attributes correctly for a collection", () => { let users = server.schema.users.all(); let result = server.serializerOrRegistry.serialize(users); expect(result).toEqual({ users: [ { id: "1", name: "John Peach", contact_infos: [ { id: "1", email: "peach@bb.me", user_id: "1", }, { id: "2", email: "john3000@mail.com", user_id: "1", }, ], }, { id: "2", name: "Pine Apple", contact_infos: [], }, ], }); }); }); describe("with serializeIds as always", () => { test("it correctly serializes a Collection for a model that has a polymorphic relationship", () => { server = new Server({ models: { post: Model, comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }, serializers: { application: ActiveModelSerializer.extend({ serializeIds: "always", }), }, }); server.schema.comments.create({ commentable: server.schema.posts.create(), }); let serializedComments = server.serializerOrRegistry.serialize( server.schema.comments.all() ); expect(serializedComments).toEqual({ comments: [ { id: "1", commentable_id: "1", commentable_type: "post", }, ], }); }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/000077500000000000000000000000001412317504700236775ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/000077500000000000000000000000001412317504700263765ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/embedded-collection-test.js000066400000000000000000000101311412317504700335670ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Embedded Collections", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blogPost", { inverse: "author" }), }), blogPost: Model.extend({ author: belongsTo("wordSmith", { inverse: "posts" }), comments: hasMany("fineComment", { inverse: "post" }), }), fineComment: Model.extend({ post: belongsTo("blogPost"), }), }, }); let wordSmith = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = wordSmith.createPost({ title: "Lorem" }); blogPost.createComment({ text: "pwned" }); wordSmith.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ name: "Zelda" }); BaseSerializer = Serializer.extend({ embed: true, }); }); afterEach(function () { server.shutdown(); }); test(`it can embed a collection with a has-many relationship`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, ], }, { id: "2", name: "Zelda", posts: [], }, ], }); }); test(`it can embed a collection with a chain of has-many relationships`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["comments"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem", comments: [{ id: "1", text: "pwned" }], }, { id: "2", title: "Ipsum", comments: [], }, ], }, { id: "2", name: "Zelda", posts: [], }, ], }); }); test(`it can embed a collection with a belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let blogPosts = server.schema.blogPosts.all(); let result = server.serializerOrRegistry.serialize(blogPosts); expect(result).toEqual({ blogPosts: [ { id: "1", title: "Lorem", author: { id: "1", name: "Link" }, }, { id: "2", title: "Ipsum", author: { id: "1", name: "Link" }, }, ], }); }); test(`it can embed a collection with a chain of belongs-to relationships`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ include: ["post"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let fineComments = server.schema.fineComments.all(); let result = server.serializerOrRegistry.serialize(fineComments); expect(result).toEqual({ fineComments: [ { id: "1", text: "pwned", post: { id: "1", title: "Lorem", author: { id: "1", name: "Link" }, }, }, ], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/embedded-model-test.js000066400000000000000000000131671412317504700325500ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Embedded Models", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blogPost", { inverse: "author" }), }), blogPost: Model.extend({ author: belongsTo("wordSmith", { inverse: "posts" }), comments: hasMany("fineComment", { inverse: "post" }), }), fineComment: Model.extend({ post: belongsTo("blogPost"), }), }, }); let wordSmith = server.schema.wordSmiths.create({ name: "Link" }); let post = wordSmith.createPost({ title: "Lorem" }); post.createComment({ text: "pwned" }); wordSmith.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ name: "Zelda" }); BaseSerializer = Serializer.extend({ embed: true, }); }); afterEach(function () { server.shutdown(); }); test(`it can embed has-many relationships`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), }, }); let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, ], }, }); }); test(`it can embed a chain of has-many relationships`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["comments"], }), }, }); let wordSmith = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem", comments: [{ id: "1", text: "pwned" }] }, { id: "2", title: "Ipsum", comments: [] }, ], }, }); }); test(`it can embed a belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, blogPost: BaseSerializer.extend({ embed: true, include: ["author"], }), }, }); let blogPost = server.schema.blogPosts.find(1); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ blogPost: { id: "1", title: "Lorem", author: { id: "1", name: "Link" }, }, }); }); test(`it can serialize a chain of belongs-to relationships`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ include: ["post"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let fineComment = server.schema.fineComments.find(1); let result = server.serializerOrRegistry.serialize(fineComment); expect(result).toEqual({ fineComment: { id: "1", text: "pwned", post: { id: "1", title: "Lorem", author: { id: "1", name: "Link", }, }, }, }); }); test(`it can have a null value on a belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, blogPost: BaseSerializer.extend({ embed: true, include: ["author"], }), }, }); let blogPost = server.schema.blogPosts.find(1); blogPost.update("author", null); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ blogPost: { id: "1", title: "Lorem", }, }); }); test(`it ignores relationships that refer to serialized ancestor resources`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let wordSmith = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, ], }, }); }); test(`it ignores relationships that refer to serialized ancestor resources, multiple levels down`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: true, include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["author", "comments"], }), fineComment: BaseSerializer.extend({ include: ["post"], }), }, }); let wordSmith = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", posts: [ { id: "1", title: "Lorem", comments: [{ id: "1", text: "pwned" }] }, { id: "2", title: "Ipsum", comments: [] }, ], }, }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/polymorphic/000077500000000000000000000000001412317504700307435ustar00rootroot00000000000000belongs-to-test.js000066400000000000000000000024131412317504700342500ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/polymorphicimport { Server, Model, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Polymorphic | Belongs To", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { post: Model.extend(), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }, }); let post = server.schema.posts.create({ title: "Lorem ipsum" }); server.schema.comments.create({ commentable: post, text: "Foo" }); BaseSerializer = Serializer.extend({ embed: false, }); }); afterEach(function () { server.shutdown(); }); test(`it can serialize a polymorphic belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, comment: BaseSerializer.extend({ include: ["commentable"], }), }, }); let comment = server.schema.comments.find(1); let result = server.serializerOrRegistry.serialize(comment); expect(result).toEqual({ comment: { id: "1", text: "Foo", commentableType: "post", commentableId: "1", }, posts: [{ id: "1", title: "Lorem ipsum" }], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/polymorphic/has-many-test.js000066400000000000000000000050731412317504700340000ustar00rootroot00000000000000import { Server, Model, hasMany, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Polymorphic | Has Many", function () { let server; beforeEach(function () { server = new Server({ models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), picture: Model.extend(), }, }); let post = server.schema.pictures.create({ title: "Lorem ipsum" }); server.schema.users.create({ things: [post], name: "Ned" }); }); afterEach(function () { server.shutdown(); }); test(`it can serialize a polymorphic has-many relationship when serializeIds is set to included`, () => { let BaseSerializer = Serializer.extend({ embed: false, serializeIds: "included", }); server.config({ serializers: { application: BaseSerializer, user: BaseSerializer.extend({ serializeIds: "included", include: ["things"], }), }, }); let user = server.schema.users.find(1); let result = server.serializerOrRegistry.serialize(user); expect(result).toEqual({ user: { id: "1", name: "Ned", thingIds: [{ id: "1", type: "picture" }], }, pictures: [{ id: "1", title: "Lorem ipsum" }], }); }); test(`it can serialize a polymorphic has-many relationship when serializeIds is set to always`, () => { let BaseSerializer = Serializer.extend({ embed: false, serializeIds: "always", }); server.config({ serializers: { application: BaseSerializer, user: BaseSerializer, }, }); let user = server.schema.users.find(1); let result = server.serializerOrRegistry.serialize(user); expect(result).toEqual({ user: { id: "1", name: "Ned", thingIds: [{ id: "1", type: "picture" }], }, }); }); test(`it can serialize an embedded polymorphic has-many relationship`, () => { let BaseSerializer = Serializer.extend({ embed: true, serializeIds: "included", }); server.config({ serializers: { application: BaseSerializer, user: BaseSerializer.extend({ include: ["things"], }), }, }); let user = server.schema.users.find(1); let result = server.serializerOrRegistry.serialize(user); expect(result).toEqual({ user: { id: "1", name: "Ned", things: [ { id: "1", title: "Lorem ipsum", }, ], }, }); }); }); top-level-test.js000066400000000000000000000026721412317504700341150ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/polymorphicimport { Server, Model, hasMany, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Polymorphic | Top level", function () { let server, user; beforeEach(function () { server = new Server({ models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), picture: Model.extend(), car: Model.extend(), }, }); user = server.create("user", { things: [ server.create("picture", { title: "Picture 1" }), server.create("car", { name: "Car 1" }), ], }); }); afterEach(function () { server.shutdown(); }); test(`it can serialize a polymorphic collection when root is false`, () => { server.config({ serializers: { application: Serializer.extend({ root: false, embed: true, }), }, }); let json = server.serializerOrRegistry.serialize(user.things); expect(json).toEqual([ { id: "1", title: "Picture 1", }, { id: "1", name: "Car 1", }, ]); }); test(`it throws if trying to serialize a polymorphic collection when root is true`, () => { server.config({ serializers: { application: Serializer.extend({ root: true, }), }, }); expect(() => { server.serializerOrRegistry.serialize(user.things); }).toThrow(); }); }); sideloading-and-embedded-collection-test.js000066400000000000000000000054011412317504700365340ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associationsimport { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Sideloading and Embedded Collections", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), comments: hasMany("fine-comment"), }), fineComment: Model.extend({ post: belongsTo("blog-post"), }), }, }); let link = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = link.createPost({ title: "Lorem" }); link.createPost({ title: "Ipsum" }); blogPost.createComment({ text: "pwned" }); let zelda = server.schema.wordSmiths.create({ name: "Zelda" }); zelda.createPost({ title: `Zeldas blogPost` }); BaseSerializer = Serializer.extend({ embed: false, }); }); afterEach(function () { server.shutdown(); }); test(`it can sideload a collection with a has-many relationship containing embedded models`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: false, include: ["posts"], }), blogPost: BaseSerializer.extend({ embed: true, include: ["comments"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", postIds: ["1", "2"] }, { id: "2", name: "Zelda", postIds: ["3"] }, ], blogPosts: [ { id: "1", title: "Lorem", comments: [{ id: "1", text: "pwned" }] }, { id: "2", title: "Ipsum", comments: [] }, { id: "3", title: "Zeldas blogPost", comments: [] }, ], }); }); test(`it can sideload a collection with a belongs-to relationship containing embedded models`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ embed: false, include: ["post"], }), blogPost: BaseSerializer.extend({ embed: true, include: ["author"], }), }, }); let fineComments = server.schema.fineComments.all(); let result = server.serializerOrRegistry.serialize(fineComments); expect(result).toEqual({ fineComments: [{ id: "1", text: "pwned", postId: "1" }], blogPosts: [ { id: "1", title: "Lorem", author: { id: "1", name: "Link" }, }, ], }); }); }); sideloading-and-embedded-model-test.js000066400000000000000000000051161412317504700355040ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associationsimport { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Sideloading and Embedded Models", function () { let server, BaseSerializer; beforeEach(function () { BaseSerializer = Serializer.extend({ embed: false, }); server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), comments: hasMany("fine-comment"), }), fineComment: Model.extend({ post: belongsTo("blog-post"), }), }, }); let wordSmith = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = wordSmith.createPost({ title: "Lorem" }); blogPost.createComment({ text: "pwned" }); wordSmith.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ name: "Zelda" }); }); afterEach(function () { server.shutdown(); }); test(`it can sideload a model with a has-many relationship containing embedded models`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: false, include: ["posts"], }), blogPost: BaseSerializer.extend({ embed: true, include: ["comments"], }), }, }); let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", postIds: ["1", "2"], }, blogPosts: [ { id: "1", title: "Lorem", comments: [{ id: "1", text: "pwned" }] }, { id: "2", title: "Ipsum", comments: [] }, ], }); }); test(`it can sideload a model with a belongs-to relationship containing embedded models`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ embed: false, include: ["post"], }), blogPost: BaseSerializer.extend({ embed: true, include: ["author"], }), }, }); let fineComment = server.schema.fineComments.find(1); let result = server.serializerOrRegistry.serialize(fineComment); expect(result).toEqual({ fineComment: { id: "1", text: "pwned", postId: "1" }, blogPosts: [ { id: "1", title: "Lorem", author: { id: "1", name: "Link" }, }, ], }); }); }); sideloading-assorted-collections-test.js000066400000000000000000000036541412317504700362620ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associationsimport { Server, Model, hasMany, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Sideloading Assorted Collections", function () { let server, wordSmiths, blogPosts, greatPhotos; beforeEach(function () { let BaseSerializer = Serializer.extend({ embed: false, }); server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model, greatPhoto: Model, }, serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["blogPosts"], }), greatPhoto: BaseSerializer.extend({ attrs: ["id", "title"], }), }, }); wordSmiths = [ { id: "1", name: "Link", blogPostIds: ["1", "2"] }, { id: "2", name: "Zelda", blogPostIds: [] }, { id: "3", name: "Epona", blogPostIds: [] }, ]; blogPosts = [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, ]; greatPhotos = [ { id: "1", title: "Amazing", location: "Hyrule" }, { id: "2", title: "greatPhoto", location: "Goron City" }, ]; server.db.loadData({ wordSmiths: wordSmiths, blogPosts: blogPosts, greatPhotos: greatPhotos, }); }); afterEach(function () { server.shutdown(); }); /* This is a strange response from a route handler, but it's used in the array get shorthand. Deprecate that shorthand? */ test(`it can sideload an array of assorted collections that have relationships`, () => { let result = server.serializerOrRegistry.serialize([ server.schema.wordSmiths.all(), server.schema.greatPhotos.all(), ]); expect(result).toEqual({ wordSmiths: wordSmiths, blogPosts: blogPosts, greatPhotos: greatPhotos.map((attrs) => { delete attrs.location; return attrs; }), }); }); }); sideloading-collection-test.js000066400000000000000000000134071412317504700342520ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/base/associationsimport { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Sideloading Collections", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), comments: hasMany("fine-comment"), }), fineComment: Model.extend({ post: belongsTo("blog-post"), }), }, }); let link = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = link.createPost({ title: "Lorem" }); link.createPost({ title: "Ipsum" }); blogPost.createComment({ text: "pwned" }); let zelda = server.schema.wordSmiths.create({ name: "Zelda" }); zelda.createPost({ title: `Zeldas blogPost` }); BaseSerializer = Serializer.extend({ embed: false, }); }); afterEach(function () { server.shutdown(); }); test(`it throws an error if embed is false and root is false`, () => { server.config({ serializers: { wordSmith: BaseSerializer.extend({ root: false, include: ["posts"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); expect(function () { server.serializerOrRegistry.serialize(wordSmiths); }).toThrow(); }); test(`it can sideload an empty collection`, () => { server.schema.db.emptyData(); server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), }, }); let result = server.serializerOrRegistry.serialize( server.schema.wordSmiths.all() ); expect(result).toEqual({ wordSmiths: [], }); }); test(`it can sideload a collection with a has-many relationship`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: false, include: ["posts"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", postIds: ["1", "2"] }, { id: "2", name: "Zelda", postIds: ["3"] }, ], blogPosts: [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, { id: "3", title: "Zeldas blogPost" }, ], }); }); test(`it can sideload a collection with a chain of has-many relationships`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: false, include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["comments"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", postIds: ["1", "2"] }, { id: "2", name: "Zelda", postIds: ["3"] }, ], blogPosts: [ { id: "1", title: "Lorem", commentIds: ["1"] }, { id: "2", title: "Ipsum", commentIds: [] }, { id: "3", title: "Zeldas blogPost", commentIds: [] }, ], fineComments: [{ id: "1", text: "pwned" }], }); }); test(`it avoids circularity when serializing a collection`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ embed: false, include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link", postIds: ["1", "2"] }, { id: "2", name: "Zelda", postIds: ["3"] }, ], blogPosts: [ { id: "1", title: "Lorem", authorId: "1" }, { id: "2", title: "Ipsum", authorId: "1" }, { id: "3", title: "Zeldas blogPost", authorId: "2" }, ], }); }); test(`it can sideload a collection with a belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, blogPost: BaseSerializer.extend({ embed: false, include: ["author"], }), }, }); let blogPosts = server.schema.blogPosts.all(); let result = server.serializerOrRegistry.serialize(blogPosts); expect(result).toEqual({ blogPosts: [ { id: "1", title: "Lorem", authorId: "1" }, { id: "2", title: "Ipsum", authorId: "1" }, { id: "3", title: "Zeldas blogPost", authorId: "2" }, ], wordSmiths: [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ], }); }); test(`it can sideload a collection with a chain of belongs-to relationships`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ embed: false, include: ["post"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let fineComments = server.schema.fineComments.all(); let result = server.serializerOrRegistry.serialize(fineComments); expect(result).toEqual({ fineComments: [{ id: "1", text: "pwned", postId: "1" }], blogPosts: [{ id: "1", title: "Lorem", authorId: "1" }], wordSmiths: [{ id: "1", name: "Link" }], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/associations/sideloading-model-test.js000066400000000000000000000112741412317504700332760ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Associations | Sideloading Models", function () { let server, BaseSerializer; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), comments: hasMany("fine-comment"), }), fineComment: Model.extend({ post: belongsTo("blog-post"), }), }, }); let wordSmith = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = wordSmith.createPost({ title: "Lorem" }); blogPost.createComment({ text: "pwned" }); wordSmith.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ name: "Zelda" }); BaseSerializer = Serializer.extend({ embed: false, }); }); afterEach(function () { server.shutdown(); }); test(`it throws an error if embed is false and root is false`, () => { server.config({ serializers: { wordSmith: BaseSerializer.extend({ root: false, include: ["posts"], }), }, }); let link = server.schema.wordSmiths.find(1); expect(function () { server.serializerOrRegistry.serialize(link); }).toThrow(); }); test(`it can sideload a model with a has-many relationship`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), }, }); let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", postIds: ["1", "2"], }, blogPosts: [ { id: "1", title: "Lorem" }, { id: "2", title: "Ipsum" }, ], }); }); test(`it can sideload a model with a chain of has-many relationships`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["comments"], }), }, }); let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", postIds: ["1", "2"], }, blogPosts: [ { id: "1", title: "Lorem", commentIds: ["1"] }, { id: "2", title: "Ipsum", commentIds: [] }, ], fineComments: [{ id: "1", text: "pwned" }], }); }); test(`it avoids circularity when serializing a model`, () => { server.config({ serializers: { application: BaseSerializer, wordSmith: BaseSerializer.extend({ include: ["posts"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let link = server.schema.wordSmiths.find(1); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", postIds: ["1", "2"], }, blogPosts: [ { id: "1", title: "Lorem", authorId: "1" }, { id: "2", title: "Ipsum", authorId: "1" }, ], }); }); test(`it can sideload a model with a belongs-to relationship`, () => { server.config({ serializers: { application: BaseSerializer, blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let blogPost = server.schema.blogPosts.find(1); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ blogPost: { id: "1", title: "Lorem", authorId: "1", }, wordSmiths: [{ id: "1", name: "Link" }], }); }); test(`it can sideload a model with a chain of belongs-to relationships`, () => { server.config({ serializers: { application: BaseSerializer, fineComment: BaseSerializer.extend({ include: ["post"], }), blogPost: BaseSerializer.extend({ include: ["author"], }), }, }); let fineComment = server.schema.fineComments.find(1); let result = server.serializerOrRegistry.serialize(fineComment); expect(result).toEqual({ fineComment: { id: "1", text: "pwned", postId: "1", }, blogPosts: [{ id: "1", title: "Lorem", authorId: "1" }], wordSmiths: [{ id: "1", name: "Link" }], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/assorted-collections-test.js000066400000000000000000000023401412317504700313510ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Assorted Collections", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, greatPhoto: Model, }, serializers: { application: Serializer, greatPhoto: Serializer.extend({ attrs: ["id", "title"], }), }, }); }); afterEach(function () { server.shutdown(); }); test(`an array of assorted collections can be serialized`, () => { let wordSmiths = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, { id: "3", name: "Epona" }, ]; let greatPhotos = [ { id: "1", title: "Amazing", location: "Hyrule" }, { id: "2", title: "greatPhoto", location: "Goron City" }, ]; server.db.loadData({ wordSmiths, greatPhotos }); let result = server.serializerOrRegistry.serialize([ server.schema.wordSmiths.all(), server.schema.greatPhotos.all(), ]); expect(result).toEqual({ wordSmiths: wordSmiths, greatPhotos: greatPhotos.map((attrs) => { delete attrs.location; return attrs; }), }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/attribute-key-formatting-test.js000066400000000000000000000032521412317504700321550ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; const dasherize = (str) => str.replace( /[A-Z]/g, (char, index) => (index !== 0 ? "-" : "") + char.toLowerCase() ); describe("External | Shared | Serializers | Base | Attribute Key Formatting", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, }, serializers: { wordSmith: Serializer.extend({ keyForAttribute(key) { return dasherize(key); }, }), }, }); }); afterEach(function () { server.shutdown(); }); test(`keyForAttribute formats the attributes of a model`, () => { let wordSmith = server.schema.wordSmiths.create({ id: 1, firstName: "Link", lastName: "Jackson", age: 323, }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", "first-name": "Link", "last-name": "Jackson", age: 323, }, }); }); test(`keyForAttribute also formats the models in a collections`, () => { server.schema.wordSmiths.create({ id: 1, firstName: "Link", lastName: "Jackson", }); server.schema.wordSmiths.create({ id: 2, firstName: "Zelda", lastName: "Brown", }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", "first-name": "Link", "last-name": "Jackson" }, { id: "2", "first-name": "Zelda", "last-name": "Brown" }, ], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/attrs-test.js000066400000000000000000000024771412317504700263610ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Attrs List", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, }, serializers: { application: Serializer, wordSmith: Serializer.extend({ attrs: ["id", "name"], }), }, }); }); afterEach(function () { server.shutdown(); }); test(`it returns only the whitelisted attrs when serializing a model`, () => { let wordSmith = server.schema.wordSmiths.create({ id: 1, name: "Link", age: 123, }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", }, }); }); test(`it returns only the whitelisted attrs when serializing a collection`, () => { server.schema.wordSmiths.create({ id: 1, name: "Link", age: 123 }); server.schema.wordSmiths.create({ id: 2, name: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/basic-test.js000066400000000000000000000046411412317504700263000ustar00rootroot00000000000000import { Server, Model } from "miragejs"; import uniqBy from "lodash.uniqby"; describe("External | Shared | Serializers | Base | Basic", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, }, }); }); afterEach(function () { server.shutdown(); }); test("it returns objects unaffected", () => { let result = server.serializerOrRegistry.serialize({ oh: "hai" }); expect(result).toEqual({ oh: "hai" }); }); test("it returns arrays unaffected", () => { let data = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; let result = server.serializerOrRegistry.serialize(data); expect(result).toEqual(data); }); test("it returns empty arrays unaffected", () => { let result = server.serializerOrRegistry.serialize([]); expect(result).toEqual([]); }); test(`it serializes a model by returning its attrs under a root`, () => { let wordSmith = server.schema.wordSmiths.create({ id: 1, name: "Link", }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", }, }); }); test(`it serializes a collection of models by returning an array of their attrs under a pluralized root`, () => { server.schema.wordSmiths.create({ id: 1, name: "Link" }); server.schema.wordSmiths.create({ id: 2, name: "Zelda" }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ], }); }); test(`it can serialize an empty collection`, () => { let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ wordSmiths: [], }); }); test("it returns POJAs of models unaffected", () => { server.schema.wordSmiths.create({ name: "Sam" }); server.schema.wordSmiths.create({ name: "Sam" }); server.schema.wordSmiths.create({ name: "Ganondorf" }); let wordSmiths = server.schema.wordSmiths.all().models; let uniqueNames = uniqBy(wordSmiths, "name"); let result = server.serializerOrRegistry.serialize(uniqueNames); expect(result).toEqual(uniqueNames); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/override-serialize-test.js000066400000000000000000000041371412317504700310230ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Overriding Serialize", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, }, }); }); afterEach(function () { server.shutdown(); }); test(`it can use a completely custom serialize function`, () => { server.config({ serializers: { wordSmith: Serializer.extend({ serialize() { return "blah"; }, }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, title: "Link", }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual("blah"); }); test(`it can access the request in a custom serialize function`, () => { server.config({ serializers: { wordSmith: Serializer.extend({ serialize(response, request) { return request.queryParams.foo || "blah"; }, }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, title: "Link", }); let request = { url: "/word-smiths/1?foo=bar", params: { id: "1" }, queryParams: { foo: "bar" }, }; let result = server.serializerOrRegistry.serialize(wordSmith, request); expect(result).toEqual("bar"); }); test(`it can access the databse while in a serializer method`, () => { server.config({ serializers: { wordSmith: Serializer.extend({ serialize(response, request) { let id = request.params.id; return server.schema.db.wordSmiths.find(id).title || "No title"; }, }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, title: "Title in database", }); let request = { url: "/word-smiths/1?foo=bar", params: { id: "1" }, queryParams: { foo: "bar" }, }; let result = server.serializerOrRegistry.serialize(wordSmith, request); expect(result).toEqual("Title in database"); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/root-test.js000066400000000000000000000030041412317504700261720ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Root", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model, }, serializers: { wordSmith: Serializer.extend({ embed: true, root: false, }), }, }); }); afterEach(function () { server.shutdown(); }); test(`if root is false, it serializes a model by returning its attrs`, () => { let wordSmith = server.schema.wordSmiths.create({ id: "1", name: "Link", }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ id: "1", name: "Link", }); }); test(`if root is false, it serializes a collection of models by returning an array of their attrs`, () => { server.schema.wordSmiths.create({ id: 1, name: "Link" }); server.schema.wordSmiths.create({ id: 2, name: "Zelda" }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual([ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]); }); test(`if root is false, it serializes an empty collection by returning an empty array`, () => { let emptywordSmithCollection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize( emptywordSmithCollection ); expect(result).toEqual([]); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/serialize-array-of-models-test.js000066400000000000000000000014371412317504700322050ustar00rootroot00000000000000import { Server, Model, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Array of Models", function () { let server; afterEach(function () { server.shutdown(); }); test(`it applies correct serializer when the response is an array of models`, () => { server = new Server({ models: { wordSmith: Model, }, serializers: { wordSmith: Serializer.extend({ serialize() { return "serializer ran"; }, }), }, }); server.schema.wordSmiths.create({ id: 1, title: "Link" }); let wordSmiths = server.schema.wordSmiths.all().filter(() => true); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual("serializer ran"); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/base/serialize-ids-test.js000066400000000000000000000037371412317504700277700ustar00rootroot00000000000000import { Server, Serializer, Model, hasMany } from "miragejs"; describe("External | Shared | Serializers | Base | Serialize ids", function () { let server; beforeEach(function () { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), specialPosts: hasMany("blog-post", { inverse: "specialAuthor" }), }), blogPost: Model, }, }); }); afterEach(function () { server.shutdown(); }); test(`if serializeIds is 'include' it serializes ids of hasMany associations that are included`, () => { let ApplicationSerializer = Serializer.extend({ serializeIds: "included", }); server.config({ serializers: { application: ApplicationSerializer, wordSmith: ApplicationSerializer.extend({ include: ["blogPosts"], }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, name: "Link", }); wordSmith.createBlogPost(); wordSmith.createBlogPost(); wordSmith.createSpecialPost(); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", blogPostIds: ["1", "2"], }, blogPosts: [{ id: "1" }, { id: "2" }], }); }); test(`if serializeIds is 'always' it serializes ids of all hasMany associations`, () => { server.config({ serializers: { application: Serializer.extend({ serializeIds: "always", }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, name: "Link", }); wordSmith.createBlogPost(); wordSmith.createBlogPost(); wordSmith.createSpecialPost(); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", blogPostIds: ["1", "2"], specialPostIds: ["3"], }, }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/000077500000000000000000000000001412317504700266545ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associations/000077500000000000000000000000001412317504700313535ustar00rootroot00000000000000collection-test.js000066400000000000000000000313751412317504700347530ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associationsimport { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Associations | Collection", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model.extend({ posts: hasMany("blogPost", { inverse: "author" }), }), blogPost: Model.extend({ author: belongsTo("wordSmith", { inverse: "posts" }), comments: hasMany("fineComment", { inverse: "post" }), }), fineComment: Model.extend({ post: belongsTo("blogPost"), }), }, }); }); afterEach(() => { server.shutdown(); }); test(`by default, it doesn't include a collection's relationships if those relationships are not included in the document and no links are defined`, () => { server.config({ serializers: { application: JSONAPISerializer, }, }); server.schema.wordSmiths.create({ firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ firstName: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", age: 123, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", age: 456, }, }, ], }); }); test(`when alwaysIncludeLinkageData is true, it contains linkage data for all a collection's relationships, regardless of includes`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }), }, }); server.schema.wordSmiths.create({ firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ firstName: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", age: 123, }, relationships: { posts: { data: [], }, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", age: 456, }, relationships: { posts: { data: [], }, }, }, ], }); }); test(`when shouldIncludeLinkageData returns true for a relationship, it contains linkage data for that relationship on all of the collection, regardless of includes`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ shouldIncludeLinkageData(relationshipName, model) { if (relationshipName == "posts") { return true; } }, }), }, }); server.schema.wordSmiths.create({ firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ firstName: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", age: 123, }, relationships: { posts: { data: [], }, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", age: 456, }, relationships: { posts: { data: [], }, }, }, ], }); }); test(`it includes linkage data for a has-many relationship that's being included`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ include: ["posts"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); link.createPost({ title: "Lorem" }); link.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ firstName: "Zelda" }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { posts: { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", }, relationships: { posts: { data: [], }, }, }, ], included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, }, ], }); }); test(`it can serialize a collection with a chain of has-many relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ include: ["posts"], }), blogPost: JSONAPISerializer.extend({ include: ["comments"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let lorem = link.createPost({ title: "Lorem" }); lorem.createComment({ text: "pwned" }); link.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ firstName: "Zelda" }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { posts: { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", }, relationships: { posts: { data: [], }, }, }, ], included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { comments: { data: [{ type: "fine-comments", id: "1" }], }, }, }, { type: "fine-comments", id: "1", attributes: { text: "pwned", }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, relationships: { comments: { data: [], }, }, }, ], }); }); test(`it can serialize a collection with a belongs-to relationship`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["author"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let post = link.createPost({ title: "Lorem" }); post.createComment(); link.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ firstName: "Zelda" }); let blogPosts = server.schema.blogPosts.all(); let result = server.serializerOrRegistry.serialize(blogPosts); expect(result).toEqual({ data: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { author: { data: { type: "word-smiths", id: "1" }, }, }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, relationships: { author: { data: { type: "word-smiths", id: "1" }, }, }, }, ], included: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, ], }); }); test(`it can serialize a collection with a chain of belongs-to relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, fineComment: JSONAPISerializer.extend({ include: ["post"], }), blogPost: JSONAPISerializer.extend({ include: ["author"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let post = link.createPost({ title: "Lorem" }); post.createComment({ text: "pwned" }); link.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ firstName: "Zelda" }); let fineComments = server.schema.fineComments.all(); let result = server.serializerOrRegistry.serialize(fineComments); expect(result).toEqual({ data: [ { type: "fine-comments", id: "1", attributes: { text: "pwned", }, relationships: { post: { data: { type: "blog-posts", id: "1" }, }, }, }, ], included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { author: { data: { type: "word-smiths", id: "1" }, }, }, }, { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, ], }); }); test(`it propertly serializes complex relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["author", "comments"], }), wordSmith: JSONAPISerializer.extend({ include: ["posts"], }), fineComment: JSONAPISerializer.extend({ include: ["post"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let post = link.createPost({ title: "Lorem" }); post.createComment({ text: "pwned" }); link.createPost({ title: "Ipsum" }); server.schema.wordSmiths.create({ firstName: "Zelda" }); let blogPost = server.schema.blogPosts.find(1); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { author: { data: { type: "word-smiths", id: "1" }, }, comments: { data: [{ type: "fine-comments", id: "1" }], }, }, }, included: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { posts: { data: [ { id: "1", type: "blog-posts", }, { id: "2", type: "blog-posts", }, ], }, }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, relationships: { author: { data: { type: "word-smiths", id: "1" }, }, comments: { data: [], }, }, }, { type: "fine-comments", id: "1", attributes: { text: "pwned", }, relationships: { post: { data: { id: "1", type: "blog-posts", }, }, }, }, ], }); }); }); includes-test.js000066400000000000000000000317611412317504700344250ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associationsimport { Server, JSONAPISerializer, Model, hasMany, belongsTo } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Associations | Includes", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), fineComments: hasMany(), }), fineComment: Model.extend({ blogPost: belongsTo(), category: belongsTo(), }), category: Model.extend({ labels: hasMany(), }), label: Model.extend({}), }, }); }); afterEach(() => { server.shutdown(); }); test("includes get serialized with correct serializer", () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ attrs: ["title"], include: ["wordSmith"], }), wordSmith: JSONAPISerializer.extend({ attrs: ["firstName"], }), }, }); let post = server.schema.blogPosts.create({ title: "We love Mirage!" }); post.createWordSmith({ firstName: "Sam" }); let result = server.serializerOrRegistry.serialize(post); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "We love Mirage!", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, }, }, included: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Sam", }, }, ], }); }); test("includes can be a function", () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ attrs: ["title"], include() { return ["wordSmith"]; }, }), wordSmith: JSONAPISerializer.extend({ attrs: ["firstName"], }), }, }); let post = server.schema.blogPosts.create({ title: "We love Mirage!" }); post.createWordSmith({ firstName: "Sam" }); let result = server.serializerOrRegistry.serialize(post); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "We love Mirage!", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, }, }, included: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Sam", }, }, ], }); }); test("query param includes work when serializing a model", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); let post = server.schema.blogPosts.create(); post.createWordSmith(); post.createFineComment(); post.createFineComment(); let request = { queryParams: { include: "word-smith,fine-comments", }, }; let result = server.serializerOrRegistry.serialize(post, request); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: {}, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [ { type: "fine-comments", id: "1" }, { type: "fine-comments", id: "2" }, ], }, }, }, included: [ { type: "word-smiths", id: "1", attributes: {}, }, { type: "fine-comments", id: "1", attributes: {}, }, { type: "fine-comments", id: "2", attributes: {}, }, ], }); }); test("query param includes work when serializing a collection", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); let post1 = server.schema.blogPosts.create(); post1.createWordSmith(); post1.createFineComment(); post1.createFineComment(); server.schema.blogPosts.create(); let request = { queryParams: { include: "word-smith,fine-comments", }, }; let result = server.serializerOrRegistry.serialize( server.schema.blogPosts.all(), request ); expect(result).toEqual({ data: [ { type: "blog-posts", id: "1", attributes: {}, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [ { type: "fine-comments", id: "1" }, { type: "fine-comments", id: "2" }, ], }, }, }, { type: "blog-posts", id: "2", attributes: {}, relationships: { "word-smith": { data: null, }, "fine-comments": { data: [], }, }, }, ], included: [ { type: "word-smiths", id: "1", attributes: {}, }, { type: "fine-comments", id: "1", attributes: {}, }, { type: "fine-comments", id: "2", attributes: {}, }, ], }); }); test("query param includes take precedence over default server includes", () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["wordSmith"], }), }, }); let post = server.schema.blogPosts.create(); post.createWordSmith(); post.createFineComment(); post.createFineComment(); let request = { queryParams: { include: "fine-comments", }, }; let result = server.serializerOrRegistry.serialize(post, request); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: {}, relationships: { "fine-comments": { data: [ { type: "fine-comments", id: "1" }, { type: "fine-comments", id: "2" }, ], }, }, }, included: [ { type: "fine-comments", id: "1", attributes: {}, }, { type: "fine-comments", id: "2", attributes: {}, }, ], }); }); test("query param includes support dot-paths when serializing a model", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); server.schema.db.loadData({ wordSmiths: [{ id: 1, name: "Sam", blogPostIds: [2] }], blogPosts: [ { id: 2, wordSmithId: 1, fineCommentIds: [3], title: "Lorem Ipsum" }, ], fineComments: [{ id: 3, text: "Foo", blogPostId: 2, categoryId: 10 }], categories: [{ id: 10, foo: "bar", labelIds: [20] }], labels: [{ id: 20, name: "Economics" }], }); let request = { queryParams: { include: "word-smith,fine-comments.category.labels", }, }; let result = server.serializerOrRegistry.serialize( server.schema.blogPosts.first(), request ); expect(result).toEqual({ data: { type: "blog-posts", id: "2", attributes: { title: "Lorem Ipsum", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [{ type: "fine-comments", id: "3" }], }, }, }, included: [ { type: "word-smiths", id: "1", attributes: { name: "Sam", }, }, { type: "fine-comments", id: "3", attributes: { text: "Foo", }, relationships: { category: { data: { type: "categories", id: "10" }, }, }, }, { type: "categories", id: "10", attributes: { foo: "bar", }, relationships: { labels: { data: [{ type: "labels", id: "20" }], }, }, }, { type: "labels", id: "20", attributes: { name: "Economics", }, }, ], }); }); test("query param includes support dot-paths when serializing a collection", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); server.schema.db.loadData({ wordSmiths: [{ id: 1, name: "Sam", blogPostIds: [2, 5] }], blogPosts: [ { id: 2, wordSmithId: 1, fineCommentIds: [3], title: "Lorem Ipsum" }, { id: 5, wordSmithId: 1, title: "Dolor" }, ], fineComments: [{ id: 3, text: "Foo", blogPostId: 2, categoryId: 10 }], categories: [{ id: 10, foo: "bar", labelIds: [20] }], labels: [{ id: 20, name: "Economics" }], }); let request = { queryParams: { include: "word-smith,fine-comments.category.labels", }, }; let result = server.serializerOrRegistry.serialize( server.schema.blogPosts.all(), request ); expect(result).toEqual({ data: [ { type: "blog-posts", id: "2", attributes: { title: "Lorem Ipsum", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [{ type: "fine-comments", id: "3" }], }, }, }, { type: "blog-posts", id: "5", attributes: { title: "Dolor", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [], }, }, }, ], included: [ { type: "word-smiths", id: "1", attributes: { name: "Sam", }, }, { type: "fine-comments", id: "3", attributes: { text: "Foo", }, relationships: { category: { data: { type: "categories", id: "10" }, }, }, }, { type: "categories", id: "10", attributes: { foo: "bar", }, relationships: { labels: { data: [{ type: "labels", id: "20" }], }, }, }, { type: "labels", id: "20", attributes: { name: "Economics", }, }, ], }); }); test("queryParamIncludes throws if including something that is not an association", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); server.schema.db.loadData({ blogPosts: [{ id: 2, title: "Lorem Ipsum" }], }); let request = { queryParams: { include: "title", }, }; expect(() => { server.serializerOrRegistry.serialize( server.schema.blogPosts.first(), request ); }).toThrow(); }); test("Do not return includes when queryParamIncludes is empty", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); let post = server.schema.blogPosts.create(); let request = { queryParams: { include: " ", }, }; let result = server.serializerOrRegistry.serialize(post, request); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: {}, }, }); }); test("Do not throw when queryParamIncludes has a trailing comma", () => { server.config({ serializers: { application: JSONAPISerializer, }, }); let post = server.schema.blogPosts.create(); post.createWordSmith({ name: "Sam" }); let request = { queryParams: { include: "word-smith,", }, }; let result = server.serializerOrRegistry.serialize(post, request); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: {}, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, }, }, included: [ { type: "word-smiths", id: "1", attributes: { name: "Sam", }, }, ], }); }); }); key-for-relationship-test.js000066400000000000000000000031521412317504700366630ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associationsimport { Server, Model, hasMany, JSONAPISerializer } from "miragejs"; import snakeCase from "lodash.snakecase"; describe("External | Shared | Serializers | JSON API Serializer | Key for relationship", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model, }, }); }); afterEach(() => { server.shutdown(); }); test(`keyForRelationship works`, () => { let ApplicationSerializer = JSONAPISerializer.extend({ keyForRelationship(key) { return snakeCase(key); }, }); server.config({ serializers: { application: ApplicationSerializer, wordSmith: ApplicationSerializer.extend({ include: ["blogPosts"], }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, firstName: "Link", lastName: "Jackson", age: 323, }); wordSmith.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { age: 323, "first-name": "Link", "last-name": "Jackson", }, relationships: { blog_posts: { data: [{ id: "1", type: "blog-posts" }], }, }, }, included: [ { attributes: { title: "Lorem ipsum", }, id: "1", type: "blog-posts", }, ], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associations/links-test.js000066400000000000000000000076421412317504700340170ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Associations | Links", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), fineComments: hasMany(), }), fineComment: Model.extend({ blogPost: belongsTo(), }), }, }); }); afterEach(() => { server.shutdown(); }); test(`it supports links`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ links(model) { return { wordSmith: { related: `/api/word_smiths/${model.wordSmith.id}`, self: `/api/blog_posts/${model.id}/relationships/word_smith`, }, fineComments: { related: `/api/fine_comments?blog_post_id=${model.id}`, self: `/api/blog_posts/${model.id}/relationships/fine_comments`, }, }; }, }), }, }); let link = server.schema.wordSmiths.create({ id: 3, name: "Link" }); // specify id to really test our links function let blogPost = link.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ data: { type: "blog-posts", id: blogPost.id, attributes: { title: "Lorem ipsum", }, relationships: { "word-smith": { links: { related: `/api/word_smiths/${link.id}`, self: `/api/blog_posts/${blogPost.id}/relationships/word_smith`, }, }, "fine-comments": { links: { related: `/api/fine_comments?blog_post_id=${blogPost.id}`, self: `/api/blog_posts/${blogPost.id}/relationships/fine_comments`, }, }, }, }, }); }); test(`it supports links alongside data linkage`, () => { let ApplicationSerializer = JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }); server.config({ serializers: { application: ApplicationSerializer, blogPost: ApplicationSerializer.extend({ links(model) { return { wordSmith: { related: `/api/word_smiths/${model.wordSmith.id}`, self: `/api/blog_posts/${model.id}/relationships/word_smith`, }, fineComments: { related: `/api/fine_comments?blog_post_id=${model.id}`, self: `/api/blog_posts/${model.id}/relationships/fine_comments`, }, }; }, }), }, }); let link = server.schema.wordSmiths.create({ id: 3, name: "Link" }); // specify id to really test our links function let blogPost = link.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ data: { type: "blog-posts", id: blogPost.id, attributes: { title: "Lorem ipsum", }, relationships: { "word-smith": { data: { id: "3", type: "word-smiths", }, links: { related: `/api/word_smiths/${link.id}`, self: `/api/blog_posts/${blogPost.id}/relationships/word_smith`, }, }, "fine-comments": { data: [], links: { related: `/api/fine_comments?blog_post_id=${blogPost.id}`, self: `/api/blog_posts/${blogPost.id}/relationships/fine_comments`, }, }, }, }, }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associations/model-test.js000066400000000000000000000302611412317504700337700ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Associations | Model", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), fineComments: hasMany(), }), fineComment: Model.extend({ blogPost: belongsTo(), }), }, }); }); afterEach(() => { server.shutdown(); }); test(`by default, it doesn't include a model's relationships if those relationships are not included in the document and no links are defined`, () => { server.config({ serializers: { application: JSONAPISerializer, }, }); let link = server.schema.wordSmiths.create({ firstName: "Link", age: 123, }); let post = link.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(post); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem ipsum", }, }, }); }); test(`when alwaysIncludeLinkageData is true, it contains linkage data for all a model's relationships, regardless of includes`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link", age: 123, }); let post = link.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(post); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem ipsum", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1", }, }, "fine-comments": { data: [], }, }, }, }); }); test(`when shouldIncludeLinkageData returns true for a certain belongsTo relationship, it contains linkage data for that relationship, regardless of includes`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ shouldIncludeLinkageData(relationshipName, model) { if (relationshipName === "wordSmith") { return true; } }, }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link", age: 123, }); let post = link.createBlogPost({ title: "Lorem ipsum" }); let result = server.serializerOrRegistry.serialize(post); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem ipsum", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1", }, }, }, }, }); }); test(`when shouldIncludeLinkageData returns true for a certain hasMany relationship, it contains linkage data for that relationship, regardless of includes`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ shouldIncludeLinkageData(relationshipName, model) { if (relationshipName === "blogPosts") { return true; } }, }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); link.createBlogPost({ title: "Lorem" }); link.createBlogPost({ title: "Ipsum" }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { "blog-posts": { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, }, }); }); test(`it includes linkage data for a has-many relationship that's being included`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ include: ["blogPosts"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); link.createBlogPost({ title: "Lorem" }); link.createBlogPost({ title: "Ipsum" }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { "blog-posts": { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, }, included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, }, ], }); }); test(`it can include a chain of has-many relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ include: ["blogPosts"], }), blogPost: JSONAPISerializer.extend({ include: ["fineComments"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let post1 = link.createBlogPost({ title: "Lorem" }); post1.createFineComment({ text: "pwned" }); link.createBlogPost({ title: "Ipsum" }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, relationships: { "blog-posts": { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, }, included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { "fine-comments": { data: [{ type: "fine-comments", id: "1" }], }, }, }, { type: "fine-comments", id: "1", attributes: { text: "pwned", }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, relationships: { "fine-comments": { data: [], }, }, }, ], }); }); test(`it can include a belongs-to relationship`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["wordSmith"], }), }, }); let link = server.schema.wordSmiths.create({ firstName: "Link" }); let blogPost = link.createBlogPost({ title: "Lorem" }); blogPost.createFineComment(); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { "word-smith": { data: { id: "1", type: "word-smiths", }, }, }, }, included: [ { attributes: { "first-name": "Link", }, id: "1", type: "word-smiths", }, ], }); }); test(`it gracefully handles null belongs-to relationship`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["wordSmith"], }), }, }); let blogPost = server.schema.blogPosts.create({ title: "Lorem" }); let result = server.serializerOrRegistry.serialize(blogPost); expect(result).toEqual({ data: { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { "word-smith": { data: null, }, }, }, }); }); test(`it can include a chain of belongs-to relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, blogPost: JSONAPISerializer.extend({ include: ["wordSmith"], }), fineComment: JSONAPISerializer.extend({ include: ["blogPost"], }), }, }); let wordSmith = server.schema.wordSmiths.create({ firstName: "Link" }); let post = wordSmith.createBlogPost({ title: "Lorem" }); let comment = post.createFineComment({ text: "pwned" }); let result = server.serializerOrRegistry.serialize(comment); expect(result).toEqual({ data: { type: "fine-comments", id: "1", attributes: { text: "pwned", }, relationships: { "blog-post": { data: { id: "1", type: "blog-posts", }, }, }, }, included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1", }, }, }, }, { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, ], }); }); test(`it properly serializes complex relationships`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ include: ["blogPosts"], }), blogPost: JSONAPISerializer.extend({ include: ["wordSmith", "fineComments"], }), fineComment: JSONAPISerializer.extend({ include: ["blogPost"], }), }, }); let wordSmith = server.schema.wordSmiths.create({ firstName: "Link" }); let post = wordSmith.createBlogPost({ title: "Lorem" }); wordSmith.createBlogPost({ title: "Ipsum" }); post.createFineComment({ text: "pwned" }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ data: { attributes: { "first-name": "Link", }, id: "1", relationships: { "blog-posts": { data: [ { type: "blog-posts", id: "1" }, { type: "blog-posts", id: "2" }, ], }, }, type: "word-smiths", }, included: [ { type: "blog-posts", id: "1", attributes: { title: "Lorem", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [{ type: "fine-comments", id: "1" }], }, }, }, { type: "fine-comments", id: "1", attributes: { text: "pwned", }, relationships: { "blog-post": { data: { type: "blog-posts", id: "1" }, }, }, }, { type: "blog-posts", id: "2", attributes: { title: "Ipsum", }, relationships: { "word-smith": { data: { type: "word-smiths", id: "1" }, }, "fine-comments": { data: [], }, }, }, ], }); }); }); polymorphic-test.js000066400000000000000000000133041412317504700351550ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/associationsimport { Server, Model, belongsTo, hasMany, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Associations | Polymorphic", () => { test("it works for belongs to polymorphic relationships", () => { let server = new Server({ models: { photo: Model.extend(), video: Model.extend(), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }, serializers: { application: JSONAPISerializer, comment: JSONAPISerializer.extend({ include: ["commentable"], }), }, }); let schema = server.schema; let photo = schema.photos.create({ title: "Foo" }); schema.comments.create({ text: "Pretty foo!", commentable: photo }); let video = schema.videos.create({ title: "Bar" }); schema.comments.create({ text: "Love the bar!", commentable: video }); let result = server.serializerOrRegistry.serialize(schema.comments.all()); expect(result).toEqual({ data: [ { attributes: { text: "Pretty foo!", }, id: "1", relationships: { commentable: { data: { id: "1", type: "photos" }, }, }, type: "comments", }, { attributes: { text: "Love the bar!", }, id: "2", relationships: { commentable: { data: { id: "1", type: "videos" }, }, }, type: "comments", }, ], included: [ { attributes: { title: "Foo", }, id: "1", type: "photos", }, { attributes: { title: "Bar", }, id: "1", type: "videos", }, ], }); server.shutdown(); }); test("it works for has many polymorphic relationships", () => { let server = new Server({ models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), car: Model.extend(), watch: Model.extend(), }, serializers: { application: JSONAPISerializer, user: JSONAPISerializer.extend({ include: ["things"], }), }, }); let schema = server.schema; let car = schema.cars.create({ make: "Infiniti" }); let watch = schema.watches.create({ make: "Citizen" }); let user = schema.users.create({ name: "Sam", things: [car, watch], }); let json = server.serializerOrRegistry.serialize(user); expect(json).toEqual({ data: { attributes: { name: "Sam", }, id: "1", relationships: { things: { data: [ { id: "1", type: "cars" }, { id: "1", type: "watches" }, ], }, }, type: "users", }, included: [ { attributes: { make: "Infiniti", }, id: "1", type: "cars", }, { attributes: { make: "Citizen", }, id: "1", type: "watches", }, ], }); server.shutdown(); }); test("it works for has many polymorphic relationships included via query params", () => { let server = new Server({ models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), car: Model.extend(), watch: Model.extend(), }, serializers: { application: JSONAPISerializer, }, }); let schema = server.schema; let car = schema.cars.create({ make: "Infiniti" }); let watch = schema.watches.create({ make: "Citizen" }); let user = schema.users.create({ name: "Sam", things: [car, watch], }); let json = server.serializerOrRegistry.serialize(user, { queryParams: { include: "things" }, }); expect(json).toEqual({ data: { attributes: { name: "Sam", }, id: "1", relationships: { things: { data: [ { id: "1", type: "cars" }, { id: "1", type: "watches" }, ], }, }, type: "users", }, included: [ { attributes: { make: "Infiniti", }, id: "1", type: "cars", }, { attributes: { make: "Citizen", }, id: "1", type: "watches", }, ], }); server.shutdown(); }); test("it works for a top-level polymorphic collection", () => { let server = new Server({ models: { user: Model.extend({ things: hasMany({ polymorphic: true }), }), car: Model.extend(), watch: Model.extend(), }, serializers: { application: JSONAPISerializer, user: JSONAPISerializer.extend({ include: ["things"], }), }, }); let schema = server.schema; let car = schema.cars.create({ make: "Infiniti" }); let watch = schema.watches.create({ make: "Citizen" }); let user = schema.users.create({ name: "Sam", things: [car, watch], }); let json = server.serializerOrRegistry.serialize(user.things); expect(json).toEqual({ data: [ { attributes: { make: "Infiniti", }, id: "1", type: "cars", }, { attributes: { make: "Citizen", }, id: "1", type: "watches", }, ], }); server.shutdown(); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/attrs-test.js000066400000000000000000000054631412317504700313340ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Attrs List", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model, photograph: Model, }, }); }); afterEach(() => { server.shutdown(); }); test(`it returns only the whitelisted attrs when serializing a model`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ attrs: ["firstName"], }), }, }); let user = server.schema.wordSmiths.create({ id: 1, firstName: "Link", age: 123, }); let result = server.serializerOrRegistry.serialize(user); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, }); }); test(`it returns only the whitelisted attrs when serializing a collection`, () => { server.config({ serializers: { application: JSONAPISerializer, wordSmith: JSONAPISerializer.extend({ attrs: ["firstName"], }), }, }); server.schema.wordSmiths.create({ id: 1, firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ id: 2, firstName: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", }, }, ], }); }); test(`it can use different attr whitelists for different serializers`, () => { server.config({ serializers: { wordSmith: JSONAPISerializer.extend({ attrs: ["firstName"], }), photograph: JSONAPISerializer.extend({ attrs: ["title"], }), }, }); let link = server.schema.wordSmiths.create({ id: 1, firstName: "Link", age: 123, }); expect(server.serializerOrRegistry.serialize(link)).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", }, }, }); let photo = server.schema.photographs.create({ id: 1, title: "Lorem ipsum", createdAt: "2010-01-01", }); expect(server.serializerOrRegistry.serialize(photo)).toEqual({ data: { type: "photographs", id: "1", attributes: { title: "Lorem ipsum", }, }, }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/base-test.js000066400000000000000000000034721412317504700311070ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; describe("External | Shared | Serializers | JSON API Serializer | Base", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model, }, serializers: { application: JSONAPISerializer, }, }); }); afterEach(() => { server.shutdown(); }); test(`it includes all attributes for a model`, () => { let link = server.schema.wordSmiths.create({ firstName: "Link", age: 123 }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { "first-name": "Link", age: 123, }, }, }); }); test(`it includes all attributes for each model in a collection`, () => { server.schema.wordSmiths.create({ firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ id: 1, firstName: "Link", age: 123 }); server.schema.wordSmiths.create({ id: 2, firstName: "Zelda", age: 456 }); let collection = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(collection); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { "first-name": "Link", age: 123, }, }, { type: "word-smiths", id: "2", attributes: { "first-name": "Zelda", age: 456, }, }, ], }); }); test(`it can serialize an empty collection`, () => { let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ data: [], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/json-api-serializer/key-formatting-test.js000066400000000000000000000041371412317504700331340ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; import snakeCase from "lodash.snakecase"; describe("External | Shared | Serializers | JSON API Serializer | Key Formatting", () => { let server; beforeEach(() => { server = new Server({ models: { wordSmith: Model, photograph: Model, }, }); }); afterEach(() => { server.shutdown(); }); test(`keyForAttribute formats the attributes of a model`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ keyForAttribute(key) { return snakeCase(key); }, }), }, }); let wordSmith = server.schema.wordSmiths.create({ id: 1, firstName: "Link", lastName: "Jackson", age: 323, }); let result = server.serializerOrRegistry.serialize(wordSmith); expect(result).toEqual({ data: { type: "word-smiths", id: "1", attributes: { age: 323, first_name: "Link", last_name: "Jackson", }, }, }); }); test(`keyForAttribute also formats the models in a collections`, () => { server.config({ serializers: { application: JSONAPISerializer.extend({ keyForAttribute(key) { return snakeCase(key); }, }), }, }); server.schema.wordSmiths.create({ id: 1, firstName: "Link", lastName: "Jackson", }); server.schema.wordSmiths.create({ id: 2, firstName: "Zelda", lastName: "Brown", }); let wordSmiths = server.schema.wordSmiths.all(); let result = server.serializerOrRegistry.serialize(wordSmiths); expect(result).toEqual({ data: [ { type: "word-smiths", id: "1", attributes: { first_name: "Link", last_name: "Jackson", }, }, { type: "word-smiths", id: "2", attributes: { first_name: "Zelda", last_name: "Brown", }, }, ], }); }); }); miragejs-0.1.42/__tests__/external/shared/serializers/rest-serializer-test.js000066400000000000000000000043251412317504700274300ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, RestSerializer } from "miragejs"; describe("External | Shared | Serializers | RestSerializer", () => { let server; afterEach(function () { server.shutdown(); }); test("it sideloads associations and camel-cases relationships and attributes correctly for a model", () => { server = new Server({ environment: "test", models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), }), }, serializers: { application: RestSerializer, wordSmith: RestSerializer.extend({ attrs: ["id", "name"], include: ["blogPosts"], }), blogPost: RestSerializer.extend({ include: ["wordSmith"], }), }, }); let link = server.create("word-smith", { name: "Link", age: 123 }); link.createBlogPost({ title: "Lorem" }); link.createBlogPost({ title: "Ipsum" }); server.create("word-smith", { name: "Zelda", age: 230 }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", blogPosts: ["1", "2"], }, blogPosts: [ { id: "1", title: "Lorem", wordSmith: "1", }, { id: "2", title: "Ipsum", wordSmith: "1", }, ], }); }); test("it works for has-many polymorphic associations", () => { server = new Server({ environment: "test", models: { wordSmith: Model.extend({ posts: hasMany({ polymorphic: true }), }), blogPost: Model.extend(), }, serializers: { application: RestSerializer, }, }); let post = server.create("blog-post", { title: "Post 1" }); let link = server.create("word-smith", { name: "Link", age: 123, posts: [post], }); let result = server.serializerOrRegistry.serialize(link); expect(result).toEqual({ wordSmith: { id: "1", name: "Link", age: 123, posts: [{ id: "1", type: "blog-post" }], }, }); }); }); miragejs-0.1.42/__tests__/external/shared/server/000077500000000000000000000000001412317504700217375ustar00rootroot00000000000000miragejs-0.1.42/__tests__/external/shared/server/load-fixtures-test.js000066400000000000000000000030011412317504700260320ustar00rootroot00000000000000import { Server } from "miragejs"; describe("External | Shared | Server | loadFixtures", () => { let server; beforeEach(() => { server = new Server({ environment: "test", factories: { author: {}, post: {}, comment: {}, }, fixtures: { authors: [ { id: 1, name: "Zelda" }, { id: 2, name: "Link" }, ], posts: [ { id: 1, title: "Lorem" }, { id: 2, title: "Ipsum" }, ], comments: [{ id: 1, title: "Lorem" }], }, }); }); afterEach(function () { server.shutdown(); }); test("it can load all fixtures in the map", () => { server.loadFixtures(); expect(server.db.authors).toHaveLength(2); expect(server.db.posts).toHaveLength(2); expect(server.db.comments).toHaveLength(1); }); test("it can load a single named fixture file", () => { server.loadFixtures("authors"); expect(server.db.authors).toHaveLength(2); expect(server.db.posts).toHaveLength(0); expect(server.db.comments).toHaveLength(0); }); test("it can load several named single fixtures", () => { server.loadFixtures("authors", "posts"); expect(server.db.authors).toHaveLength(2); expect(server.db.posts).toHaveLength(2); expect(server.db.comments).toHaveLength(0); }); test("it throws on a non-existing file name", () => { expect(() => server.loadFixtures("authors", "zomg", "posts", "lol") ).toThrow("Fixtures not found: zomg, lol"); }); }); miragejs-0.1.42/__tests__/external/shared/server/seeds-test.js000066400000000000000000000017361412317504700243640ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("External | Shared | Server | seeds", () => { let server; afterEach(function () { server.shutdown(); }); test("seeds config option works", async () => { server = new Server({ models: { user: Model, }, seeds(server) { server.createList("user", 3); }, }); expect(server.db.dump()).toEqual({ users: [{ id: "1" }, { id: "2" }, { id: "3" }], }); }); test("there's an error if both scenarios default and seeds options are passed in", async () => { expect(() => { new Server({ environment: "test", seeds(server) { server.create("user"); }, scenarios: { default(server) { server.create("user"); }, }, }); }).toThrow( "The seeds option is an alias for the scenarios.default option. You can't pass both options into your server definition." ); }); }); miragejs-0.1.42/__tests__/internal/000077500000000000000000000000001412317504700171555ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/integration/000077500000000000000000000000001412317504700215005ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/integration/performance/000077500000000000000000000000001412317504700240015ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/integration/performance/simple-factory-test.js000066400000000000000000000022031412317504700302470ustar00rootroot00000000000000import { Server, Model, Factory } from "miragejs"; describe("Internal | Integration | Performance | Simple factory test", () => { let server; beforeEach(() => { server = new Server({ environment: "test", models: { car: Model, }, factories: { car: Factory.extend({ make: "Fjord", model: "Wagon", year: "1886", }), }, }); server.timing = 0; server.logging = false; }); afterEach(() => { server.shutdown(); }); const carMaker = (count) => { server.createList("car", count); }; perfTest(50, "models", carMaker); perfTest(500, "models", carMaker); perfTest(5000, "models", carMaker); }); function perfTest(count, message, testFn, timeout = 0) { test(`(${count}) ${message}`, () => { let duration = time(() => { testFn(count); }); if (timeout) { expect(duration).toBeLessThan(timeout); } else { expect(`${duration}ms`).toBeTruthy(); } }); } function time(fn) { let start = now(); fn(); return now() - start; } function now() { return Date.now ? Date.now() : +new Date(); } miragejs-0.1.42/__tests__/internal/integration/schema/000077500000000000000000000000001412317504700227405ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/integration/schema/schema-verification/000077500000000000000000000000001412317504700266605ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/integration/schema/schema-verification/belongs-to-test.js000066400000000000000000000130641412317504700322500ustar00rootroot00000000000000import "@lib/container"; import Db from "@lib/db"; import Schema from "@lib/orm/schema"; import { Model, belongsTo } from "miragejs"; describe("Internal | Integration | Schema | Schema Verification | Belongs To", function () { test("a one-way belongsTo association is correct", () => { let schema = new Schema( new Db({ authors: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem ipsum" }], }), { author: Model.extend(), post: Model.extend({ author: belongsTo(), }), } ); let post = schema.posts.find(1); let association = post.associationFor("author"); let frodo = schema.authors.find(1); expect(association.name).toEqual("author"); expect(association.modelName).toEqual("author"); expect(association.ownerModelName).toEqual("post"); expect(frodo.inverseFor(association) === null).toBeTruthy(); }); test("a one-way named belongsTo association is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem ipsum" }], }), { user: Model.extend(), post: Model.extend({ author: belongsTo("user"), }), } ); let post = schema.posts.find(1); let association = post.associationFor("author"); let frodo = schema.users.find(1); expect(association.name).toEqual("author"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("post"); expect(frodo.inverseFor(association) === null).toBeTruthy(); }); test("a reflexive belongsTo association is correct and has an implicit inverse", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ user: belongsTo(), }), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("user"); expect(association.name).toEqual("user"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("user"); expect(frodo.inverseFor(association) === association).toBeTruthy(); }); test("a named reflexive belongsTo association with an implicit inverse is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ bestFriend: belongsTo("user"), }), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("bestFriend"); expect(association.name).toEqual("bestFriend"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("user"); expect(frodo.inverseFor(association) === association).toBeTruthy(); }); test("a named reflexive belongsTo association with an explicit inverse is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ bestFriend: belongsTo("user", { inverse: "bestFriend" }), }), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("bestFriend"); expect(association.name).toEqual("bestFriend"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("user"); expect(frodo.inverseFor(association) === association).toBeTruthy(); }); test("a one-way reflexive belongsTo association with a null inverse is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ user: belongsTo("user", { inverse: null }), }), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("user"); expect(association.name).toEqual("user"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("user"); expect(frodo.inverseFor(association) === null).toBeTruthy(); }); test("a named one-way way reflexive belongsTo association with a null inverse is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ parent: belongsTo("user", { inverse: null }), }), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("parent"); expect(association.name).toEqual("parent"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("user"); expect(frodo.inverseFor(association) === null).toBeTruthy(); }); test("a one-to-one belongsTo association with an implicit inverse is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], profiles: [{ id: 1, type: "Admin" }], }), { user: Model.extend({ profile: belongsTo(), }), profile: Model.extend({ user: belongsTo(), }), } ); let admin = schema.profiles.find(1); let association = admin.associationFor("user"); expect(association.name).toEqual("user"); expect(association.modelName).toEqual("user"); expect(association.ownerModelName).toEqual("profile"); let frodo = schema.users.find(1); let inverse = frodo.inverseFor(association); expect(inverse.name).toEqual("profile"); expect(inverse.modelName).toEqual("profile"); expect(inverse.ownerModelName).toEqual("user"); }); }); miragejs-0.1.42/__tests__/internal/integration/schema/schema-verification/has-many-test.js000066400000000000000000000042151412317504700317120ustar00rootroot00000000000000import "@lib/container"; import Db from "@lib/db"; import Schema from "@lib/orm/schema"; import { Model, hasMany } from "miragejs"; describe("Integration | ORM | Schema Verification | Has Many", function () { test("a one-way has many association is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ posts: hasMany(), }), post: Model.extend(), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("posts"); expect(association.name).toEqual("posts"); expect(association.modelName).toEqual("post"); expect(association.ownerModelName).toEqual("user"); let post = schema.posts.find(1); expect(post.inverseFor(association) === null).toBeTruthy(); }); test("a named one-way has many association is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ blogPosts: hasMany("post"), }), post: Model.extend(), } ); let frodo = schema.users.find(1); let association = frodo.associationFor("blogPosts"); expect(association.name).toEqual("blogPosts"); expect(association.modelName).toEqual("post"); expect(association.ownerModelName).toEqual("user"); let post = schema.posts.find(1); expect(post.inverseFor(association) === null).toBeTruthy(); }); test("a reflexive hasMany association with an implicit inverse is correct", () => { let schema = new Schema( new Db({ tags: [{ id: 1, name: "economics" }], }), { tag: Model.extend({ tags: hasMany(), }), } ); let tag = schema.tags.find(1); let association = tag.associationFor("tags"); expect(association.name).toEqual("tags"); expect(association.modelName).toEqual("tag"); expect(association.ownerModelName).toEqual("tag"); expect(tag.inverseFor(association) === association).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/integration/schema/schema-verification/mixed-test.js000066400000000000000000000215451412317504700313100ustar00rootroot00000000000000import "@lib/container"; import Db from "@lib/db"; import Schema from "@lib/orm/schema"; import { Model, hasMany, belongsTo } from "miragejs"; describe("Integration | ORM | Schema Verification | Mixed", function () { test("unnamed one-to-many associations are correct", () => { let schema = new Schema( new Db({ wordSmiths: [{ id: 1, name: "Frodo" }], blogPosts: [{ id: 1, title: "Lorem" }], }), { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ wordSmith: belongsTo(), }), } ); let frodo = schema.wordSmiths.find(1); let association = frodo.associationFor("blogPosts"); expect(association.name).toEqual("blogPosts"); expect(association.modelName).toEqual("blog-post"); expect(association.ownerModelName).toEqual("word-smith"); let post = schema.blogPosts.find(1); expect(post.inverseFor(association)).toEqual( post.associationFor("wordSmith") ); }); test("a named one-to-many association is correct", () => { let schema = new Schema( new Db({ wordSmiths: [{ id: 1, name: "Frodo" }], blogPosts: [{ id: 1, title: "Lorem" }], }), { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), }), } ); let frodo = schema.wordSmiths.find(1); let association = frodo.associationFor("posts"); expect(association.name).toEqual("posts"); expect(association.modelName).toEqual("blog-post"); expect(association.ownerModelName).toEqual("word-smith"); let post = schema.blogPosts.find(1); expect(post.inverseFor(association)).toEqual(post.associationFor("author")); }); test("multiple has-many associations of the same type", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ notes: hasMany("post", { inverse: "author" }), messages: hasMany("post", { inverse: "messenger" }), }), post: Model.extend({ author: belongsTo("user", { inverse: "notes" }), messenger: belongsTo("user", { inverse: "messages" }), }), } ); let frodo = schema.users.find(1); let notesAssociation = frodo.associationFor("notes"); expect(notesAssociation.name).toEqual("notes"); expect(notesAssociation.modelName).toEqual("post"); expect(notesAssociation.ownerModelName).toEqual("user"); let post = schema.posts.find(1); expect(post.inverseFor(notesAssociation)).toEqual( post.associationFor("author") ); let messagesAssociation = frodo.associationFor("messages"); expect(messagesAssociation.name).toEqual("messages"); expect(messagesAssociation.modelName).toEqual("post"); expect(messagesAssociation.ownerModelName).toEqual("user"); expect(post.inverseFor(messagesAssociation)).toEqual( post.associationFor("messenger") ); }); test("one-to-many reflexive association is correct", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], }), { user: Model.extend({ parent: belongsTo("user", { inverse: "children" }), children: hasMany("user", { inverse: "parent" }), }), } ); let frodo = schema.users.find(1); let parentAssociation = frodo.associationFor("parent"); expect(parentAssociation.name).toEqual("parent"); expect(parentAssociation.modelName).toEqual("user"); expect(parentAssociation.ownerModelName).toEqual("user"); expect(frodo.inverseFor(parentAssociation)).toEqual( frodo.associationFor("children") ); }); test("one-to-many polymorphic association is correct", () => { let schema = new Schema( new Db({ authors: [{ id: 1, name: "Peter" }], posts: [{ id: 1, title: "Lorem" }], articles: [{ id: 1, title: "Ipsum" }], }), { author: Model.extend({ writings: hasMany({ polymorphic: true }), }), post: Model.extend({ author: belongsTo("author", { inverse: "writings" }), }), article: Model.extend({ author: belongsTo("author", { inverse: "writings" }), }), } ); let author = schema.authors.find(1); let writingsAssociation = author.associationFor("writings"); let post = schema.posts.find(1); let postAuthorAssociation = post.associationFor("author"); let article = schema.articles.find(1); let articleAuthorAssociation = article.associationFor("author"); expect(post.inverseFor(writingsAssociation)).toEqual(postAuthorAssociation); expect(article.inverseFor(writingsAssociation)).toEqual( articleAuthorAssociation ); expect(author.inverseFor(postAuthorAssociation)).toEqual( writingsAssociation ); expect(author.inverseFor(postAuthorAssociation)).toEqual( writingsAssociation ); }); test("multiple implicit inverse associations with the same key throws an error", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ posts: hasMany("post"), }), post: Model.extend({ editor: belongsTo("user"), authors: hasMany("user"), }), } ); let frodo = schema.users.find(1); let userPostsAssociation = frodo.associationFor("posts"); let post = schema.posts.find(1); expect(function () { post.inverseFor(userPostsAssociation); }).toThrow(); }); test("multiple explicit inverse associations with the same key throws an error", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ posts: hasMany("post", { inverse: "authors" }), }), post: Model.extend({ editor: belongsTo("user", { inverse: "posts" }), authors: hasMany("user", { inverse: "posts" }), }), } ); let frodo = schema.users.find(1); let userPostsAssociation = frodo.associationFor("posts"); let post = schema.posts.find(1); expect(function () { post.inverseFor(userPostsAssociation); }).toThrow(); }); test("explicit inverse is chosen over implicit inverses", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], }), { user: Model.extend({ posts: hasMany("post", { inverse: "authors" }), }), post: Model.extend({ editor: belongsTo("user"), authors: hasMany("user", { inverse: "posts" }), }), } ); let frodo = schema.users.find(1); let userPostsAssociation = frodo.associationFor("posts"); expect(userPostsAssociation.name).toEqual("posts"); expect(userPostsAssociation.modelName).toEqual("post"); expect(userPostsAssociation.ownerModelName).toEqual("user"); let post = schema.posts.find(1); expect(post.inverseFor(userPostsAssociation)).toEqual( post.associationFor("authors") ); }); test("multiple explicit inverse associations with the same key but different models does not throw an error", () => { let schema = new Schema( new Db({ users: [{ id: 1, name: "Frodo" }], posts: [{ id: 1, title: "Lorem" }], books: [{ id: 1, title: "Ipsum" }], }), { user: Model.extend({ authoredPosts: hasMany("post", { inverse: "authors" }), authoredBooks: hasMany("book", { inverse: "authors" }), }), post: Model.extend({ authors: hasMany("user", { inverse: "authoredPosts" }), }), book: Model.extend({ authors: hasMany("user", { inverse: "authoredBooks" }), }), } ); let frodo = schema.users.find(1); let post = schema.posts.find(1); let book = schema.books.find(1); let userAuthoredPostsAssociation = frodo.associationFor("authoredPosts"); let userAuthoredBooksAssociation = frodo.associationFor("authoredBooks"); let postsAuthorsAssociation = post.associationFor("authors"); let bookAuthorsAssociation = book.associationFor("authors"); expect(post.inverseFor(userAuthoredPostsAssociation)).toEqual( post.associationFor("authors") ); expect(book.inverseFor(userAuthoredBooksAssociation)).toEqual( book.associationFor("authors") ); expect(frodo.inverseFor(postsAuthorsAssociation)).toEqual( frodo.associationFor("authoredPosts") ); expect(frodo.inverseFor(bookAuthorsAssociation)).toEqual( frodo.associationFor("authoredBooks") ); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/000077500000000000000000000000001412317504700241415ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/custom-responses-test.js000066400000000000000000000030621412317504700310060ustar00rootroot00000000000000import { Server, Response } from "miragejs"; describe("Integration | Server | Custom responses", function () { let server; beforeEach(function () { server = new Server({ environment: "test", }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("GET to an empty Response defaults to 200 and an empty json object", async () => { server.get("/example", function () { return new Response(); }); let res = await fetch("/example"); let data = await res.json(); expect(data).toEqual({}); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); test("GET to a 200 Response responds with an empty json object", async () => { server.get("/example", function () { return new Response(200); }); let res = await fetch("/example"); let data = await res.json(); expect(data).toEqual({}); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); test("a 204 Response responds with an empty body", async () => { server.post("/example", function () { return new Response(204); }); let res = await fetch("/example", { method: "POST" }); let text = await res.text(); expect(text).toEqual(""); expect(res.status).toEqual(204); expect([...res.headers.entries()]).toEqual([ ["content-type", "text/plain;charset=UTF-8"], ]); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/customized-normalize-method-test.js000066400000000000000000000043471412317504700331260ustar00rootroot00000000000000import { Server, Model, ActiveModelSerializer } from "miragejs"; import { camelize } from "@lib/utils/inflector"; describe("Integration | Server | Customized normalize method", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { contact: Model, }, serializers: { application: ActiveModelSerializer, contact: ActiveModelSerializer.extend({ normalize(payload) { let attrs = payload.some.random[1].attrs; Object.keys(attrs).forEach(camelize); let jsonApiDoc = { data: { type: "contacts", attributes: attrs, }, }; return jsonApiDoc; }, }), }, }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("custom model-specific normalize functions are used", async () => { expect.assertions(3); server.post("/contacts"); let res = await fetch("/contacts", { method: "POST", body: JSON.stringify({ some: { random: [ { format: true, }, { attrs: { first_name: "Zelda", }, }, ], }, }), }); expect(res.status).toEqual(201); expect(server.db.contacts).toHaveLength(1); expect(server.db.contacts[0].firstName).toEqual("Zelda"); }); test("custom model-specific normalize functions are used with custom function handlers", async () => { server.put("/contacts/:id", function (schema, request) { let attrs = this.normalizedRequestAttrs(); expect(attrs).toEqual({ id: "1", firstName: "Zelda", }); return {}; }); await fetch("/contacts/1", { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ some: { random: [ { format: true, }, { attrs: { first_name: "Zelda", }, }, ], }, }), }); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/falsy-responses-test.js000066400000000000000000000035251412317504700306160ustar00rootroot00000000000000import { Server } from "miragejs"; describe("Integration | Server | Falsy responses", function () { let server; beforeEach(function () { server = new Server({ environment: "test", }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("undefined response returns an empty object", async () => { server.get("/example", function () { return undefined; }); let res = await fetch("/example"); let data = await res.json(); expect(data).toEqual({}); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); test("null response returns a JSON null", async () => { server.get("/example", function () { return null; }); let res = await fetch("/example"); let data = await res.json(); expect(data).toBeNull(); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); test("empty string response returns an empty object", async () => { server.get("/example", function () { return ""; }); let res = await fetch("/example"); let data = await res.json(); expect(data).toEqual({}); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); test("empty object PUT response returns an empty object", async () => { server.put("/example", function () { return {}; }); let res = await fetch("/example", { method: "PUT" }); let data = await res.json(); expect(data).toEqual({}); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([ ["content-type", "application/json"], ]); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/full-request-test.js000066400000000000000000000062701412317504700301110ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("External | Shared | Serializers | Base | Full Request", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { author: Model.extend({ posts: hasMany(), }), post: Model.extend({ author: belongsTo(), comments: hasMany(), }), comment: Model.extend({ post: belongsTo(), }), }, serializers: { application: Serializer.extend({ embed: true, root: false, }), author: Serializer.extend({ embed: true, attrs: ["id", "first"], include: ["posts"], }), comment: Serializer.extend({ embed: true, root: false, include(request) { return request.queryParams.include_post ? ["post"] : []; }, }), }, }); }); afterEach(function () { server.shutdown(); }); test("the appropriate serializer is used", async () => { expect.assertions(1); let author = server.schema.authors.create({ first: "Link", last: "of Hyrule", age: 323, }); author.createPost({ title: "Lorem ipsum" }); server.get("/authors/:id", function (schema, request) { let { id } = request.params; return schema.authors.find(id); }); let res = await fetch("/authors/1"); let data = await res.json(); expect(data).toEqual({ author: { id: "1", first: "Link", posts: [{ id: "1", title: "Lorem ipsum" }], }, }); }); test("components decoded", async () => { expect.assertions(1); server.get("/authors/:id", function (schema, request) { let { id } = request.params; return { data: { id } }; }); let res = await fetch("/authors/%3A1"); let data = await res.json(); expect(data).toEqual({ data: { id: ":1" } }); }); test("a response falls back to the application serializer, if it exists", async () => { expect.assertions(1); server.schema.posts.create({ title: "Lorem", date: "20001010", }); server.get("/posts/:id", function (schema, request) { let { id } = request.params; return schema.posts.find(id); }); let res = await fetch("/posts/1"); let data = await res.json(); expect(data).toEqual({ id: "1", title: "Lorem", date: "20001010", }); }); test("serializer.include is invoked when it is a function", async () => { expect.assertions(1); let post = server.schema.posts.create({ title: "Lorem", date: "20001010", }); post.createComment({ description: "Lorem is the best", }); server.get("/comments/:id", function (schema, request) { let { id } = request.params; return schema.comments.find(id); }); let res = await fetch("/comments/1?include_post=true"); let data = await res.json(); expect(data).toEqual({ id: "1", description: "Lorem is the best", post: { id: "1", title: "Lorem", date: "20001010", }, }); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/get-full-path-test.js000066400000000000000000000051601412317504700301270ustar00rootroot00000000000000import { Server } from "miragejs"; describe("Integration | Server | Get full path", function () { let server; beforeEach(function () { server = new Server({ environment: "test", }); }); afterEach(function () { server.shutdown(); }); test("it works with a configured namespace with a leading slash", () => { expect.assertions(1); server.namespace = "/api"; expect(server._getFullPath("/contacts")).toEqual("/api/contacts"); }); test("it works with a configured namespace with a trailing slash", () => { expect.assertions(1); server.namespace = "api/"; expect(server._getFullPath("/contacts")).toEqual("/api/contacts"); }); test("it works with a configured namespace without a leading slash", () => { expect.assertions(1); server.namespace = "api"; expect(server._getFullPath("/contacts")).toEqual("/api/contacts"); }); test("it works with a configured namespace is an empty string", () => { expect.assertions(1); server.namespace = ""; expect(server._getFullPath("/contacts")).toEqual("/contacts"); }); test("it works with a configured urlPrefix with a trailing slash", () => { expect.assertions(1); server.urlPrefix = "http://localhost:3000/"; expect(server._getFullPath("/contacts")).toEqual( "http://localhost:3000/contacts" ); }); test("it works with a configured urlPrefix without a trailing slash", () => { expect.assertions(1); server.urlPrefix = "http://localhost:3000"; expect(server._getFullPath("/contacts")).toEqual( "http://localhost:3000/contacts" ); }); test("it works with a configured urlPrefix as an empty string", () => { expect.assertions(1); server.urlPrefix = ""; expect(server._getFullPath("/contacts")).toEqual("/contacts"); }); test("it works with a configured namespace and a urlPrefix", () => { expect.assertions(1); server.namespace = "api"; server.urlPrefix = "http://localhost:3000"; expect(server._getFullPath("/contacts")).toEqual( "http://localhost:3000/api/contacts" ); }); test("it works with a configured namespace with a leading slash and a urlPrefix", () => { expect.assertions(1); server.namespace = "/api"; server.urlPrefix = "http://localhost:3000"; expect(server._getFullPath("/contacts")).toEqual( "http://localhost:3000/api/contacts" ); }); test("it works with a configured namespace and a urlPrefix as empty strings", () => { expect.assertions(1); server.namespace = ""; server.urlPrefix = ""; expect(server._getFullPath("/contacts")).toEqual("/contacts"); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/regressions/000077500000000000000000000000001412317504700265045ustar00rootroot000000000000001318-linkage-data-bug-test.js000066400000000000000000000033271412317504700334330ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/regressionsimport { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; describe("Integration | Server | Regressions | 1318 Linkage bug test", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { happyUser: Model.extend({ happyLicenses: hasMany(), }), happyLicense: Model.extend({ happyUser: belongsTo(), happySubscription: belongsTo(), }), happySubscription: Model.extend({ happyLicenses: hasMany(), }), }, serializers: { application: JSONAPISerializer, }, routes() { this.resource("happy-users"); }, }); }); afterEach(function () { server.shutdown(); }); test("it works", async () => { let happySubscription = server.create("happy-subscription"); let user1 = server.create("happy-user"); server.create("happy-license", { happyUser: user1, happySubscription, }); let user2 = server.create("happy-user"); server.create("happy-license", { happyUser: user2, happySubscription, }); expect.assertions(1); let res = await fetch( "/happy-users/1?include=happy-licenses.happy-subscription" ); let json = await res.json(); expect(json.included).toEqual([ { id: "1", type: "happy-licenses", attributes: {}, relationships: { "happy-subscription": { data: { type: "happy-subscriptions", id: "1", }, }, }, }, { id: "1", type: "happy-subscriptions", attributes: {}, }, ]); }); }); 1322-relationship-path-normalization-test.js000066400000000000000000000037361412317504700366550ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/regressionsimport { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; import { underscore } from "@lib/utils/inflector"; describe("Integration | Server | Regressions | 1322 Relationship Path Normalization Test", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { happyUser: Model.extend({ happyLicenses: hasMany(), happyAvatar: belongsTo(), }), happyLicense: Model.extend({ happyUser: belongsTo(), }), happyAvatar: Model.extend({ happyUser: belongsTo(), }), }, serializers: { application: JSONAPISerializer.extend({ keyForRelationship(relationshipName) { return underscore(relationshipName); }, }), }, routes() { this.resource("happy-licenses"); }, }); }); afterEach(function () { server.shutdown(); }); test("it works", async () => { let avatar1 = server.create("happy-avatar"); let user1 = server.create("happy-user", { happyAvatar: avatar1 }); server.create("happy-license", { happyUser: user1 }); expect.assertions(2); let res = await fetch("/happy-licenses/1?include=happy_user.happy_avatar"); let json = await res.json(); expect(json.data).toEqual({ attributes: {}, id: "1", relationships: { happy_user: { data: { id: user1.id, type: "happy-users", }, }, }, type: "happy-licenses", }); expect(json.included).toEqual([ { id: user1.id, type: "happy-users", attributes: {}, relationships: { happy_avatar: { data: { id: avatar1.id, type: "happy-avatars", }, }, }, }, { id: avatar1.id, type: "happy-avatars", attributes: {}, }, ]); }); }); 1613-two-bidirectional-many-to-many-with-same-target-model-update-bug-test.js000066400000000000000000000043641412317504700446130ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/regressionsimport { Server, Model, hasMany, belongsTo, JSONAPISerializer } from "miragejs"; describe("Integration | Server | Regressions | 1613 Two bidirectional many-to-many with same target model update bug", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { user: Model.extend({ authoredPosts: hasMany("post", { inverse: "author" }), editedPosts: hasMany("post", { inverse: "editor" }), }), post: Model.extend({ author: belongsTo("user", { inverse: "authoredPosts" }), editor: belongsTo("user", { inverse: "editedPosts" }), }), }, serializers: { application: JSONAPISerializer.extend(), user: JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }), }, routes() { this.resource("posts"); this.resource("users"); }, }); }); afterEach(function () { server.shutdown(); }); test("it stores both relationships", async () => { let post = server.create("post"); let user = server.create("user"); expect.assertions(1); await fetch(`/posts/${post.id}`, { method: "PATCH", headers: { "Content-Type": "application/vnd.api+json", }, body: JSON.stringify({ data: { id: post.id, attributes: {}, relationships: { author: { data: { type: "users", id: user.id, }, }, editor: { data: { type: "users", id: user.id, }, }, }, type: "posts", }, }), }); let res = await fetch(`/users/${user.id}`); let json = await res.json(); expect(json.data).toEqual({ attributes: {}, id: "1", relationships: { "authored-posts": { data: [ { id: "1", type: "posts", }, ], }, "edited-posts": { data: [ { id: "1", type: "posts", }, ], }, }, type: "users", }); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/regressions/many-to-many-bug-test.js000066400000000000000000000033121412317504700331170ustar00rootroot00000000000000import { Server, Model, hasMany, JSONAPISerializer } from "miragejs"; describe("Integration | Server | Regressions | Many to many bug", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { post: Model.extend({ tags: hasMany(), }), tag: Model.extend({ posts: hasMany(), }), }, serializers: { application: JSONAPISerializer, }, routes() { this.resource("posts"); }, }); }); afterEach(function () { server.shutdown(); }); test("it works", async () => { expect.assertions(6); let serverTagA = server.create("tag", { name: "A", slug: "a" }); let serverTagB = server.create("tag", { name: "B", slug: "b" }); let serverPost = server.create("post", { title: "Post 1", tags: [serverTagA, serverTagB], }); expect(serverTagA.postIds).toHaveLength(1); expect(serverTagB.postIds).toHaveLength(1); expect(serverPost.tagIds).toEqual(["1", "2"]); await fetch("/posts/1", { method: "PATCH", body: JSON.stringify({ data: { id: "1", attributes: { title: "Post 2", }, relationships: { tags: { data: [ { type: "tags", id: "2", }, ], }, }, type: "posts", }, }), }); serverTagA.reload(); serverTagB.reload(); serverPost.reload(); expect(serverTagA.postIds).toEqual([]); expect(serverTagB.postIds).toEqual(["1"]); expect(serverPost.tagIds).toEqual(["2"]); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/resource-shorthand-test.js000066400000000000000000000210231412317504700312710ustar00rootroot00000000000000import { Server, Model, ActiveModelSerializer } from "miragejs"; describe("Integration | Server | Resource shorthand", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { contact: Model, blogPost: Model, }, serializers: { application: ActiveModelSerializer, }, }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("resource generates get shorthand for index action", async () => { expect.assertions(2); server.db.loadData({ contacts: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], blogPosts: [ { id: 1, title: "Post 1" }, { id: 2, title: "Post 2" }, ], }); server.resource("contacts"); let res = await fetch("/contacts"); let data = await res.json(); expect(res.status).toEqual(200); expect(data).toEqual({ contacts: [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ], }); }); test("resource generates get shorthand for show action", async () => { expect.assertions(2); server.db.loadData({ contacts: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], blogPosts: [ { id: 1, title: "Post 1" }, { id: 2, title: "Post 2" }, ], }); server.resource("contacts"); server.resource("blog-posts", { path: "/posts" }); let res = await fetch("/contacts/2"); let data = await res.json(); expect(res.status).toEqual(200); expect(data).toEqual({ contact: { id: "2", name: "Zelda" } }); }); test("resource generates post shorthand", async () => { expect.assertions(2); server.resource("contacts"); let res = await fetch("/contacts", { method: "POST", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(201); expect(server.db.contacts).toHaveLength(1); }); test("resource generates put shorthand", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], blogPosts: [{ id: 1, title: "Post 1" }], }); server.resource("contacts"); let res = await fetch("/contacts/1", { method: "PUT", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("resource generates patch shorthand", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], blogPosts: [{ id: 1, title: "Post 1" }], }); server.resource("contacts"); let res = await fetch("/contacts/1", { method: "PATCH", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("resource generates delete shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], blogPosts: [{ id: 1, title: "Post 1" }], }); server.resource("contacts"); let res = await fetch("/contacts/1", { method: "DELETE" }); expect(res.status).toEqual(204); expect(server.db.contacts).toHaveLength(0); }); test("resource accepts a custom path for a resource", async () => { expect.assertions(6); server.db.loadData({ blogPosts: [ { id: 1, title: "Post 1" }, { id: 2, title: "Post 2" }, ], }); server.resource("blog-posts", { path: "/posts" }); let indexResponse = await fetch("/posts"); expect(indexResponse.status).toEqual(200); let showResponse = await fetch("/posts/2"); expect(showResponse.status).toEqual(200); let createResponse = await fetch("/posts", { method: "POST", body: JSON.stringify({ blog_post: { name: "Post 1", }, }), }); expect(createResponse.status).toEqual(201); let updatePutResponse = await fetch("/posts/1", { method: "PUT", body: JSON.stringify({ blog_post: { name: "Post 2", }, }), }); expect(updatePutResponse.status).toEqual(200); let updatePatchResponse = await fetch("/posts/1", { method: "PATCH", body: JSON.stringify({ blog_post: { name: "Post 2", }, }), }); expect(updatePatchResponse.status).toEqual(200); let deleteResponse = await fetch("/posts/1", { method: "DELETE" }); expect(deleteResponse.status).toEqual(204); }); test("resource accepts singular name", async () => { expect.assertions(4); server.db.loadData({ contacts: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], blogPosts: [ { id: 1, title: "Post 1" }, { id: 2, title: "Post 2" }, ], }); server.resource("contact"); server.resource("blog-post", { path: "/posts" }); let contactsResponse = await fetch("/contacts"); let contactsResponseData = await contactsResponse.json(); expect(contactsResponse.status).toEqual(200); expect(contactsResponseData).toEqual({ contacts: [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ], }); let postsResponse = await fetch("/posts"); let postsResponseData = await postsResponse.json(); expect(postsResponse.status).toEqual(200); expect(postsResponseData).toEqual({ blog_posts: [ { id: "1", title: "Post 1" }, { id: "2", title: "Post 2" }, ], }); }); test("resource does not accept both :all and :except options", () => { expect(() => { server.resource("contacts", { only: ["index"], except: ["create"] }); }).toThrow("cannot use both :only and :except options"); }); test("resource generates shorthands which are whitelisted by :only option", async () => { expect.assertions(1); server.db.loadData({ contacts: [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, ], }); server.resource("contacts", { only: ["index"] }); let res = await fetch("/contacts"); expect(res.status).toEqual(200); }); test("resource does not generate shorthands which are not whitelisted with :only option", async () => { expect.assertions(5); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.resource("contacts", { only: ["index"] }); await expect(fetch("/contacts/1")).rejects.toThrow( "Mirage: Your app tried to GET '/contacts/1'" ); await expect(fetch("/contacts", { method: "POST" })).rejects.toThrow( "Mirage: Your app tried to POST '/contacts'" ); await expect(fetch("/contacts/1", { method: "PUT" })).rejects.toThrow( "Mirage: Your app tried to PUT '/contacts/1'" ); await expect(fetch("/contacts/1", { method: "PATCH" })).rejects.toThrow( "Mirage: Your app tried to PATCH '/contacts/1'" ); await expect(fetch("/contacts/1", { method: "DELETE" })).rejects.toThrow( "Mirage: Your app tried to DELETE '/contacts/1'" ); }); test("resource generates shorthands which are not blacklisted by :except option", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.resource("contacts", { except: ["create", "update", "delete"] }); let indexResponse = await fetch("/contacts"); expect(indexResponse.status).toEqual(200); let showResponse = await fetch("/contacts/1"); expect(showResponse.status).toEqual(200); }); test("resource does not generate shorthands which are blacklisted by :except option", async () => { expect.assertions(4); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.resource("contacts", { except: ["create", "update", "delete"] }); await expect(fetch("/contacts", { method: "POST" })).rejects.toThrow( "Mirage: Your app tried to POST '/contacts'" ); await expect(fetch("/contacts/1", { method: "PUT" })).rejects.toThrow( "Mirage: Your app tried to PUT '/contacts/1'" ); await expect(fetch("/contacts/1", { method: "PATCH" })).rejects.toThrow( "Mirage: Your app tried to PATCH '/contacts/1'" ); await expect(fetch("/contacts/1", { method: "DELETE" })).rejects.toThrow( "Mirage: Your app tried to DELETE '/contacts/1'" ); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/000077500000000000000000000000001412317504700270755ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/assertions-test.js000066400000000000000000000027311412317504700326050ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; import FunctionRouteHandler from "@lib/route-handlers/function"; describe("Integration | Route handlers | Assertions", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { user: Model.extend({}), comment: Model.extend({}), }, serializers: { application: JSONAPISerializer, }, }); server.timing = 0; server.logging = false; server.post("/users"); }); afterEach(() => { server.shutdown(); }); test("a helpful assert is thrown if a relationship passed in a request is not a defined association on the posted model", async () => { expect.assertions(1); let request = { requestHeaders: {}, method: "POST", url: "/users", requestBody: JSON.stringify({ data: { type: "user", attributes: { name: "Jacob Dylan", }, relationships: { comments: { data: { type: "comment", name: "Bob Dylan", }, }, }, }, }), }; let functionHandler = new FunctionRouteHandler( server.schema, server.serializerOrRegistry ); functionHandler.path = "/users"; functionHandler.request = request; expect(function () { functionHandler.normalizedRequestAttrs(); }).toThrow(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/delete-shorthand-test.js000066400000000000000000000060371412317504700336500ustar00rootroot00000000000000import { Server, Model, hasMany } from "miragejs"; import DeleteShorthandRouteHandler from "@lib/route-handlers/shorthands/delete"; import JSONAPISerializer from "@lib/serializers/json-api-serializer"; describe("Integration | Route Handlers | DELETE shorthand", () => { let server, schema, serializer; beforeEach(() => { server = new Server({ environment: "development", models: { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model, }, }); server.timing = 0; server.logging = false; let wordSmiths = [{ id: 1, name: "Ganon", blogPostIds: [1] }]; let blogPosts = [ { id: 1, title: "Lorem", wordSmithId: "1" }, { id: 2, title: "Another", wordSmithId: "2" }, ]; server.db.loadData({ wordSmiths, blogPosts }); schema = server.schema; serializer = new JSONAPISerializer(); }); afterEach(() => { server.shutdown(); }); test("undefined shorthand deletes the record and returns null", () => { let request = { url: "/word-smiths/1", params: { id: "1" } }; let handler = new DeleteShorthandRouteHandler( schema, serializer, undefined, "/word-smiths/:id" ); let response = handler.handle(request); expect(schema.db.wordSmiths).toHaveLength(0); expect(response).toBeNil(); }); test("query params are ignored", () => { let request = { url: "/word-smiths/1?foo=bar", params: { id: "1" }, queryParams: { foo: "bar" }, }; let handler = new DeleteShorthandRouteHandler( schema, serializer, undefined, "/word-smiths/:id" ); let response = handler.handle(request); expect(schema.db.wordSmiths).toHaveLength(0); expect(response).toBeNil(); }); test("string shorthand deletes the record of the specified type", () => { let request = { url: "/word-smiths/1?foo=bar", params: { id: "1" }, queryParams: { foo: "bar" }, }; let handler = new DeleteShorthandRouteHandler( schema, serializer, undefined, "/word-smiths/:id" ); let response = handler.handle(request); expect(schema.db.wordSmiths).toHaveLength(0); expect(response).toBeNil(); }); test("array shorthand deletes the record and all related records", () => { let request = { url: "/word-smiths/1", params: { id: "1" } }; let handler = new DeleteShorthandRouteHandler(schema, serializer, [ "word-smith", "blog-posts", ]); let response = handler.handle(request); expect(schema.db.wordSmiths).toHaveLength(0); expect(schema.db.blogPosts).toHaveLength(1); expect(response).toBeNil(); }); test("if a shorthand tries to access an unknown type it throws an error", () => { let request = { url: "/foobars/1", params: { id: "1" } }; let handler = new DeleteShorthandRouteHandler( schema, serializer, undefined, "/foobars/:id" ); expect(function () { handler.handle(request); }).toThrow(); expect(true).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/function-handler/000077500000000000000000000000001412317504700323355ustar00rootroot00000000000000basic-test.js000066400000000000000000000062011412317504700346510ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/function-handlerimport { Server, Model, ActiveModelSerializer, Response } from "miragejs"; describe("Integration | Route handlers | Function handler", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { user: Model.extend({}), }, serializers: { application: ActiveModelSerializer, sparseUser: ActiveModelSerializer.extend({ attrs: ["id", "name", "tall"], }), }, }); server.timing = 0; server.logging = false; }); afterEach(() => { server.shutdown(); }); test("a meaningful error is thrown if a custom route handler throws an error", async () => { server.get("/users", function () { throw "I goofed"; }); let res = await fetch("/users"); let data = await res.json(); expect(data.message).toBe("I goofed"); expect(data.stack).toMatch( "Mirage: Your GET handler for the url /users threw an error" ); }); test("mirage response string is not serialized to string", async () => { expect.assertions(1); server.get("/users", function () { return new Response( 200, { "Content-Type": "text/csv" }, "firstname,lastname\nbob,dylon" ); }); let res = await fetch("/users"); let text = await res.text(); expect(text).toEqual("firstname,lastname\nbob,dylon"); }); test("it can return a promise with non-serializable content", async () => { expect.assertions(1); server.get("/users", function () { return new Promise((resolve) => { resolve( new Response( 200, { "Content-Type": "text/csv" }, "firstname,lastname\nbob,dylan" ) ); }); }); let res = await fetch("/users"); let text = await res.text(); expect(text).toEqual("firstname,lastname\nbob,dylan"); }); test("it can return a promise with serializable content", async () => { expect.assertions(1); let user = server.create("user", { name: "Sam" }); server.get("/users", function (schema) { return new Promise((resolve) => { resolve(schema.users.all()); }); }); let res = await fetch("/users"); let data = await res.json(); expect(data).toEqual({ users: [{ id: user.id, name: "Sam" }] }); }); test("it can return a promise with an empty string", async () => { expect.assertions(3); server.get("/users", function () { return new Promise((resolve) => { resolve(new Response(200, { "Content-Type": "text/csv" }, "")); }); }); let res = await fetch("/users"); let text = await res.text(); expect(text).toEqual(""); expect(res.status).toEqual(200); expect([...res.headers.entries()]).toEqual([["content-type", "text/csv"]]); }); test(`it can serialize a POJA of models`, async () => { expect.assertions(1); server.createList("user", 3); server.get("/users", (schema) => { return schema.users.all().models; }); let res = await fetch("/users"); let data = await res.json(); expect(data).toEqual([{ id: "1" }, { id: "2" }, { id: "3" }]); }); }); normalize-request-attrs-test.js000066400000000000000000000100321412317504700404060ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/function-handlerimport { Server, Model, ActiveModelSerializer } from "miragejs"; describe("Integration | Route handlers | Function handler | #normalizedRequestAttrs", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { user: Model.extend({}), fineComment: Model.extend({}), }, serializers: { application: ActiveModelSerializer, }, }); server.timing = 0; server.logging = false; }); afterEach(() => { server.shutdown(); }); test(`it returns an object with the primary resource's attrs and belongsTo keys camelized`, async () => { expect.assertions(1); server.post("/users", function () { let attrs = this.normalizedRequestAttrs(); expect(attrs).toEqual({ firstName: "Sam", lastName: "Selikoff", teamId: 1, }); return {}; }); await fetch("/users", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ user: { first_name: "Sam", last_name: "Selikoff", team_id: 1, }, }), }); }); test(`it works for compound names`, async () => { expect.assertions(1); server.post("/fine-comments", function () { let attrs = this.normalizedRequestAttrs(); expect(attrs).toEqual({ shortText: "lorem ipsum", }); return {}; }); await fetch("/fine-comments", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ fine_comment: { short_text: "lorem ipsum", }, }), }); }); test(`it shows a meaningful error message if it cannot infer the modelname from the URL`, async () => { expect.assertions(2); server.post("/users/create", function () { this.normalizedRequestAttrs(); }); let res = await fetch("/users/create", { method: "POST" }); let data = await res.json(); expect(res.status).toEqual(500); expect(data.message).toMatch( "the detected model of 'create' does not exist" ); }); test(`it accepts an optional modelName if it cannot be inferred from the path`, async () => { expect.assertions(1); server.post("/users/create", function () { let attrs = this.normalizedRequestAttrs("user"); expect(attrs).toEqual({ firstName: "Sam", lastName: "Selikoff", teamId: 1, }); return {}; }); await fetch("/users/create", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ user: { first_name: "Sam", last_name: "Selikoff", team_id: 1, }, }), }); }); test(`it errors if the optional parameter is camelized for a model with a compount name`, async () => { expect.assertions(2); server.post("/fine-comments/create", function () { this.normalizedRequestAttrs("fineComment"); }); let res = await fetch("/fine-comments/create", { method: "POST" }); let data = await res.json(); expect(res.status).toEqual(500); expect(data.message).toMatch( "You called normalizedRequestAttrs('fineComment'), but normalizedRequestAttrs was intended to be used with the dasherized version of the model type. Please change this to normalizedRequestAttrs('fine-comment')" ); }); test(`it works with a form encoded request that has a lower-case content-type (issue 1398)`, async () => { expect.assertions(1); server.post("/form-test", function () { let attrs = this.normalizedRequestAttrs("user"); expect(attrs).toEqual({ name: "Sam Selikoff", company: "TED", email: "sam.selikoff@gmail.com", }); return {}; }); await fetch("/form-test", { method: "POST", headers: { "content-type": "x-www-form-urlencoded", }, body: "name=Sam+Selikoff&company=TED&email=sam.selikoff@gmail.com", }); }); }); serialize-test.js000066400000000000000000000072741412317504700355720ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/function-handlerimport { Server, Model, Collection, ActiveModelSerializer } from "miragejs"; import uniqBy from "lodash.uniqby"; describe("Integration | Route handlers | Function handler | #serialize", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { user: Model.extend({}), }, serializers: { application: ActiveModelSerializer, sparseUser: ActiveModelSerializer.extend({ attrs: ["id", "name", "tall"], }), }, }); server.timing = 0; server.logging = false; }); afterEach(() => { server.shutdown(); }); test("it uses the default serializer on a model", async () => { expect.assertions(1); server.create("user", { name: "Sam" }); server.get("/users", function (schema) { let user = schema.users.first(); let json = this.serialize(user); expect(json).toEqual({ user: { id: "1", name: "Sam", }, }); return true; }); await fetch("/users"); }); test("it uses the default serializer on a collection", async () => { expect.assertions(1); server.create("user", { name: "Sam" }); server.get("/users", function (schema) { let users = schema.users.all(); let json = this.serialize(users); expect(json).toEqual({ users: [{ id: "1", name: "Sam" }], }); return true; }); await fetch("/users"); }); test("it takes an optional serializer type", async () => { expect.assertions(1); server.create("user", { name: "Sam", tall: true, evil: false }); server.create("user", { name: "Ganondorf", tall: true, evil: true }); server.get("/users", function (schema) { let users = schema.users.all(); let json = this.serialize(users, "sparse-user"); expect(json).toEqual({ users: [ { id: "1", name: "Sam", tall: true }, { id: "2", name: "Ganondorf", tall: true }, ], }); return true; }); await fetch("/users"); }); test("it throws an error when trying to specify a serializer that doesnt exist", async () => { expect.assertions(2); server.create("user", { name: "Sam" }); server.get("/users", function (schema) { let users = schema.users.all(); this.serialize(users, "foo-user"); }); let res = await fetch("/users"); let data = await res.json(); expect(res.status).toBe(500); expect(data.message).toMatch(`that serializer doesn't exist`); }); test("it noops on plain JS arrays", async () => { expect.assertions(1); server.create("user", { name: "Sam" }); server.create("user", { name: "Ganondorf" }); server.get("/users", function (schema) { let names = schema.users.all().models.map((user) => user.name); let json = this.serialize(names); expect(json).toEqual(names); }); await fetch("/users"); }); test("it can take an optional serializer type on a Collection", async () => { expect.assertions(1); server.create("user", { name: "Sam", tall: true, evil: false }); server.create("user", { name: "Sam", tall: true, evil: false }); server.create("user", { name: "Ganondorf", tall: true, evil: true }); server.get("/users", function (schema) { let users = schema.users.all().models; let uniqueNames = uniqBy(users, "name"); let collection = new Collection("user", uniqueNames); let json = this.serialize(collection, "sparse-user"); expect(json).toEqual({ users: [ { id: "1", name: "Sam", tall: true }, { id: "3", name: "Ganondorf", tall: true }, ], }); }); await fetch("/users"); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/get-shorthand-test.js000066400000000000000000000214131412317504700331600ustar00rootroot00000000000000import { Model, hasMany, belongsTo, JSONAPISerializer, RestSerializer, Response, Server, } from "miragejs"; import Collection from "@lib/orm/collection"; import GetShorthandRouteHandler from "@lib/route-handlers/shorthands/get"; describe("Integration | Route Handlers | GET shorthand", () => { let server, authors, posts, photos, projectOwners, schema, serializer; beforeEach(() => { server = new Server({ environment: "development", models: { author: Model.extend({ posts: hasMany(), }), post: Model.extend({ author: belongsTo(), comments: hasMany(), }), comment: Model.extend({ post: belongsTo(), }), photo: Model, "project-owner": Model, }, }); server.timing = 0; server.logging = false; authors = [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, { id: 3, name: "Epona" }, ]; posts = [ { id: 1, title: "Lorem", authorId: 1 }, { id: 2, title: "Ipsum", authorId: 1 }, ]; photos = [ { id: 1, title: "Amazing", location: "Hyrule" }, { id: 2, title: "Photo", location: "Goron City" }, ]; projectOwners = [{ id: 1, name: "Nintendo" }]; server.db.loadData({ authors: authors, posts: posts, photos: photos, projectOwners: projectOwners, }); schema = server.schema; serializer = new JSONAPISerializer(); }); afterEach(() => { server.shutdown(); }); test("undefined shorthand returns the collection of models", () => { let request = { url: "/authors" }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors" ); let authors = handler.handle(request); expect(authors.models).toHaveLength(3); expect(authors.models[0] instanceof Model).toBeTruthy(); expect(authors.models[0].modelName).toEqual("author"); }); test("undefined shorthand ignores query params", () => { let request = { url: "/authors?foo=bar" }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors" ); let authors = handler.handle(request); expect(authors.models).toHaveLength(3); expect(authors.models[0] instanceof Model).toBeTruthy(); expect(authors.models[0].modelName).toEqual("author"); }); test("undefined shorthand can return a single model", () => { let request = { url: "/authors/2", params: { id: 2 } }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors/:id" ); let author = handler.handle(request); expect(author instanceof Model).toBeTruthy(); expect(author.modelName).toEqual("author"); expect(author.name).toEqual("Zelda"); }); test("undefined shorthand returns a 404 if a singular resource does not exist", () => { let request = { url: "/authors/99", params: { id: 99 } }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors/:id" ); let author = handler.handle(request); expect(author instanceof Response).toBeTruthy(); expect(author.code).toEqual(404); }); test("undefined shorthand ignores query params for a singular resource", () => { let request = { url: "/authors/2?foo=bar", params: { id: 2 } }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors/:id" ); let author = handler.handle(request); expect(author instanceof Model).toBeTruthy(); expect(author.modelName).toEqual("author"); expect(author.name).toEqual("Zelda"); }); test("undefined shorthand with coalesce true returns the appropriate models [JSONAPI]", () => { let request = { url: "/authors?filter[id]=1,3", queryParams: { "filter[id]": "1,3" }, }; let options = { coalesce: true }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, "/authors", options ); let authors = handler.handle(request); expect(authors.models).toHaveLength(2); expect(authors.models.map((author) => author.name)).toEqual([ "Link", "Epona", ]); }); test("undefined shorthand with coalesce true returns the appropriate models [REST]", () => { let request = { url: "/authors?ids[]=1&ids[]=3", queryParams: { ids: [1, 3] }, }; let options = { coalesce: true }; let handler = new GetShorthandRouteHandler( schema, new RestSerializer(), undefined, "/authors", options ); let authors = handler.handle(request); expect(authors.models).toHaveLength(2); expect(authors.models.map((author) => author.name)).toEqual([ "Link", "Epona", ]); }); test("string shorthand returns the correct collection of models", () => { let request = { url: "/people" }; let handler = new GetShorthandRouteHandler(schema, serializer, "author"); let authors = handler.handle(request); expect(authors.models).toHaveLength(3); expect(authors.models[0] instanceof Model).toBeTruthy(); expect(authors.models[0].modelName).toEqual("author"); }); test("string shorthand with an id returns the correct model", () => { let request = { url: "/people/2", params: { id: 2 } }; let handler = new GetShorthandRouteHandler(schema, serializer, "author"); let author = handler.handle(request); expect(author instanceof Model).toBeTruthy(); expect(author.modelName).toEqual("author"); expect(author.name).toEqual("Zelda"); }); test("string shorthand with an id 404s if the model is not found", () => { let request = { url: "/people/99", params: { id: 99 } }; let handler = new GetShorthandRouteHandler(schema, serializer, "author"); let author = handler.handle(request); expect(author instanceof Response).toBeTruthy(); expect(author.code).toEqual(404); }); test("string shorthand with coalesce returns the correct models [JSONAPI]", () => { let request = { url: "/authors?filter[id]=1,3", queryParams: { "filter[id]": "1,3" }, }; let options = { coalesce: true }; let handler = new GetShorthandRouteHandler( schema, serializer, "author", "/people", options ); let authors = handler.handle(request); expect(authors.models).toHaveLength(2); expect(authors.models.map((author) => author.name)).toEqual([ "Link", "Epona", ]); }); test("string shorthand with coalesce returns the correct models [REST]", () => { let request = { url: "/people?ids[]=1&ids[]=3", queryParams: { ids: [1, 3] }, }; let options = { coalesce: true }; let handler = new GetShorthandRouteHandler( schema, new RestSerializer(), "author", "/people", options ); let authors = handler.handle(request); expect(authors.models).toHaveLength(2); expect(authors.models.map((author) => author.name)).toEqual([ "Link", "Epona", ]); }); test("array shorthand returns the correct models", () => { let url = "/home"; let request = { url }; let handler = new GetShorthandRouteHandler( schema, serializer, ["authors", "photos"], url ); let models = handler.handle(request); expect(models[0] instanceof Collection).toBeTruthy(); expect(models[0].modelName).toEqual("author"); expect(models[0].models).toHaveLength(authors.length); expect(models[1] instanceof Collection).toBeTruthy(); expect(models[1].modelName).toEqual("photo"); expect(models[1].models).toHaveLength(photos.length); }); test("array shorthand for a singular resource errors", () => { let url = "/authors/1"; let request = { url, params: { id: 1 } }; let handler = new GetShorthandRouteHandler( schema, serializer, ["author", "posts"], url ); expect(function () { handler.handle(request); }).toThrow(); }); test("shorthand for list of models with a dash in their name", () => { let url = "/project-owners"; let request = { url }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, url ); let models = handler.handle(request); expect(models.models).toHaveLength(1); expect(models.models[0] instanceof Model).toBeTruthy(); expect(models.models[0].modelName).toEqual("project-owner"); }); test("if a shorthand tries to access an unknown type it throws an error", () => { let url = "/foobars"; let request = { url }; let handler = new GetShorthandRouteHandler( schema, serializer, undefined, url ); expect(function () { handler.handle(request); }).toThrow(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/head-shorthand-test.js000066400000000000000000000105211412317504700333000ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer, Response } from "miragejs"; import HeadShorthandRouteHandler from "@lib/route-handlers/shorthands/head"; describe("Integration | Route Handlers | HEAD shorthand", () => { let server, authors, photos, schema, serializer; beforeEach(() => { server = new Server({ environment: "development", models: { author: Model, photo: Model, }, }); server.timing = 0; server.logging = false; authors = [ { id: 1, name: "Link" }, { id: 2, name: "Zelda" }, { id: 3, name: "Epona" }, ]; photos = [ { id: 1, title: "Amazing", location: "Hyrule" }, { id: 2, title: "Photo", location: "Goron City" }, ]; server.db.loadData({ authors: authors, photos: photos, }); schema = server.schema; serializer = new JSONAPISerializer(); }); afterEach(() => { server.shutdown(); }); test("undefined shorthand with an ID that is not in the DB will return a 404 Response", () => { let request = { url: "/authors", params: { id: 101 } }; let handler = new HeadShorthandRouteHandler( schema, serializer, undefined, "/authors" ); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(404); }); test("undefined shorthand with an ID that is in the DB will return a 204 Response", () => { let request = { url: "/authors", params: { id: 1 } }; let handler = new HeadShorthandRouteHandler( schema, serializer, undefined, "/authors" ); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); test("undefined shorthand with coalesce true will return a 204 response if one of the IDs are found", () => { let request = { url: "/authors?ids[]=1&ids[]=3", queryParams: { ids: [1, 3] }, }; let options = { coalesce: true }; let handler = new HeadShorthandRouteHandler( schema, serializer, undefined, "/authors", options ); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); test("undefined shorthand string (no id) shorthand returns a 204 (regardless of the length of the collection)", () => { let request = { url: "/authors" }; let handler = new HeadShorthandRouteHandler( schema, serializer, undefined, "/authors" ); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); test("string shorthand with an ID that is not in the DB will return a 404 Response", () => { let request = { url: "/authors", params: { id: 101 } }; let handler = new HeadShorthandRouteHandler(schema, serializer, "author"); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(404); }); test("string shorthand with an ID that is in the DB will return a 204 Response", () => { let request = { url: "/authors", params: { id: 1 } }; let handler = new HeadShorthandRouteHandler(schema, serializer, "author"); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); test("string shorthand with coalesce true will return a 204 response if one of the IDs are found", () => { let request = { url: "/authors?ids[]=1&ids[]=3", queryParams: { ids: [1, 3] }, }; let options = { coalesce: true }; let handler = new HeadShorthandRouteHandler( schema, serializer, "author", "/people", options ); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); test("string shorthand string (no id) shorthand returns a 204 (regardless of the length of the collection)", () => { let request = { url: "/authors" }; let handler = new HeadShorthandRouteHandler(schema, serializer, "author"); let response = handler.handle(request); expect(response instanceof Response).toBeTruthy(); expect(response.code).toEqual(204); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/post-shorthand-test.js000066400000000000000000000050351412317504700333700ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; import PostShorthandRouteHandler from "@lib/route-handlers/shorthands/post"; describe("Integration | Route Handlers | POST shorthand", () => { let server, schema, serializer, body; beforeEach(() => { server = new Server({ environment: "development", models: { author: Model.extend({}), }, }); server.timing = 0; server.logging = false; schema = server.schema; serializer = new JSONAPISerializer(); body = { data: { type: "authors", attributes: { "first-name": "Ganon", "last-name": "Dorf", }, }, }; }); afterEach(() => { server.shutdown(); }); test("string shorthand creates a record of the specified type and returns the new model", () => { let request = { requestBody: JSON.stringify(body), url: "/people" }; let handler = new PostShorthandRouteHandler(schema, serializer, "author"); let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganon"); }); test("query params are ignored", () => { let request = { requestBody: JSON.stringify(body), url: "/authors?foo=bar", queryParams: { foo: "bar" }, }; let handler = new PostShorthandRouteHandler(schema, serializer, "author"); let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganon"); }); test("undefined shorthand creates a record and returns the new model", () => { let request = { requestBody: JSON.stringify(body), url: "/authors" }; let handler = new PostShorthandRouteHandler( schema, serializer, null, "/authors" ); let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganon"); }); test("if a shorthand tries to access an unknown type it throws an error", () => { let request = { requestBody: JSON.stringify(body), url: "/foobars" }; let handler = new PostShorthandRouteHandler(schema, serializer, "foobar"); expect(function () { handler.handle(request); }).toThrow(); expect(true).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/route-handlers/put-shorthand-test.js000066400000000000000000000056231412317504700332160ustar00rootroot00000000000000import { Server, Model, JSONAPISerializer } from "miragejs"; import PutShorthandRouteHandler from "@lib/route-handlers/shorthands/put"; describe("Integration | Route Handlers | PUT shorthand", () => { let server, authors, schema, serializer, body; beforeEach(() => { server = new Server({ environment: "development", models: { author: Model.extend(), }, }); server.timing = 0; server.logging = false; authors = [{ id: 1, firstName: "Ganon" }]; server.db.loadData({ authors: authors, }); schema = server.schema; serializer = new JSONAPISerializer(); body = { data: { type: "authors", id: "1", attributes: { "first-name": "Ganondorf", }, }, }; }); afterEach(() => { server.shutdown(); }); test("undefined shorthand updates the record and returns the model", () => { let handler = new PutShorthandRouteHandler( schema, serializer, undefined, "/authors/:id" ); let request = { requestBody: JSON.stringify(body), url: "/authors/1", params: { id: "1" }, }; let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganondorf"); }); test("query params are ignored", () => { let handler = new PutShorthandRouteHandler(schema, serializer, "author"); let request = { requestBody: JSON.stringify(body), url: "/authors/1?foo=bar", params: { id: "1" }, queryParams: { foo: "bar" }, }; let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganondorf"); }); test("string shorthand updates the record of the specified type and returns the model", () => { let handler = new PutShorthandRouteHandler( schema, serializer, undefined, "/authors/:id" ); let request = { requestBody: JSON.stringify(body), url: "/authors/1", params: { id: "1" }, }; let model = handler.handle(request); expect(schema.db.authors).toHaveLength(1); expect(model instanceof Model).toBeTruthy(); expect(model.modelName).toEqual("author"); expect(model.firstName).toEqual("Ganondorf"); }); test("if a shorthand tries to access an unknown type it throws an error", () => { let handler = new PutShorthandRouteHandler( schema, serializer, undefined, "/foobars/:id" ); let request = { requestBody: JSON.stringify(body), url: "/foobars/1", params: { id: "1" }, }; expect(function () { handler.handle(request); }).toThrow(); expect(true).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/routes-test.js000066400000000000000000000021101412317504700267670ustar00rootroot00000000000000import { Server, Model } from "miragejs"; describe("Integration | Routes", () => { let server; afterEach(function () { server.shutdown(); }); test("routes config option works", async () => { server = new Server({ environment: "test", models: { user: Model, }, routes() { this.namespace = "api"; this.get("/users"); }, }); server.createList("user", 3); let data = await fetch("/api/users").then((res) => res.json()); expect(data).toEqual({ users: [{ id: "1" }, { id: "2" }, { id: "3" }], }); }); test("there's an error if both baseConfig and routes options are passed in", async () => { expect(() => { new Server({ environment: "test", routes() { this.get("/users", () => ({ users: [] })); }, baseConfig() { this.get("/posts", () => ({ posts: [] })); }, }); }).toThrow( "The routes option is an alias for the baseConfig option. You can't pass both options into your server definition." ); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/serializers/000077500000000000000000000000001412317504700264755ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/serializers/includes-test.js000066400000000000000000000100141412317504700316120ustar00rootroot00000000000000import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs"; describe("Internal | MoveAfterHandleRequest | Serializers | includes", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { wordSmith: Model.extend({ posts: hasMany("blog-post"), }), blogPost: Model.extend({ author: belongsTo("word-smith"), comments: hasMany("fine-comment"), }), fineComment: Model.extend({ post: belongsTo("blog-post"), }), }, routes() { this.resource("blog-posts"); }, }); let wordSmith = server.schema.wordSmiths.create({ name: "Link" }); let blogPost = wordSmith.createPost({ title: "Lorem" }); blogPost.createComment({ text: "pwned" }); }); afterEach(function () { server.shutdown(); }); test("include can be an array of relationship names", async () => { server.config({ serializers: { blogPost: Serializer.extend({ include: ["author", "comments"], }), }, }); let json = await fetch("/blog-posts/1").then((res) => res.json()); expect(json).toEqual({ blogPost: { authorId: "1", commentIds: ["1"], id: "1", title: "Lorem", }, fineComments: [ { id: "1", text: "pwned", }, ], wordSmiths: [ { id: "1", name: "Link", }, ], }); }); test("include can be a function", async () => { server.config({ serializers: { blogPost: Serializer.extend({ include() { return ["comments"]; }, }), }, }); let json = await fetch("/blog-posts/1").then((res) => res.json()); expect(json).toEqual({ blogPost: { commentIds: ["1"], id: "1", title: "Lorem", }, fineComments: [ { id: "1", text: "pwned", }, ], }); }); test("include gets the request as the first param", async () => { server.config({ serializers: { blogPost: Serializer.extend({ include(request) { return request.queryParams.include ? ["comments"] : []; }, }), }, }); let json = await fetch("/blog-posts/1?include").then((res) => res.json()); expect(json).toEqual({ blogPost: { commentIds: ["1"], id: "1", title: "Lorem", }, fineComments: [ { id: "1", text: "pwned", }, ], }); }); test("include gets the model as the second param", async () => { server.config({ serializers: { blogPost: Serializer.extend({ include(request, model) { return Object.keys(model.associations); }, }), }, }); let json = await fetch("/blog-posts/1?include").then((res) => res.json()); expect(json).toEqual({ blogPost: { authorId: "1", commentIds: ["1"], id: "1", title: "Lorem", }, fineComments: [ { id: "1", text: "pwned", }, ], wordSmiths: [ { id: "1", name: "Link", }, ], }); }); test("serializer.schema is exposed", async () => { server.config({ serializers: { blogPost: Serializer.extend({ include(request, resource) { return Object.keys(this.schema.associationsFor(resource.modelName)); }, }), }, }); let json = await fetch("/blog-posts/1?include").then((res) => res.json()); expect(json).toEqual({ blogPost: { authorId: "1", commentIds: ["1"], id: "1", title: "Lorem", }, fineComments: [ { id: "1", text: "pwned", }, ], wordSmiths: [ { id: "1", name: "Link", }, ], }); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/server-config-test.js000066400000000000000000000131511412317504700302260ustar00rootroot00000000000000import { Server, Model, ActiveModelSerializer, RestSerializer } from "miragejs"; describe("Integration | Server Config", () => { let server; beforeEach(() => { server = new Server({ environment: "development", models: { contact: Model, post: Model, }, serializers: { contact: ActiveModelSerializer, }, }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("namespace can be configured", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.namespace = "api"; server.get("/contacts"); let res = await fetch("/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("urlPrefix can be configured", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.urlPrefix = "http://localhost:3000"; server.get("/contacts"); let res = await fetch("http://localhost:3000/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("urlPrefix and namespace can be configured simultaneously", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.urlPrefix = "http://localhost:3000"; server.namespace = "api"; server.get("/contacts"); let res = await fetch("http://localhost:3000/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("fully qualified domain names can be used in configuration", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.get("http://example.org/api/contacts"); let res = await fetch("http://example.org/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("urlPrefix/namespace are ignored when fully qualified domain names are used in configuration", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.urlPrefix = "https://example.net"; server.get("http://example.org/api/contacts"); let res = await fetch("http://example.org/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("blank urlPrefix and namespace ends up as /", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.namespace = ""; server.urlPrefix = ""; server.get("contacts"); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("namespace with no slash gets one", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.namespace = "api"; server.get("contacts"); let res = await fetch("/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("urlPrefix with no slash gets one", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.urlPrefix = "pre"; server.get("contacts"); let res = await fetch("/pre/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("namespace of / works", async () => { expect.assertions(1); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.db.loadData({ contacts, }); server.namespace = "/"; server.get("contacts"); let res = await fetch("/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); }); test("redefining options using the config method works", async () => { expect.assertions(5); let contacts = [ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, ]; server.config({ namespace: "api", urlPrefix: "http://localhost:3000", timing: 1000, serializers: { post: RestSerializer, }, }); server.db.loadData({ contacts, }); server.get("contacts"); expect(server.timing).toEqual(1000); let res = await fetch("http://localhost:3000/api/contacts"); let data = await res.json(); expect(data).toEqual({ contacts }); let serializerMap = server.serializerOrRegistry._serializerMap; expect(Object.keys(serializerMap)).toHaveLength(2); expect(serializerMap.contact).toEqual(ActiveModelSerializer); expect(serializerMap.post).toEqual(RestSerializer); }); test("changing the environment of the server throws an error", () => { expect(() => { server.config({ environment: "test", }); }).toThrow(); }); test("changing the trackRequests configuration of the server throws an error", () => { expect(() => { server.config({ trackRequests: true, }); }).toThrow(); }); }); miragejs-0.1.42/__tests__/internal/move-after-handle-request/shorthands/000077500000000000000000000000001412317504700263165ustar00rootroot00000000000000active-model-serializer-sanity-test.js000066400000000000000000000050061412317504700356000ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/shorthandsimport { Server, Model, ActiveModelSerializer } from "miragejs"; describe("Integration | Server | Shorthands | Active Model Serializer Sanity check", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { contact: Model, }, serializers: { application: ActiveModelSerializer, }, }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("a get shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.get("/contacts"); let res = await fetch("/contacts"); let data = await res.json(); expect(res.status).toEqual(200); expect(data).toEqual({ contacts: [{ id: "1", name: "Link" }] }); }); test("a post shorthand works", async () => { expect.assertions(2); server.post("/contacts"); let res = await fetch("/contacts", { method: "POST", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(201); expect(server.db.contacts).toHaveLength(1); }); test("a put shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.put("/contacts/:id"); let res = await fetch("/contacts/1", { method: "PUT", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("a patch shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.patch("/contacts/:id"); let res = await fetch("/contacts/1", { method: "PATCH", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("a delete shorthand works", async () => { expect.assertions(3); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.del("/contacts/:id"); let res = await fetch("/contacts/1", { method: "DELETE", }); let text = await res.text(); expect(text).toEqual(""); expect(res.status).toEqual(204); expect(server.db.contacts).toHaveLength(0); }); }); patch-shorthand-with-relationships-test.js000066400000000000000000000072741412317504700365060ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/shorthandsimport { Server, JSONAPISerializer, Model, belongsTo, hasMany } from "miragejs"; describe("Integration | Server | Shorthands | Patch with relationships", function () { let newServerWithSchema, server; beforeEach(function () { newServerWithSchema = function (schema) { server = new Server({ environment: "development", models: schema, serializers: { application: JSONAPISerializer, }, }); server.timing = 0; server.logging = false; return server; }; }); afterEach(function () { server.shutdown(); }); test("it can null out belongs to relationships", async () => { let server = newServerWithSchema({ author: Model.extend({ posts: hasMany(), }), post: Model.extend({ author: belongsTo(), }), }); server.patch("/posts/:id"); let author = server.create("author"); let post = server.create("post", { author }); await fetch(`/posts/${post.id}`, { method: "PATCH", body: JSON.stringify({ data: { attributes: { title: "Post 1", }, relationships: { author: { data: null, }, }, }, }), }); post.reload(); expect(post.author).toBeNull(); }); test("it can null out belongs to polymorphic relationships", async () => { let server = newServerWithSchema({ video: Model.extend(), post: Model.extend(), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }); server.patch("/comments/:id"); let video = server.create("video"); let comment = server.create("comment", { commentable: video, }); await fetch(`/comments/${comment.id}`, { method: "PATCH", body: JSON.stringify({ data: { attributes: { title: "Post 1", }, relationships: { commentable: { data: null, }, }, }, }), }); comment.reload(); expect(comment.commentable).toBeNull(); }); test("it can null out has many polymorphic relationships", async () => { let server = newServerWithSchema({ car: Model.extend(), watch: Model.extend(), user: Model.extend({ collectibles: hasMany({ polymorphic: true }), }), }); server.patch("/users/:id"); let car = server.create("car"); let watch = server.create("watch"); let user = server.create("user", { collectibles: [car, watch], }); await fetch(`/users/${user.id}`, { method: "PATCH", body: JSON.stringify({ data: { attributes: {}, relationships: { collectibles: { data: null, }, }, }, }), }); user.reload(); expect(user.collectibles).toHaveLength(0); }); test("it camelizes relationship names", async () => { let server = newServerWithSchema({ postAuthor: Model.extend({ posts: hasMany(), }), post: Model.extend({ postAuthor: belongsTo(), }), }); server.patch("/posts/:id"); let postAuthor = server.create("post-author"); let post = server.create("post"); await fetch(`/posts/${post.id}`, { method: "PATCH", body: JSON.stringify({ data: { attributes: {}, relationships: { "post-author": { data: { id: postAuthor.id, type: "post-authors", }, }, }, }, }), }); post.reload(); expect(post.postAuthorId).toEqual(postAuthor.id); }); }); post-shorthand-with-relationships-test.js000066400000000000000000000073021412317504700363640ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/shorthandsimport { Server, JSONAPISerializer, Model, belongsTo, hasMany } from "miragejs"; describe("Integration | Server | Shorthands | Post with relationships", function () { let newServerWithSchema, server; beforeEach(function () { newServerWithSchema = function (schema) { server = new Server({ environment: "development", models: schema, serializers: { appliction: JSONAPISerializer, }, }); server.timing = 0; server.logging = false; return server; }; }); afterEach(function () { server.shutdown(); }); test("it works for belongs to", async () => { let server = newServerWithSchema({ author: Model.extend({ posts: hasMany(), }), post: Model.extend({ author: belongsTo(), }), }); server.post("/posts"); expect(server.db.posts).toHaveLength(0); let author = server.create("author"); let res = await fetch("/posts", { method: "POST", body: JSON.stringify({ data: { attributes: { title: "Post 1", }, relationships: { author: { data: { type: "authors", id: author.id, }, }, }, }, }), }); let data = await res.json(); let postId = data.post.id; let post = server.schema.posts.find(postId); expect(post).toBeTruthy(); expect(post.author.id).toEqual(author.id); }); test("it works for belongs to polymorphic", async () => { let server = newServerWithSchema({ video: Model.extend(), post: Model.extend(), comment: Model.extend({ commentable: belongsTo({ polymorphic: true }), }), }); server.post("/comments"); expect(server.db.comments).toHaveLength(0); let video = server.create("video"); let res = await fetch("/comments", { method: "POST", body: JSON.stringify({ data: { type: "comments", attributes: { text: "Comment 1", }, relationships: { commentable: { data: { type: "videos", id: video.id, }, }, }, }, }), }); let data = await res.json(); let commentId = data.comment.id; let comment = server.schema.comments.find(commentId); expect(comment).toBeTruthy(); expect(comment.commentable.equals(video)).toBeTruthy(); }); test("it works for has many polymorphic", async () => { let server = newServerWithSchema({ car: Model.extend(), watch: Model.extend(), user: Model.extend({ collectibles: hasMany({ polymorphic: true }), }), }); server.post("/users"); expect(server.db.users).toHaveLength(0); let car = server.create("car"); let watch = server.create("watch"); let res = await fetch("/users", { method: "POST", body: JSON.stringify({ data: { type: "users", attributes: { name: "Elon Musk", }, relationships: { collectibles: { data: [ { type: "cars", id: car.id, }, { type: "watches", id: watch.id, }, ], }, }, }, }), }); let data = await res.json(); let userId = data.user.id; let user = server.schema.users.find(userId); expect(user).toBeTruthy(); expect(user.collectibles.includes(car)).toBeTruthy(); expect(user.collectibles.includes(watch)).toBeTruthy(); }); }); rest-serializer-sanity-test.js000066400000000000000000000054641412317504700342140ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/move-after-handle-request/shorthandsimport { Server, Model, hasMany, belongsTo, RestSerializer } from "miragejs"; describe("Integration | Server | Shorthands | REST Serializer Sanity check", function () { let server; beforeEach(function () { server = new Server({ environment: "test", models: { contact: Model.extend({ addresses: hasMany(), }), address: Model.extend({ contact: belongsTo(), }), }, serializers: { application: RestSerializer.extend({ normalizeIds: true, }), }, }); server.timing = 0; server.logging = false; }); afterEach(function () { server.shutdown(); }); test("a get shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.get("/contacts"); let res = await fetch("/contacts"); let data = await res.json(); expect(res.status).toEqual(200); expect(data).toEqual({ contacts: [{ id: "1", name: "Link", addresses: [] }], }); }); test("a post shorthand works", async () => { expect.assertions(3); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.post("/addresses"); let res = await fetch("/addresses", { method: "POST", body: JSON.stringify({ address: { street: "5th ave", contact: 1, }, }), }); expect(res.status).toEqual(201); expect(server.db.addresses).toHaveLength(1); expect(server.db.addresses[0].contactId).toEqual(1); }); test("a put shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.put("/contacts/:id"); let res = await fetch("/contacts/1", { method: "PUT", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("a patch shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.patch("/contacts/:id"); let res = await fetch("/contacts/1", { method: "PATCH", body: JSON.stringify({ contact: { name: "Zelda", }, }), }); expect(res.status).toEqual(200); expect(server.db.contacts[0].name).toEqual("Zelda"); }); test("a delete shorthand works", async () => { expect.assertions(2); server.db.loadData({ contacts: [{ id: 1, name: "Link" }], }); server.del("/contacts/:id"); let res = await fetch("/contacts/1", { method: "DELETE", }); expect(res.status).toEqual(204); expect(server.db.contacts).toHaveLength(0); }); }); miragejs-0.1.42/__tests__/internal/unit/000077500000000000000000000000001412317504700201345ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/collection-test.js000066400000000000000000000023321412317504700236020ustar00rootroot00000000000000import Collection from "@lib/orm/collection"; describe("Unit | Collection", function () { test("it can be instantiated", () => { let collection = new Collection("plant"); expect(collection).toBeTruthy(); }); test("it cannot be instantiated without a modelName", () => { expect(() => { new Collection(); }).toThrow(/must pass a `modelName`/); }); test("it knows its modelname", () => { let collection = new Collection("author"); expect(collection.modelName).toEqual("author"); }); test("it can be instantiated with an array of models", () => { let models = [{ id: 1 }, { id: 2 }, { id: 3 }]; let collection = new Collection("author", models); expect(collection).toBeTruthy(); }); test("#models returns the underlying array", () => { let models = [{ id: 1 }, { id: 2 }, { id: 3 }]; let collection = new Collection("author", models); expect(collection.models).toEqual(models); }); test("#length returns the number of elements", () => { let models = [{ id: 1 }, { id: 2 }]; let collection = new Collection("post", models); expect(collection).toHaveLength(2); collection.models = [{ id: 1 }]; expect(collection).toHaveLength(1); }); }); miragejs-0.1.42/__tests__/internal/unit/db-test.js000066400000000000000000000432471412317504700220460ustar00rootroot00000000000000import "@lib/container"; import Db from "@lib/db"; import DefaultIdentityManager from "@lib/identity-manager"; let db; describe("Unit | Db", function () { test("it can be instantiated", () => { db = new Db(); expect(Db).toBeTruthy(); }); test("it can load data on instantiation", () => { db = new Db({ users: [{ id: 1, name: "Link" }], addresses: [ { id: 1, name: "123 Hyrule Way" }, { id: 2, name: "Lorem ipsum" }, ], }); expect(db.users).toHaveLength(1); expect(db.addresses).toHaveLength(2); }); test("it can empty its data", () => { db = new Db({ users: [{ id: 1, name: "Link" }], addresses: [ { id: 1, name: "123 Hyrule Way" }, { id: 2, name: "Lorem ipsum" }, ], }); db.emptyData(); expect(db.users).toHaveLength(0); expect(db.addresses).toHaveLength(0); }); }); describe("Unit | Db #createCollection", function () { beforeEach(function () { db = new Db(); }); afterEach(function () { db.emptyData(); }); test("it can create an empty collection", () => { db.createCollection("contacts"); expect(db.contacts).toBeTruthy(); }); test("it can create many collections", () => { db.createCollections("contacts", "addresses"); expect(db.contacts).toBeTruthy(); expect(db.addresses).toBeTruthy(); }); }); describe("Unit | Db #loadData", function () { beforeEach(function () { db = new Db(); }); afterEach(function () { db.emptyData(); }); test("it can load an object of data", () => { let data = { contacts: [{ id: "1", name: "Link" }], addresses: [{ id: "1", name: "123 Hyrule Way" }], }; db.loadData(data); expect(db.contacts).toIncludeSameMembers(data.contacts); expect(db.addresses).toIncludeSameMembers(data.addresses); }); test("it clones all data so nothing is passed by reference", () => { let data = { contacts: [{ id: "1", someArray: ["foo", "bar"] }], }; db.loadData(data); let contactRecord = db.contacts.find(1); contactRecord.someArray.push("baz"); expect(contactRecord.someArray).toHaveLength(3); expect(data.contacts[0].someArray).toHaveLength(2); }); }); describe("Unit | Db #all", function () { let data; beforeEach(function () { data = { contacts: [{ id: "1", name: "Link" }], addresses: [{ id: "1", name: "123 Hyrule Way" }], }; db = new Db(data); }); afterEach(function () { db.emptyData(); }); test("it can return a collection", () => { expect(db.contacts).toIncludeSameMembers(data.contacts); expect(db.addresses).toIncludeSameMembers(data.addresses); }); test("the collection is a copy", () => { let { contacts } = db; expect(contacts).toIncludeSameMembers(data.contacts); contacts[0].name = "Zelda"; expect(db.contacts).toIncludeSameMembers(data.contacts); }); }); describe("Unit | Db #insert", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); }); afterEach(function () { db.emptyData(); }); test("it inserts an object and returns it", () => { let link = db.contacts.insert({ name: "Link" }); let expectedRecord = { id: "1", name: "Link", }; expect(db.contacts).toIncludeSameMembers([expectedRecord]); expect(link).toEqual(expectedRecord); }); test("it returns a copy", () => { let link = db.contacts.insert({ name: "Link" }); let expectedRecord = { id: "1", name: "Link", }; expect(link).toEqual(expectedRecord); link.name = "Young link"; expect(db.contacts.find(1)).toEqual(expectedRecord); }); test("it can insert objects sequentially", () => { db.contacts.insert({ name: "Link" }); db.contacts.insert({ name: "Ganon" }); let records = [ { id: "1", name: "Link" }, { id: "2", name: "Ganon" }, ]; expect(db.contacts).toIncludeSameMembers(records); }); test("it does not add an id if present", () => { let attrs = { id: "5", name: "Link" }; db.contacts.insert(attrs); expect(db.contacts).toIncludeSameMembers([attrs]); }); test("it can insert an array and return it", () => { db.contacts.insert({ name: "Link" }); let contacts = db.contacts.insert([{ name: "Zelda" }, { name: "Ganon" }]); expect(db.contacts).toIncludeSameMembers([ { id: "1", name: "Link" }, { id: "2", name: "Zelda" }, { id: "3", name: "Ganon" }, ]); expect(contacts).toIncludeSameMembers([ { id: "2", name: "Zelda" }, { id: "3", name: "Ganon" }, ]); }); test("it does not add ids to array data if present", () => { db.contacts.insert([ { id: 2, name: "Link" }, { id: 1, name: "Ganon" }, ]); expect(db.contacts).toHaveLength(2); expect(db.contacts).toContainEqual({ id: "2", name: "Link" }); expect(db.contacts).toContainEqual({ id: "1", name: "Ganon" }); }); test("it can insert a record with an id of 0", () => { db.contacts.insert({ id: 0, name: "Link" }); expect(db.contacts).toHaveLength(1); expect(db.contacts).toContainEqual({ id: "0", name: "Link" }); }); test("IDs increment correctly, even after a record is removed", () => { let records = db.contacts.insert([{ name: "Link" }, { name: "Ganon" }]); db.contacts.remove(records[0]); let record = db.contacts.insert({ name: "Zelda" }); expect(record.id).toEqual("3"); }); test("inserting a record with an already used ID throws an error", () => { expect.assertions(2); db.contacts.insert({ id: 1, name: "Duncan McCleod" }); expect(function () { db.contacts.insert({ id: 1, name: "Duncan McCleod" }); }).toThrow(); db.contacts.insert({ id: "atp", name: "Adenosine Triphosphate" }); expect(function () { db.contacts.insert({ id: "atp", name: "Adenosine Triphosphate" }); }).toThrow(); }); test("tracks the correct IDs being used", () => { db.contacts.insert({ name: "Vegeta" }); db.contacts.insert({ id: 2, name: "Krilli" }); expect(db.contacts).toHaveLength(2); }); }); describe("Unit | Db #findBy", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { name: "Zelda" }, { name: "Link" }, { name: "Epona", race: "Horse" }, { name: "Epona", race: "Centaur" }, { id: "abc", name: "Ganon" }, ]); }); afterEach(function () { db.emptyData(); }); test("returns a record that matches the given name", () => { let contact = db.contacts.findBy({ name: "Link" }); expect(contact).toEqual({ id: "2", name: "Link" }); }); test("returns a copy not a reference", () => { let contact = db.contacts.findBy({ name: "Link" }); contact.name = "blah"; expect(db.contacts.find(2)).toEqual({ id: "2", name: "Link" }); }); test("returns the first record matching the criteria", () => { let contact = db.contacts.findBy({ name: "Epona" }); expect(contact).toEqual({ id: "3", name: "Epona", race: "Horse" }); }); test("returns a record only matching multiple criteria", () => { let contact = db.contacts.findBy({ name: "Epona", race: "Centaur" }); expect(contact).toEqual({ id: "4", name: "Epona", race: "Centaur" }); }); test("returns null when no record is found", () => { let contact = db.contacts.findBy({ name: "Fi" }); expect(contact).toBeNull(); }); }); describe("Unit | Db #find", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { name: "Zelda" }, { name: "Link" }, { id: "abc", name: "Ganon" }, ]); }); afterEach(function () { db.emptyData(); }); test("returns a record that matches a numerical id", () => { let contact = db.contacts.find(2); expect(contact).toEqual({ id: "2", name: "Link" }); }); test("returns a copy not a reference", () => { let contact = db.contacts.find(2); expect(contact).toEqual({ id: "2", name: "Link" }); contact.name = "blah"; expect(db.contacts.find(2)).toEqual({ id: "2", name: "Link" }); }); test("returns a record that matches a string id", () => { let contact = db.contacts.find("abc"); expect(contact).toEqual({ id: "abc", name: "Ganon" }); }); test("returns multiple record that matches an array of ids", () => { let contacts = db.contacts.find([1, 2]); expect(contacts).toEqual([ { id: "1", name: "Zelda" }, { id: "2", name: "Link" }, ]); }); test("returns a record whose id is a string that start with numbers", () => { db.contacts.insert({ id: "123-456", name: "Epona", }); let contact = db.contacts.find("123-456"); expect(contact).toEqual({ id: "123-456", name: "Epona" }); }); test("returns multiple record that match an array of ids", () => { let contacts = db.contacts.find([1, 2]); expect(contacts).toEqual([ { id: "1", name: "Zelda" }, { id: "2", name: "Link" }, ]); }); test("returns an empty array when it doesnt find multiple ids", () => { let contacts = db.contacts.find([99, 100]); expect(contacts).toEqual([]); }); }); describe("Unit | Db #where", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { name: "Link", evil: false, age: 17 }, { name: "Zelda", evil: false, age: 17 }, { name: "Ganon", evil: true, age: 45 }, ]); }); afterEach(function () { db.emptyData(); }); test("returns an array of records that match the query", () => { let result = db.contacts.where({ evil: true }); expect(result).toEqual([{ id: "3", name: "Ganon", evil: true, age: 45 }]); }); test("it coerces query params to strings", () => { let result = db.contacts.where({ age: "45" }); expect(result).toEqual([{ id: "3", name: "Ganon", evil: true, age: 45 }]); }); test("returns a copy, not a referecne", () => { let result = db.contacts.where({ evil: true }); expect(result).toEqual([{ id: "3", name: "Ganon", evil: true, age: 45 }]); result[0].evil = false; expect(db.contacts.where({ evil: true })).toEqual([ { id: "3", name: "Ganon", evil: true, age: 45 }, ]); }); test("returns an empty array if no records match the query", () => { let result = db.contacts.where({ name: "Link", evil: true }); expect(result).toEqual([]); }); test("accepts a filter function", () => { let result = db.contacts.where(function (record) { return record.age === 45; }); expect(result).toEqual([{ id: "3", name: "Ganon", evil: true, age: 45 }]); }); }); describe("Unit | Db #update", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { name: "Link", evil: false }, { name: "Zelda", evil: false }, { name: "Ganon", evil: true }, { id: "123-abc", name: "Epona", evil: false }, ]); }); afterEach(function () { db.emptyData(); }); test("it can update the whole collection", () => { db.contacts.update({ name: "Sam", evil: false }); expect(db.contacts).toHaveLength(4); [ { id: "1", name: "Sam", evil: false }, { id: "2", name: "Sam", evil: false }, { id: "3", name: "Sam", evil: false }, { id: "123-abc", name: "Sam", evil: false }, ].forEach((contact) => { expect(db.contacts).toContainEqual(contact); }); }); test("it can update a record by id", () => { db.contacts.update(3, { name: "Ganondorf", evil: false }); let ganon = db.contacts.find(3); expect(ganon).toEqual({ id: "3", name: "Ganondorf", evil: false }); }); test("it can update a record by id when the id is a string", () => { db.contacts.update("123-abc", { evil: true }); let epona = db.contacts.find("123-abc"); expect(epona).toEqual({ id: "123-abc", name: "Epona", evil: true }); }); test("it can update multiple records by ids", () => { db.contacts.update([1, 2], { evil: true }); let link = db.contacts.find(1); let zelda = db.contacts.find(2); expect(link.evil).toEqual(true); expect(zelda.evil).toEqual(true); }); test("it can update records by query", () => { db.contacts.update({ evil: false }, { name: "Sam" }); expect(db.contacts).toHaveLength(4); [ { id: "1", name: "Sam", evil: false }, { id: "2", name: "Sam", evil: false }, { id: "3", name: "Ganon", evil: true }, { id: "123-abc", name: "Sam", evil: false }, ].forEach((contact) => { expect(db.contacts).toContainEqual(contact); }); }); test("updating a single record returns that record", () => { let ganon = db.contacts.update(3, { name: "Ganondorf" }); expect(ganon).toEqual({ id: "3", name: "Ganondorf", evil: true }); }); test("updating a collection returns the updated records", () => { let characters = db.contacts.update({ evil: true }); expect(characters).toEqual([ { id: "1", name: "Link", evil: true }, { id: "2", name: "Zelda", evil: true }, { id: "123-abc", name: "Epona", evil: true }, ]); }); test("updating multiple records returns the updated records", () => { let characters = db.contacts.update({ evil: false }, { evil: true }); expect(characters).toEqual([ { id: "1", name: "Link", evil: true }, { id: "2", name: "Zelda", evil: true }, { id: "123-abc", name: "Epona", evil: true }, ]); }); test("throws when updating an ID is attempted", () => { expect.assertions(1); expect(function () { db.contacts.update(1, { id: 3 }); }).toThrow(); }); }); describe("Unit | Db #remove", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { name: "Link", evil: false }, { name: "Zelda", evil: false }, { name: "Ganon", evil: true }, { id: "123-abc", name: "Epona", evil: false }, ]); }); afterEach(function () { db.emptyData(); }); test("it can remove an entire collection", () => { db.contacts.remove(); expect(db.contacts).toHaveLength(0); }); test("it can remove a single record by id", () => { db.contacts.remove(1); expect(db.contacts).toContainEqual({ id: "2", name: "Zelda", evil: false }); expect(db.contacts).toContainEqual({ id: "3", name: "Ganon", evil: true }); expect(db.contacts).toContainEqual({ id: "123-abc", name: "Epona", evil: false, }); }); test("it can remove a single record when the id is a string", () => { db.contacts.remove("123-abc"); expect(db.contacts).toHaveLength(3); expect(db.contacts).toContainEqual({ id: "1", name: "Link", evil: false }); expect(db.contacts).toContainEqual({ id: "2", name: "Zelda", evil: false }); expect(db.contacts).toContainEqual({ id: "3", name: "Ganon", evil: true }); }); test("it can remove multiple records by ids", () => { db.contacts.remove([1, 2]); expect(db.contacts).toHaveLength(2); expect(db.contacts).toContainEqual({ id: "3", name: "Ganon", evil: true }); expect(db.contacts).toContainEqual({ id: "123-abc", name: "Epona", evil: false, }); }); test("it can remove multiple records by query", () => { db.contacts.remove({ evil: false }); expect(db.contacts).toHaveLength(1); expect(db.contacts).toContainEqual({ id: "3", name: "Ganon", evil: true }); }); test("it can add a record after removing all records", () => { db.contacts.remove(); db.contacts.insert({ name: "Foo" }); expect(db.contacts).toHaveLength(1); expect(db.contacts).toContainEqual({ id: "1", name: "Foo" }); }); }); describe("Unit | Db #firstOrCreate", function () { beforeEach(function () { db = new Db(); db.createCollection("contacts"); db.contacts.insert([ { id: 1, name: "Link", evil: false }, { id: 2, name: "Zelda", evil: false }, { id: 3, name: "Ganon", evil: true }, ]); }); afterEach(function () { db.emptyData(); }); test("it can find the first record available from the query", () => { let record = db.contacts.firstOrCreate({ name: "Link" }); expect(record).toEqual({ id: "1", name: "Link", evil: false }); }); test("it creates a new record from query + attrs if none found", () => { let record = db.contacts.firstOrCreate({ name: "Mario" }, { evil: false }); expect(record.name).toEqual("Mario"); expect(record.evil).toEqual(false); expect(record.id).toBeTruthy(); }); test("does not require attrs", () => { let record = db.contacts.firstOrCreate({ name: "Luigi" }); expect(record.name).toEqual("Luigi"); expect(record.id).toBeTruthy(); }); }); describe("Unit | Db #registerIdentityManagers and #identityManagerFor", function () { test("identityManagerFor returns default IdentityManager if there aren't any custom ones", () => { let db = new Db(); expect(db.identityManagerFor("foo")).toEqual(DefaultIdentityManager); }); test("it can register identity managers per db collection and for application", () => { let FooIdentityManager = class {}; let ApplicationIdentityManager = class {}; let db = new Db(); db.registerIdentityManagers({ foo: FooIdentityManager, application: ApplicationIdentityManager, }); expect(db.identityManagerFor("foo")).toEqual(FooIdentityManager); expect(db.identityManagerFor("bar")).toEqual(ApplicationIdentityManager); }); test("it can register idenitity managers on instantiation", () => { let CustomIdentityManager = class {}; let db = new Db(undefined, { foo: CustomIdentityManager, }); expect(db.identityManagerFor("foo")).toEqual(CustomIdentityManager); expect(db.identityManagerFor("bar")).toEqual(DefaultIdentityManager); }); }); miragejs-0.1.42/__tests__/internal/unit/db/000077500000000000000000000000001412317504700205215ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/db/identity-manager-test.js000066400000000000000000000047051412317504700253030ustar00rootroot00000000000000import { IdentityManager } from "@lib"; describe("Unit | Db | IdentityManager", function () { test("it can be instantiated", () => { let manager = new IdentityManager(); expect(manager).toBeTruthy(); }); test(`fetch returns the latest number`, () => { let manager = new IdentityManager(); expect(manager.fetch()).toEqual("1"); expect(manager.fetch()).toEqual("2"); expect(manager.fetch()).toEqual("3"); }); test(`get returns the upcoming id used for fetch`, () => { let manager = new IdentityManager(); expect(manager.fetch()).toEqual("1"); // TODO: strange case since it's the one returning int instead of string expect(manager.get()).toEqual(2); expect(manager.fetch()).toEqual("2"); }); test(`set indicates an id is being used`, () => { let manager = new IdentityManager(); manager.set("abc"); expect(function () { manager.set("abc"); }).toThrow("Attempting to use the ID abc, but it's already been used"); }); test(`a numerical value passed into set affects future ids used by fetch`, () => { let manager = new IdentityManager(); manager.set(5); expect(manager.fetch()).toEqual("6"); expect(manager.fetch()).toEqual("7"); }); test(`multiple numerical values passed into set affects future ids used by fetch`, () => { let manager = new IdentityManager(); manager.set(5); manager.set(6); expect(manager.fetch()).toEqual("7"); expect(manager.fetch()).toEqual("8"); }); test(`an int as a string passed into set affects future ids used by fetch`, () => { let manager = new IdentityManager(); manager.set("5"); expect(manager.fetch()).toEqual("6"); expect(manager.fetch()).toEqual("7"); }); test(`multiple ints as a string passed into set affects future ids used by fetch`, () => { let manager = new IdentityManager(); manager.set("5"); manager.set("6"); expect(manager.fetch()).toEqual("7"); expect(manager.fetch()).toEqual("8"); }); test(`a string value that doesn't parse as an int passed into set doesn't affect future ids used by fetch`, () => { let manager = new IdentityManager(); manager.set("123-abc"); expect(manager.fetch()).toEqual("1"); expect(manager.fetch()).toEqual("2"); }); test(`reset clears the managers memory`, () => { let manager = new IdentityManager(); manager.set("abc"); manager.reset(); manager.set("abc"); expect(true).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/unit/factory-test.js000066400000000000000000000200551412317504700231200ustar00rootroot00000000000000import Factory from "@lib/factory"; import trait from "@lib/trait"; describe("Unit | Factory", function () { test("it exists", () => { expect(Factory).toBeTruthy(); }); test("the base class builds empty objects", () => { let f = new Factory(); let data = f.build(); expect(data).toEqual({}); }); test("a noop extension builds empty objects", () => { let EmptyFactory = Factory.extend(); let f = new EmptyFactory(); let data = f.build(); expect(data).toEqual({}); }); test("it works with strings, numbers and booleans", () => { let AFactory = Factory.extend({ name: "Sam", age: 28, alive: true, }); let f = new AFactory(); let data = f.build(); expect(data).toEqual({ name: "Sam", age: 28, alive: true }); }); test("it supports inheritance", () => { let PersonFactory = Factory.extend({ species: "human", }); let ManFactory = PersonFactory.extend({ gender: "male", }); let SamFactory = ManFactory.extend({ name: "Sam", }); let p = new PersonFactory(); let m = new ManFactory(); let s = new SamFactory(); expect(p.build()).toEqual({ species: "human" }); expect(m.build()).toEqual({ species: "human", gender: "male" }); expect(s.build()).toEqual({ species: "human", gender: "male", name: "Sam", }); }); test("it can use sequences", () => { let PostFactory = Factory.extend({ likes(i) { return 5 * i; }, }); let p = new PostFactory(); let post1 = p.build(1); let post2 = p.build(2); expect(post1).toEqual({ likes: 5 }); expect(post2).toEqual({ likes: 10 }); }); test("it can reuse static properties", () => { let BazFactory = Factory.extend({ foo: 5, bar(i) { return this.foo * i; }, }); let b = new BazFactory(); let baz1 = b.build(1); let baz2 = b.build(2); expect(baz1).toEqual({ foo: 5, bar: 5 }); expect(baz2).toEqual({ foo: 5, bar: 10 }); }); test("it can reuse dynamic properties", () => { let BazFactory = Factory.extend({ foo(i) { return 5 * i; }, bar() { return this.foo * 2; }, }); let b = new BazFactory(); let baz1 = b.build(1); let baz2 = b.build(2); expect(baz1).toEqual({ foo: 5, bar: 10 }); expect(baz2).toEqual({ foo: 10, bar: 20 }); }); test("it can have dynamic properties that depend on another", () => { let BazFactory = Factory.extend({ name() { return "foo"; }, bar() { return this.name.substr(1); }, }); let b = new BazFactory(); let baz1 = b.build(1); expect(baz1).toEqual({ name: "foo", bar: "oo" }); }); test("it can reference properties out of order", () => { let BazFactory = Factory.extend({ bar() { return this.foo + 2; }, baz: 6, foo(i) { return this.baz * i; }, }); let b = new BazFactory(); let baz1 = b.build(1); let baz2 = b.build(2); expect(baz1).toEqual({ baz: 6, foo: 6, bar: 8 }); expect(baz2).toEqual({ baz: 6, foo: 12, bar: 14 }); }); test("it can reference multiple properties in any order", () => { let FooFactory = Factory.extend({ foo() { return this.bar + this.baz; }, bar: 6, baz: 10, }); let BarFactory = Factory.extend({ bar: 6, foo() { return this.bar + this.baz; }, baz: 10, }); let BazFactory = Factory.extend({ bar: 6, baz: 10, foo() { return this.bar + this.baz; }, }); let Foo = new FooFactory(); let Bar = new BarFactory(); let Baz = new BazFactory(); let foo = Foo.build(1); let bar = Bar.build(1); let baz = Baz.build(1); expect(foo).toEqual({ foo: 16, bar: 6, baz: 10 }); expect(bar).toEqual({ foo: 16, bar: 6, baz: 10 }); expect(baz).toEqual({ foo: 16, bar: 6, baz: 10 }); }); test("it can reference properties on complex object", () => { let AbcFactory = Factory.extend({ a(i) { return this.b + i; }, b() { return this.c + 1; }, c() { return this.f + 1; }, d(i) { return this.e + i; }, e() { return this.c + 1; }, f: 1, g: 2, h: 3, }); let b = new AbcFactory(); let abc1 = b.build(1); let abc2 = b.build(2); expect(abc1).toEqual({ a: 4, b: 3, c: 2, d: 4, e: 3, f: 1, g: 2, h: 3 }); expect(abc2).toEqual({ a: 5, b: 3, c: 2, d: 5, e: 3, f: 1, g: 2, h: 3 }); }); test("throws meaningfull exception on circular reference", () => { let BazFactory = Factory.extend({ bar() { return this.foo; }, foo() { return this.bar; }, }); let b = new BazFactory(); expect(function () { b.build(1); }).toThrow(); }); test("#build skips invoking `afterCreate`", () => { let skipped = true; let PostFactory = Factory.extend({ afterCreate() { skipped = false; }, }); let factory = new PostFactory(); let post = factory.build(0); expect(skipped).toBeTruthy(); expect(typeof post.afterCreate).toEqual("undefined"); }); test("extractAfterCreateCallbacks returns all afterCreate callbacks from factory with the base one being first", () => { let PostFactory = Factory.extend({ published: trait({ afterCreate() { return "from published"; }, }), withComments: trait({ afterCreate() { return "from withComments"; }, }), otherTrait: trait({}), afterCreate() { return "from base"; }, }); let callbacks = PostFactory.extractAfterCreateCallbacks(); expect(callbacks).toHaveLength(3); expect(callbacks.map((cb) => cb())).toEqual([ "from base", "from published", "from withComments", ]); }); test("extractAfterCreateCallbacks filters traits from which the afterCreate callbacks will be extracted from", () => { let PostFactory = Factory.extend({ published: trait({ afterCreate() { return "from published"; }, }), withComments: trait({ afterCreate() { return "from withComments"; }, }), otherTrait: trait({}), afterCreate() { return "from base"; }, }); expect( PostFactory.extractAfterCreateCallbacks({ traits: [] }) ).toHaveLength(1); expect( PostFactory.extractAfterCreateCallbacks({ traits: [] }).map((cb) => cb()) ).toEqual(["from base"]); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments"] }) ).toHaveLength(2); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments"], }).map((cb) => cb()) ).toEqual(["from base", "from withComments"]); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments", "published"], }) ).toHaveLength(3); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments", "published"], }).map((cb) => cb()) ).toEqual(["from base", "from withComments", "from published"]); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments", "otherTrait"], }) ).toHaveLength(2); expect( PostFactory.extractAfterCreateCallbacks({ traits: ["withComments", "otherTrait"], }).map((cb) => cb()) ).toEqual(["from base", "from withComments"]); }); test("isTrait returns true if there is a trait with given name", () => { let PostFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, }), someNestedObject: { value: "nested", }, }); expect(!PostFactory.isTrait("title")).toBeTruthy(); expect(PostFactory.isTrait("published")).toBeTruthy(); expect(!PostFactory.isTrait("someNestedObject")).toBeTruthy(); expect(!PostFactory.isTrait("notdefined")).toBeTruthy(); }); }); miragejs-0.1.42/__tests__/internal/unit/model-test.js000066400000000000000000000016751412317504700225600ustar00rootroot00000000000000import { Model } from "@lib"; describe("Unit | Model", function () { test("it can be instantiated", () => { let model = new Model({}, "user"); expect(model).toBeTruthy(); }); test("it cannot be instantiated without a schema", () => { expect(function () { new Model(); }).toThrow("A model requires a schema"); }); test("it cannot be instantiated without a modelName", () => { expect(function () { new Model({}); }).toThrow("A model requires a modelName"); }); test("findBelongsToAssociation returns association for given type if defined", () => { let ModelClass = Model.extend(); let authorAssociationMock = {}; ModelClass.prototype.belongsToAssociations = { author: authorAssociationMock, }; expect(ModelClass.findBelongsToAssociation("article")).toBeUndefined(); expect(ModelClass.findBelongsToAssociation("author")).toEqual( authorAssociationMock ); }); }); miragejs-0.1.42/__tests__/internal/unit/reference-sort-test.js000066400000000000000000000014371412317504700243770ustar00rootroot00000000000000import { _utilsReferenceSort as referenceSort } from "@lib"; describe("mirage:reference-sort", function () { test("it sorts property references", () => { let sorted = referenceSort([ ["propA"], ["propB", "propC"], ["propC", "propA"], ["propD"], ]); expect(sorted).toEqual(["propD", "propA", "propC", "propB"]); }); test("it throws on circular dependency", () => { expect(function () { referenceSort([ ["propA", "propB"], ["propB", "propA"], ]); }).toThrow('Cyclic dependency in properties ["propB","propA"]'); }); test("it works with no references", () => { let sorted = referenceSort([["propA"], ["propB"], ["propC"], ["propD"]]); expect(sorted).toEqual(["propD", "propC", "propB", "propA"]); }); }); miragejs-0.1.42/__tests__/internal/unit/response-test.js000066400000000000000000000016121412317504700233050ustar00rootroot00000000000000import { Response } from "@lib"; describe("Unit | Response", function () { test("it can be instantiated and return a rack response", () => { let response = new Response(404, {}, {}); expect(response).toBeTruthy(); expect(response.toRackResponse()).toBeTruthy(); }); test("it can be instantiated with just a response code", () => { let response = new Response(404); expect(response).toBeTruthy(); expect(response.toRackResponse()).toBeTruthy(); }); test("it adds Content-Type by default", () => { let response = new Response(200, {}, {}); expect(response).toBeTruthy(); expect(response.headers["Content-Type"]).toEqual("application/json"); }); test("it does not add Content-Type for a 204 response", () => { let response = new Response(204); expect(response).toBeTruthy(); expect(response.headers["Content-Type"]).toBeFalsy(); }); }); miragejs-0.1.42/__tests__/internal/unit/route-handlers/000077500000000000000000000000001412317504700230705ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/route-handlers/shorthands/000077500000000000000000000000001412317504700252455ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/route-handlers/shorthands/base-test.js000066400000000000000000000047101412317504700274740ustar00rootroot00000000000000import { _routeHandlersShorthandsBase as BaseShorthandRouteHandler } from "@lib"; describe("Unit | Route handlers | Shorthands | BaseShorthandRouteHandler", function () { let handler = null; let request = null; beforeEach(function () { handler = new BaseShorthandRouteHandler(); request = { params: { id: "" } }; }); test("it returns a number if it's a number", () => { request.params.id = 2; expect(handler._getIdForRequest(request)).toEqual(2); }); test("it returns a number if it's a string represented number", () => { request.params.id = "2"; expect(handler._getIdForRequest(request)).toEqual("2"); }); test("it returns a string it's a dasherized number", () => { request.params.id = "2-1"; expect(handler._getIdForRequest(request)).toEqual("2-1"); }); test("it returns a string if it's a string", () => { request.params.id = "someID"; expect(handler._getIdForRequest(request)).toEqual("someID"); }); test("getModelClassFromPath works with various named route path variable", () => { let urlWithSlash = "/api/fancy-users"; let urlWithIdAndSlash = "/api/fancy-users/:id"; let urlWithTrailingSlash = "/api/fancy-users/"; expect(handler.getModelClassFromPath(urlWithSlash)).toEqual("fancy-user"); expect(handler.getModelClassFromPath(urlWithIdAndSlash, true)).toEqual( "fancy-user" ); expect(handler.getModelClassFromPath(urlWithTrailingSlash)).toEqual( "fancy-user" ); urlWithSlash = "/api/exquisite-users"; urlWithIdAndSlash = "/api/exquisite-users/:objectId"; expect(handler.getModelClassFromPath(urlWithSlash)).toEqual( "exquisite-user" ); expect(handler.getModelClassFromPath(urlWithIdAndSlash, true)).toEqual( "exquisite-user" ); urlWithSlash = "/api/elegant-users"; urlWithIdAndSlash = "/api/elegant-users/:firstName/:lastName"; expect(handler.getModelClassFromPath(urlWithSlash)).toEqual("elegant-user"); expect(handler.getModelClassFromPath(urlWithIdAndSlash, true)).toEqual( "elegant-user" ); }); test("it can read the id from the url", () => { let request = { params: { id: "test-id" } }; expect(handler._getIdForRequest(request)).toEqual("test-id"); }); test("it can read the id from the request body", () => { let request = { params: {} }; let jsonApiDoc = { data: { id: "jsonapi-id" } }; expect(handler._getIdForRequest(request, jsonApiDoc)).toEqual("jsonapi-id"); }); }); miragejs-0.1.42/__tests__/internal/unit/schema-test.js000066400000000000000000000035721412317504700227160ustar00rootroot00000000000000import { _ormSchema as Schema, _Db as Db, Model, belongsTo } from "@lib"; describe("Unit | Schema", function () { test("it can be instantiated", () => { let dbMock = {}; let schema = new Schema(dbMock); expect(schema).toBeTruthy(); }); test("it cannot be instantiated without a db", () => { expect(function () { new Schema(); }).toThrow("A schema requires a db"); }); test("modelFor returns model for given type if registered", () => { let db = new Db(); let schema = new Schema(db); expect(schema.modelFor("article")).toBeUndefined(); let authorModel = Model.extend({}); let articleModel = Model.extend({ author: belongsTo(), }); schema.registerModel("article", articleModel); schema.registerModel("author", authorModel); expect(schema.modelFor("article").foreignKeys).toEqual(["authorId"]); expect(schema.modelFor("author").foreignKeys).toEqual([]); }); test("`first()` returns null when nothing is found", () => { expect.assertions(2); let db = new Db(); let schema = new Schema(db); let authorModel = Model.extend({}); schema.registerModel("author", authorModel); expect(schema.first("author")).toBeNull(); let record = schema.create("author", { id: 1, name: "Mary Roach" }); expect(schema.first("author")).toEqual(record); }); test("`findBy()` returns null when nothing is found", () => { expect.assertions(3); let db = new Db(); let schema = new Schema(db); let authorModel = Model.extend({}); schema.registerModel("author", authorModel); expect(schema.findBy("author", { name: "Mary Roach" })).toBeNull(); let record = schema.create("author", { id: 1, name: "Mary Roach" }); expect(schema.findBy("author", { name: "Mary Roach" })).toEqual(record); expect(schema.findBy("author", { name: "Charles Dickens" })).toBeNull(); }); }); miragejs-0.1.42/__tests__/internal/unit/serializers/000077500000000000000000000000001412317504700224705ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/serializers/active-model-serializer-test.js000066400000000000000000000055731412317504700305350ustar00rootroot00000000000000import { _ormSchema as Schema, _Db as Db, Model, belongsTo, ActiveModelSerializer, } from "@lib"; describe("Unit | Serializers | ActiveModelSerializer", function () { let serializer = null; let schema = null; beforeEach(function () { schema = new Schema(new Db(), { contact: Model.extend({ address: belongsTo(), }), address: Model.extend({ contact: belongsTo(), }), }); serializer = new ActiveModelSerializer({ schema, }); }); test("normalize works", () => { let payload = { contact: { id: 1, name: "Link", }, }; let jsonApiDoc = serializer.normalize(payload); expect(jsonApiDoc).toEqual({ data: { type: "contacts", id: 1, attributes: { name: "Link", }, }, }); }); test("it hyphenates snake_cased words", () => { let payload = { contact: { id: 1, first_name: "Link", }, }; let jsonApiDoc = serializer.normalize(payload); expect(jsonApiDoc).toEqual({ data: { type: "contacts", id: 1, attributes: { "first-name": "Link", }, }, }); }); test("it works without an id", () => { let payload = { contact: { first_name: "Link", last_name: "zor", }, }; let jsonApiDoc = serializer.normalize(payload); expect(jsonApiDoc).toEqual({ data: { type: "contacts", attributes: { "first-name": "Link", "last-name": "zor", }, }, }); }); test("it returns coalesce Ids if present", () => { let request = { url: "/authors", queryParams: { ids: ["1", "3"] } }; expect(serializer.getCoalescedIds(request)).toEqual(["1", "3"]); }); test("it returns undefined coalesce Ids if not present", () => { let request = { url: "/authors", queryParams: {} }; expect(serializer.getCoalescedIds(request)).toBeUndefined(); }); test("normalizeIds defaults to true", () => { let serializer = new ActiveModelSerializer(); expect(serializer.normalizeIds).toEqual(true); }); test("normalize works with normalizeIds set to true", () => { serializer.normalizeIds = true; let payload = { contact: { id: 1, name: "Link", address: 1, }, }; let jsonApiDoc = serializer.normalize(payload); expect(jsonApiDoc).toEqual({ data: { type: "contacts", id: 1, attributes: { name: "Link", }, relationships: { address: { data: { type: "address", id: 1, }, }, }, }, }); }); test('serializeIds defaults to "always"', () => { let defaultState = new ActiveModelSerializer(); expect(defaultState.serializeIds).toEqual("always"); }); }); miragejs-0.1.42/__tests__/internal/unit/serializers/json-api-serializer-test.js000066400000000000000000000011471412317504700276750ustar00rootroot00000000000000import { JSONAPISerializer } from "@lib"; describe("Unit | Serializers | JSON API Serializer", function () { let serializer = null; beforeEach(function () { serializer = new JSONAPISerializer(); }); test("it returns coalesce Ids if present", () => { let request = { url: "/authors", queryParams: { "filter[id]": "1,3" } }; expect(serializer.getCoalescedIds(request)).toEqual(["1", "3"]); }); test("it returns undefined coalesce Ids if not present", () => { let request = { url: "/authors", queryParams: {} }; expect(serializer.getCoalescedIds(request)).toBeUndefined(); }); }); miragejs-0.1.42/__tests__/internal/unit/serializers/json-api-serializer/000077500000000000000000000000001412317504700263575ustar00rootroot00000000000000create-includes-graph-snapshot-collections-test.js000066400000000000000000000063451412317504700401420ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/serializers/json-api-serializerimport { _ormSchema as Schema, _Db as Db, Model, hasMany, JSONAPISerializer, } from "@lib"; /* This test is heavily coupled to the implementation and can be deleted during a future refactoring. */ describe("Unit | Serializers | JSON API Serializer | #_createIncludesGraphSnapshot collections", function () { let serializer = null; let registry = null; let type = null; let request = {}; beforeEach(function () { registry = { serializerFor() { return serializer; }, }; type = "foo"; request = {}; serializer = new JSONAPISerializer(registry, type, request); }); test("it works on collections with no includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({}), }); schema.wordSmiths.create(); schema.wordSmiths.create(); serializer._createRequestedIncludesGraph(schema.wordSmiths.all()); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": {}, "word-smith:2": {}, }, }); }); test("it works on collections with hasMany relationships and dot-path includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ redTags: hasMany(), bluePosts: hasMany(), }), bluePost: Model.extend({ redTags: hasMany(), }), redTag: Model.extend({ someColors: hasMany(), }), someColor: Model.extend(), }); let wordSmith1 = schema.wordSmiths.create(); wordSmith1.createRedTag(); wordSmith1.createRedTag(); let bluePost = wordSmith1.createBluePost(); let redTag = bluePost.createRedTag(); redTag.createSomeColor(); let wordSmith2 = schema.wordSmiths.create(); wordSmith2.createRedTag(); let bluePost2 = wordSmith2.createBluePost(); let redTag2 = bluePost2.createRedTag(); redTag2.createSomeColor(); serializer.request = { queryParams: { include: "red-tags,blue-posts.red-tags.some-colors" }, }; serializer._createRequestedIncludesGraph(schema.wordSmiths.all()); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "red-tags": ["red-tag:1", "red-tag:2"], "blue-posts": ["blue-post:1"], }, }, "word-smith:2": { relationships: { "red-tags": ["red-tag:4"], "blue-posts": ["blue-post:2"], }, }, }, included: { "red-tags": { "red-tag:1": {}, "red-tag:2": {}, "red-tag:3": { relationships: { "some-colors": ["some-color:1"], }, }, "red-tag:4": {}, "red-tag:5": { relationships: { "some-colors": ["some-color:2"], }, }, }, "blue-posts": { "blue-post:1": { relationships: { "red-tags": ["red-tag:3"], }, }, "blue-post:2": { relationships: { "red-tags": ["red-tag:5"], }, }, }, "some-colors": { "some-color:1": {}, "some-color:2": {}, }, }, }); }); }); create-includes-graph-snapshot-mixed-test.js000066400000000000000000000045671412317504700367360ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/serializers/json-api-serializerimport { _ormSchema as Schema, _Db as Db, Model, hasMany, belongsTo, JSONAPISerializer, } from "@lib"; /* This test is heavily coupled to the implementation and can be deleted during a future refactoring. */ describe("Unit | Serializers | JSON API Serializer | #_createIncludesGraphSnapshot mixed", function () { let serializer = null; let registry = null; let type = null; let request = {}; beforeEach(function () { registry = { serializerFor() { return serializer; }, }; type = "foo"; request = {}; serializer = new JSONAPISerializer(registry, type, request); }); test("it works on models and collections with dot-path includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ blogPosts: hasMany(), }), blogPost: Model.extend({ happyTag: belongsTo(), }), happyTag: Model.extend({ happyColor: belongsTo(), }), happyColor: Model.extend(), }); let wordSmith = schema.wordSmiths.create(); let blogPost1 = wordSmith.createBlogPost(); let happyTag = blogPost1.createHappyTag(); happyTag.createHappyColor(); let blogPost2 = wordSmith.createBlogPost(); let happyTag2 = blogPost2.createHappyTag(); happyTag2.createHappyColor(); serializer.request = { queryParams: { include: "blog-posts.happy-tag.happy-color" }, }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "blog-posts": ["blog-post:1", "blog-post:2"], }, }, }, included: { "blog-posts": { "blog-post:1": { relationships: { "happy-tag": "happy-tag:1", }, }, "blog-post:2": { relationships: { "happy-tag": "happy-tag:2", }, }, }, "happy-tags": { "happy-tag:1": { relationships: { "happy-color": "happy-color:1", }, }, "happy-tag:2": { relationships: { "happy-color": "happy-color:2", }, }, }, "happy-colors": { "happy-color:1": {}, "happy-color:2": {}, }, }, }); }); }); create-includes-graph-snapshot-models-test.js000066400000000000000000000155661412317504700371140ustar00rootroot00000000000000miragejs-0.1.42/__tests__/internal/unit/serializers/json-api-serializerimport { _ormSchema as Schema, _Db as Db, Model, hasMany, belongsTo, JSONAPISerializer, } from "@lib"; /* This test is heavily coupled to the implementation and can be deleted during a future refactoring. */ describe("Unit | Serializers | JSON API Serializer | #_createIncludesGraphSnapshot models", function () { let serializer = null; let registry = null; let type = null; let request = {}; beforeEach(function () { registry = { serializerFor() { return serializer; }, }; type = "foo"; request = {}; serializer = new JSONAPISerializer(registry, type, request); }); test("it works on models with no includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({}), }); let wordSmith = schema.wordSmiths.create(); serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": {}, }, }); }); test("it doesn't choke on an empty belongsTo relationship", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ blogPost: belongsTo(), }), blogPost: Model.extend({ happyCategory: belongsTo(), }), happyCategory: Model.extend(), }); let wordSmith = schema.wordSmiths.create(); wordSmith.createBlogPost(); serializer.request = { queryParams: { include: "blog-post.happy-category" }, }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "blog-post": "blog-post:1", }, }, }, included: { "blog-posts": { "blog-post:1": { relationships: { "happy-category": undefined, }, }, }, }, }); }); test("it works on models with belongsTo relationships", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ redTag: belongsTo(), bluePost: belongsTo(), }), bluePost: Model.extend({ redTag: belongsTo(), }), redTag: Model.extend(), }); let wordSmith = schema.wordSmiths.create(); wordSmith.createRedTag(); let bluePost = wordSmith.createBluePost(); bluePost.createRedTag(); serializer.request = { queryParams: { include: "red-tag,blue-post" } }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "red-tag": "red-tag:1", "blue-post": "blue-post:1", }, }, }, included: { "red-tags": { "red-tag:1": {}, }, "blue-posts": { "blue-post:1": {}, }, }, }); }); test("it works on models with belongsTo relationships and dot-path includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ redTag: belongsTo(), bluePost: belongsTo(), }), bluePost: Model.extend({ redTag: belongsTo(), }), redTag: Model.extend({ someColor: belongsTo(), }), someColor: Model.extend({}), }); let wordSmith = schema.wordSmiths.create(); wordSmith.createRedTag(); let bluePost = wordSmith.createBluePost(); let redTag = bluePost.createRedTag(); redTag.createSomeColor(); serializer.request = { queryParams: { include: "red-tag,blue-post.red-tag.some-color" }, }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "red-tag": "red-tag:1", "blue-post": "blue-post:1", }, }, }, included: { "red-tags": { "red-tag:1": {}, "red-tag:2": { relationships: { "some-color": "some-color:1", }, }, }, "blue-posts": { "blue-post:1": { relationships: { "red-tag": "red-tag:2", }, }, }, "some-colors": { "some-color:1": {}, }, }, }); }); test("it works on models with hasMany relationships", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ redTags: hasMany(), bluePosts: hasMany(), }), bluePost: Model.extend({ redTags: hasMany(), }), redTag: Model.extend(), }); let wordSmith = schema.wordSmiths.create(); wordSmith.createRedTag(); wordSmith.createRedTag(); let bluePost = wordSmith.createBluePost(); bluePost.createRedTag(); serializer.request = { queryParams: { include: "red-tags,blue-posts" } }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "red-tags": ["red-tag:1", "red-tag:2"], "blue-posts": ["blue-post:1"], }, }, }, included: { "red-tags": { "red-tag:1": {}, "red-tag:2": {}, }, "blue-posts": { "blue-post:1": {}, }, }, }); }); test("it works on models with hasMany relationships and dot-path includes", () => { let schema = new Schema(new Db(), { wordSmith: Model.extend({ redTags: hasMany(), bluePosts: hasMany(), }), bluePost: Model.extend({ redTags: hasMany(), }), redTag: Model.extend({ someColors: hasMany(), }), someColor: Model.extend(), }); let wordSmith = schema.wordSmiths.create(); wordSmith.createRedTag(); wordSmith.createRedTag(); let bluePost = wordSmith.createBluePost(); let redTag = bluePost.createRedTag(); redTag.createSomeColor(); serializer.request = { queryParams: { include: "red-tags,blue-posts.red-tags.some-colors" }, }; serializer._createRequestedIncludesGraph(wordSmith); expect(serializer.request._includesGraph).toEqual({ data: { "word-smith:1": { relationships: { "red-tags": ["red-tag:1", "red-tag:2"], "blue-posts": ["blue-post:1"], }, }, }, included: { "red-tags": { "red-tag:1": {}, "red-tag:2": {}, "red-tag:3": { relationships: { "some-colors": ["some-color:1"], }, }, }, "blue-posts": { "blue-post:1": { relationships: { "red-tags": ["red-tag:3"], }, }, }, "some-colors": { "some-color:1": {}, }, }, }); }); }); miragejs-0.1.42/__tests__/internal/unit/serializers/rest-serializer-test.js000066400000000000000000000024651412317504700271360ustar00rootroot00000000000000import { _ormSchema as Schema, _Db as Db, Model, RestSerializer } from "@lib"; describe("Unit | Serializers | RestSerializer", function () { let schema = null; let serializer = null; beforeEach(function () { schema = new Schema(new Db(), { person: Model, }); serializer = new RestSerializer({ schema, }); }); test("it hyphenates camelized words", () => { let payload = { person: { id: 1, firstName: "Rick", lastName: "Sanchez", }, }; let jsonApiDoc = serializer.normalize(payload); expect(jsonApiDoc).toEqual({ data: { type: "people", id: 1, attributes: { "first-name": "Rick", "last-name": "Sanchez", }, }, }); }); test("it returns coalesce Ids if present", () => { let request = { url: "/authors", queryParams: { ids: ["1", "3"] } }; expect(serializer.getCoalescedIds(request)).toEqual(["1", "3"]); }); test("it returns undefined coalesce Ids if not present", () => { let request = { url: "/authors", queryParams: {} }; expect(serializer.getCoalescedIds(request)).toBeUndefined(); }); }); test('serializeIds defaults to "always"', () => { let defaultState = new RestSerializer(); expect(defaultState.serializeIds).toEqual("always"); }); miragejs-0.1.42/__tests__/internal/unit/server-test.js000066400000000000000000001072621412317504700227650ustar00rootroot00000000000000import { createServer, Server, Model, Factory, belongsTo, hasMany, trait, association, } from "@lib"; describe("Unit | Server", function () { test("it can be instantiated", () => { let server = new Server({ environment: "test" }); expect(server).toBeTruthy(); server.shutdown(); }); test("routes return pretender handler", () => { let server = new Server({ environment: "test" }); let handler = server.post("foo"); expect(handler.numberOfCalls).toBe(0); server.shutdown(); }); test("it runs the default scenario in non-test environments", () => { expect.assertions(1); let server = new Server({ environment: "development", seeds() { expect(true).toBeTruthy(); }, }); server.shutdown(); }); }); describe("Unit | createServer", function () { test("it returns a server instance", () => { let server = createServer(); expect(server).toBeTruthy(); server.shutdown(); }); test("routes return pretender handler", () => { let server = createServer({ environment: "test" }); let handler = server.post("foo"); expect(handler.numberOfCalls).toBe(0); server.shutdown(); }); test("it runs the default scenario in non-test environments", () => { expect.assertions(1); let server = createServer({ environment: "development", seeds() { expect(true).toBeTruthy(); }, }); server.shutdown(); }); }); describe("Unit | Server #loadConfig", function () { test("forces timing to 0 in test environment", () => { let server = new Server({ environment: "test" }); server.loadConfig(function () { this.timing = 50; }); expect(server.timing).toEqual(0); server.shutdown(); }); test("doesn't modify user's timing config in other environments", () => { let server = new Server({ environment: "blah" }); server.loadConfig(function () { this.timing = 50; }); expect(server.timing).toEqual(50); server.shutdown(); }); }); describe("Unit | Server #db", function () { test("its db is isolated across instances", () => { let server1 = new Server({ environment: "test" }); server1.db.createCollection("contacts"); server1.db.contacts.insert({ name: "Sam" }); server1.shutdown(); let server2 = new Server({ environment: "test" }); expect(server2.contacts).toBeUndefined(); server2.shutdown(); }); }); describe("Unit | Server #create", function () { test("create fails when no factories or models are registered", () => { let server = new Server({ environment: "test" }); expect(function () { server.create("contact"); }).toThrow( "Mirage: You called server.create('contact') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name." ); server.shutdown(); }); test("create fails when an expected factory isn't registered", () => { let server = new Server({ environment: "test", factories: { address: Factory, }, }); expect(function () { server.create("contact"); }).toThrow( "Mirage: You called server.create('contact') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name." ); server.shutdown(); }); test("create works when models but no factories are registered", () => { let server = new Server({ environment: "test", models: { contact: Model, }, }); server.create("contact"); expect(server.db.contacts).toHaveLength(1); server.shutdown(); }); test("create adds the data to the db", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ name: "Sam", }), }, }); server.create("contact"); let contactsInDb = server.db.contacts; expect(contactsInDb).toHaveLength(1); expect(contactsInDb[0]).toEqual({ id: "1", name: "Sam" }); server.shutdown(); }); test("create returns the new data in the db", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ name: "Sam", }), }, }); let contact = server.create("contact"); expect(contact).toEqual({ id: "1", name: "Sam" }); server.shutdown(); }); test("create allows for attr overrides", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ name: "Sam", }), }, }); let sam = server.create("contact"); let link = server.create("contact", { name: "Link" }); expect(sam).toEqual({ id: "1", name: "Sam" }); expect(link).toEqual({ id: "2", name: "Link" }); server.shutdown(); }); test("create allows for attr overrides with extended factories", () => { let ContactFactory = Factory.extend({ name: "Link", age: 500, }); let FriendFactory = ContactFactory.extend({ is_young() { return this.age < 18; }, }); let server = new Server({ environment: "test", factories: { contact: ContactFactory, friend: FriendFactory, }, }); let link = server.create("friend"); let youngLink = server.create("friend", { age: 10 }); expect(link).toEqual({ id: "1", name: "Link", age: 500, is_young: false }); expect(youngLink).toEqual({ id: "2", name: "Link", age: 10, is_young: true, }); server.shutdown(); }); test("create allows for attr overrides with arrays", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ name: ["Sam", "Carl"], }), }, }); let sam = server.create("contact"); let link = server.create("contact", { name: ["Link"] }); let noname = server.create("contact", { name: [] }); expect(sam).toEqual({ id: "1", name: ["Sam", "Carl"] }); expect(link).toEqual({ id: "2", name: ["Link"] }); expect(noname).toEqual({ id: "3", name: [] }); server.shutdown(); }); test("create allows for nested attr overrides", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ address: { streetName: "Main", streetAddress(i) { return 1000 + i; }, }, }), }, }); let contact1 = server.create("contact"); let contact2 = server.create("contact"); expect(contact1).toEqual({ id: "1", address: { streetName: "Main", streetAddress: 1000 }, }); expect(contact2).toEqual({ id: "2", address: { streetName: "Main", streetAddress: 1001 }, }); server.shutdown(); }); test("factories can have dynamic properties that depend on attr overrides", () => { let server = new Server({ environment: "test", factories: { baz: Factory.extend({ bar() { return this.name.substr(1); }, }), }, }); let baz1 = server.create("baz", { name: "foo" }); expect(baz1).toEqual({ id: "1", name: "foo", bar: "oo" }); server.shutdown(); }); test("create allows for arrays of attr overrides", () => { let server = new Server({ environment: "test", factories: { contact: Factory.extend({ websites: [ "http://example.com", function (i) { return `http://placekitten.com/${320 + i}/${240 + i}`; }, ], }), }, }); let contact1 = server.create("contact"); let contact2 = server.create("contact"); expect(contact1).toEqual({ id: "1", websites: ["http://example.com", "http://placekitten.com/320/240"], }); expect(contact2).toEqual({ id: "2", websites: ["http://example.com", "http://placekitten.com/321/241"], }); server.shutdown(); }); test("create allows to extend factory with trait", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, }, }); let article = server.create("article"); let publishedArticle = server.create("article", "published"); expect(article).toEqual({ id: "1", title: "Lorem ipsum" }); expect(publishedArticle).toEqual({ id: "2", title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", }); server.shutdown(); }); test("create allows to extend factory with multiple traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, }, }); let article = server.create("article"); let publishedArticle = server.create("article", "published"); let publishedArticleWithContent = server.create( "article", "published", "withContent" ); expect(article).toEqual({ id: "1", title: "Lorem ipsum" }); expect(publishedArticle).toEqual({ id: "2", title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", }); expect(publishedArticleWithContent).toEqual({ id: "3", title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); server.shutdown(); }); test("create allows to extend factory with traits containing afterCreate callbacks", () => { let CommentFactory = Factory.extend({ content: "content", }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withComments: trait({ afterCreate(article, server) { server.createList("comment", 3, { article }); }, }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, comment: CommentFactory, }, }); let articleWithComments = server.create("article", "withComments"); expect(articleWithComments).toEqual({ id: "1", title: "Lorem ipsum" }); expect(server.db.comments).toHaveLength(3); server.shutdown(); }); test("create does not execute afterCreate callbacks from traits that are not applied", () => { let CommentFactory = Factory.extend({ content: "content", }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withComments: trait({ afterCreate(article, server) { server.createList("comment", 3, { article }); }, }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, comment: CommentFactory, }, }); let articleWithComments = server.create("article"); expect(articleWithComments).toEqual({ id: "1", title: "Lorem ipsum" }); expect(server.db.comments).toHaveLength(0); server.shutdown(); }); test("create allows to extend with multiple traits and to apply attr overrides", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, }, }); let overrides = { publishedAt: "2012-01-01 10:00:00", }; let publishedArticleWithContent = server.create( "article", "published", "withContent", overrides ); expect(publishedArticleWithContent).toEqual({ id: "1", title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); server.shutdown(); }); test("create throws errors when using trait that is not defined and distinquishes between traits and non-traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), private: { someAttr: "value", }, }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, }, }); expect(() => { server.create("article", "private"); }).toThrow("'private' trait is not registered in 'article' factory"); server.shutdown(); }); test("create allows to create objects with associations", () => { let AuthorFactory = Factory.extend({ name: "Sam", }); let CategoryFactory = Factory.extend({ name: "splendid software", }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withCategory: trait({ awesomeCategory: association(), }), author: association(), }); let server = new Server({ environment: "test", models: { author: Model.extend({ articles: hasMany(), }), category: Model.extend({}), article: Model.extend({ author: belongsTo(), awesomeCategory: belongsTo("category"), }), }, factories: { article: ArticleFactory, author: AuthorFactory, category: CategoryFactory, }, }); let article = server.create("article", "withCategory"); expect(article.attrs).toEqual({ title: "Lorem ipsum", id: "1", authorId: "1", awesomeCategoryId: "1", }); expect(server.db.authors).toHaveLength(1); expect(server.db.categories).toHaveLength(1); let anotherArticle = server.create("article", "withCategory"); expect(anotherArticle.attrs).toEqual({ title: "Lorem ipsum", id: "2", authorId: "2", awesomeCategoryId: "2", }); expect(server.db.authors).toHaveLength(2); expect(server.db.categories).toHaveLength(2); server.shutdown(); }); test("create allows to create objects with associations with traits and overrides for associations", () => { let CategoryFactory = Factory.extend({ name: "splendid software", published: trait({ isPublished: true, publishedAt: "2014-01-01 10:00:00", }), }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withCategory: trait({ category: association("published", { publishedAt: "2016-01-01 12:00:00", }), }), }); let server = new Server({ environment: "test", factories: { article: ArticleFactory, category: CategoryFactory, }, models: { category: Model.extend({}), article: Model.extend({ category: belongsTo("category"), }), }, }); let article = server.create("article", "withCategory"); expect(article.attrs).toEqual({ title: "Lorem ipsum", id: "1", categoryId: "1", }); expect(server.db.categories).toHaveLength(1); expect(server.db.categories[0]).toEqual({ name: "splendid software", id: "1", isPublished: true, publishedAt: "2016-01-01 12:00:00", }); server.shutdown(); }); test("create does not create (extra) models on associations when they are passed in as overrides", () => { let MotherFactory = Factory.extend({ name: "Should not create", }); let ChildFactory = Factory.extend({ mother: association(), }); let server = new Server({ environment: "test", factories: { mother: MotherFactory, child: ChildFactory, }, models: { mother: Model.extend({ children: hasMany("child"), }), child: Model.extend({ mother: belongsTo("mother"), }), }, }); let mother = server.create("mother", { name: "Lynda" }); server.create("child", { name: "Don", mother }); server.create("child", { name: "Dan", mother }); expect(server.db.mothers).toHaveLength(1); server.shutdown(); }); }); describe("Unit | Server #createList", function () { let server = null; beforeEach(function () { server = new Server({ environment: "test" }); }); afterEach(function () { server.shutdown(); }); test("createList adds the given number of elements to the db", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); server.createList("contact", 3); let contactsInDb = server.db.contacts; expect(contactsInDb).toHaveLength(3); expect(contactsInDb[0]).toEqual({ id: "1", name: "Sam" }); expect(contactsInDb[1]).toEqual({ id: "2", name: "Sam" }); expect(contactsInDb[2]).toEqual({ id: "3", name: "Sam" }); }); test("createList returns the created elements", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); server.create("contact"); let contacts = server.createList("contact", 3); expect(contacts).toHaveLength(3); expect(contacts[0]).toEqual({ id: "2", name: "Sam" }); expect(contacts[1]).toEqual({ id: "3", name: "Sam" }); expect(contacts[2]).toEqual({ id: "4", name: "Sam" }); }); test("createList respects sequences", () => { server.loadFactories({ contact: Factory.extend({ name(i) { return `name${i}`; }, }), }); let contacts = server.createList("contact", 3); expect(contacts[0]).toEqual({ id: "1", name: "name0" }); expect(contacts[1]).toEqual({ id: "2", name: "name1" }); expect(contacts[2]).toEqual({ id: "3", name: "name2" }); }); test("createList respects attr overrides", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); let sams = server.createList("contact", 2); let links = server.createList("contact", 2, { name: "Link" }); expect(sams[0]).toEqual({ id: "1", name: "Sam" }); expect(sams[1]).toEqual({ id: "2", name: "Sam" }); expect(links[0]).toEqual({ id: "3", name: "Link" }); expect(links[1]).toEqual({ id: "4", name: "Link" }); }); test("createList respects traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let articles = server.createList("article", 2, "published", "withContent"); expect(articles[0]).toEqual({ id: "1", title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); expect(articles[1]).toEqual({ id: "2", title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); }); test("createList respects traits with attr overrides", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let overrides = { publishedAt: "2012-01-01 10:00:00" }; let articles = server.createList( "article", 2, "published", "withContent", overrides ); expect(articles[0]).toEqual({ id: "1", title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); expect(articles[1]).toEqual({ id: "2", title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); }); test("createList throws errors when using trait that is not defined and distinquishes between traits and non-traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), private: { someAttr: "value", }, }); server.loadFactories({ article: ArticleFactory, }); expect(() => { server.createList("article", 2, "private"); }).toThrow("'private' trait is not registered in 'article' factory"); }); test("createList throws an error if the second argument is not an integer", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), }); server.loadFactories({ article: ArticleFactory, }); expect(() => { server.createList("article", "published"); }).toThrow( "Mirage: second argument has to be an integer, you passed: string" ); }); }); describe("Unit | Server #build", function () { let server = null; beforeEach(function () { server = new Server({ environment: "test" }); }); afterEach(function () { server.shutdown(); }); test("build does not add the data to the db", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); server.build("contact"); let contactsInDb = server.db.contacts; expect(contactsInDb).toHaveLength(0); }); test("build returns the new attrs with no id", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); let contact = server.build("contact"); expect(contact).toEqual({ name: "Sam" }); }); test("build allows for attr overrides", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); let sam = server.build("contact"); let link = server.build("contact", { name: "Link" }); expect(sam).toEqual({ name: "Sam" }); expect(link).toEqual({ name: "Link" }); }); test("build allows for attr overrides with extended factories", () => { let ContactFactory = Factory.extend({ name: "Link", age: 500, }); let FriendFactory = ContactFactory.extend({ is_young() { return this.age < 18; }, }); server.loadFactories({ contact: ContactFactory, friend: FriendFactory, }); let link = server.build("friend"); let youngLink = server.build("friend", { age: 10 }); expect(link).toEqual({ name: "Link", age: 500, is_young: false }); expect(youngLink).toEqual({ name: "Link", age: 10, is_young: true }); }); test("build allows for attr overrides with arrays", () => { server.loadFactories({ contact: Factory.extend({ name: ["Sam", "Carl"] }), }); let sam = server.build("contact"); let link = server.build("contact", { name: ["Link"] }); let noname = server.build("contact", { name: [] }); expect(sam).toEqual({ name: ["Sam", "Carl"] }); expect(link).toEqual({ name: ["Link"] }); expect(noname).toEqual({ name: [] }); }); test("build allows for nested attr overrides", () => { server.loadFactories({ contact: Factory.extend({ address: { streetName: "Main", streetAddress(i) { return 1000 + i; }, }, }), }); let contact1 = server.build("contact"); let contact2 = server.build("contact"); expect(contact1).toEqual({ address: { streetName: "Main", streetAddress: 1000 }, }); expect(contact2).toEqual({ address: { streetName: "Main", streetAddress: 1001 }, }); }); test("build allows for arrays of attr overrides", () => { server.loadFactories({ contact: Factory.extend({ websites: [ "http://example.com", function (i) { return `http://placekitten.com/${320 + i}/${240 + i}`; }, ], }), }); let contact1 = server.build("contact"); let contact2 = server.build("contact"); expect(contact1).toEqual({ websites: ["http://example.com", "http://placekitten.com/320/240"], }); expect(contact2).toEqual({ websites: ["http://example.com", "http://placekitten.com/321/241"], }); }); test("build allows to extend factory with trait", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), }); server.loadFactories({ article: ArticleFactory, }); let article = server.build("article"); let publishedArticle = server.build("article", "published"); expect(article).toEqual({ title: "Lorem ipsum" }); expect(publishedArticle).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", }); }); test("build allows to extend factory with multiple traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let article = server.build("article"); let publishedArticle = server.build("article", "published"); let publishedArticleWithContent = server.build( "article", "published", "withContent" ); expect(article).toEqual({ title: "Lorem ipsum" }); expect(publishedArticle).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", }); expect(publishedArticleWithContent).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); }); test("build allows to extend with multiple traits and to apply attr overrides", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let overrides = { publishedAt: "2012-01-01 10:00:00", }; let publishedArticleWithContent = server.build( "article", "published", "withContent", overrides ); expect(publishedArticleWithContent).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); }); test("build allows to build objects with associations", () => { let AuthorFactory = Factory.extend({ name: "Yehuda", }); let CategoryFactory = Factory.extend({ name: "splendid software", }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withCategory: trait({ awesomeCategory: association(), }), someOtherTrait: trait({ user: association(), }), author: association(), }); server.loadFactories({ article: ArticleFactory, author: AuthorFactory, category: CategoryFactory, }); server.schema.registerModels({ author: Model.extend({ articles: hasMany(), }), category: Model.extend({}), article: Model.extend({ author: belongsTo(), awesomeCategory: belongsTo("category"), }), }); let article = server.build("article", "withCategory"); expect(article).toEqual({ title: "Lorem ipsum", authorId: "1", awesomeCategoryId: "1", }); expect(server.db.authors).toHaveLength(1); expect(server.db.categories).toHaveLength(1); }); test("build allows to build objects with associations with traits and overrides for associations", () => { let CategoryFactory = Factory.extend({ name: "splendid software", published: trait({ isPublished: true, publishedAt: "2014-01-01 10:00:00", }), }); let ArticleFactory = Factory.extend({ title: "Lorem ipsum", withCategory: trait({ category: association("published", { publishedAt: "2016-01-01 12:00:00", }), }), }); server.config({ factories: { article: ArticleFactory, category: CategoryFactory, }, models: { category: Model.extend({}), article: Model.extend({ category: belongsTo(), }), }, }); let article = server.build("article", "withCategory"); expect(article).toEqual({ title: "Lorem ipsum", categoryId: "1" }); expect(server.db.categories).toHaveLength(1); expect(server.db.categories[0]).toEqual({ name: "splendid software", id: "1", isPublished: true, publishedAt: "2016-01-01 12:00:00", }); }); test("build throws errors when using trait that is not defined and distinquishes between traits and non-traits", () => { server.config({ factories: { article: Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), private: { someAttr: "value", }, }), }, }); expect(() => { server.build("article", "private"); }).toThrow("'private' trait is not registered in 'article' factory"); }); test("build does not build objects and throws error if model is not registered and association helper is used", () => { server.config({ factories: { article: Factory.extend({ title: "Lorem ipsum", withCategory: trait({ category: association("published", { publishedAt: "2016-01-01 12:00:00", }), }), }), category: Factory.extend({ name: "splendid software", published: trait({ isPublished: true, publishedAt: "2014-01-01 10:00:00", }), }), }, models: { category: Model.extend(), }, }); expect(() => { server.build("article", "withCategory"); }).toThrow("Mirage: Model not registered: article"); }); test("build does not build objects and throws error if model for given association is not registered", () => { server.config({ factories: { article: Factory.extend({ title: "Lorem ipsum", withCategory: trait({ category: association("published", { publishedAt: "2016-01-01 12:00:00", }), }), }), category: Factory.extend({ name: "splendid software", published: trait({ isPublished: true, publishedAt: "2014-01-01 10:00:00", }), }), }, models: { article: Model.extend(), }, }); expect(() => { server.build("article", "withCategory"); }).toThrow( "Mirage: You're using the `association` factory helper on the 'category' attribute of your article factory, but that attribute is not a `belongsTo` association." ); }); }); describe("Unit | Server #buildList", function () { let server = null; beforeEach(function () { server = new Server({ environment: "test" }); }); afterEach(function () { server.shutdown(); }); test("buildList does not add elements to the db", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); server.buildList("contact", 3); let contactsInDb = server.db.contacts; expect(contactsInDb).toHaveLength(0); }); test("buildList returns the built elements without ids", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); server.create("contact"); let contacts = server.buildList("contact", 3); expect(contacts).toHaveLength(3); expect(contacts[0]).toEqual({ name: "Sam" }); expect(contacts[1]).toEqual({ name: "Sam" }); expect(contacts[2]).toEqual({ name: "Sam" }); }); test("buildList respects sequences", () => { server.loadFactories({ contact: Factory.extend({ name(i) { return `name${i}`; }, }), }); let contacts = server.buildList("contact", 3); expect(contacts[0]).toEqual({ name: "name0" }); expect(contacts[1]).toEqual({ name: "name1" }); expect(contacts[2]).toEqual({ name: "name2" }); }); test("buildList respects attr overrides", () => { server.loadFactories({ contact: Factory.extend({ name: "Sam" }), }); let sams = server.buildList("contact", 2); let links = server.buildList("contact", 2, { name: "Link" }); expect(sams[0]).toEqual({ name: "Sam" }); expect(sams[1]).toEqual({ name: "Sam" }); expect(links[0]).toEqual({ name: "Link" }); expect(links[1]).toEqual({ name: "Link" }); }); test("buildList respects traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let articles = server.buildList("article", 2, "published", "withContent"); expect(articles[0]).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); expect(articles[1]).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2010-01-01 10:00:00", content: "content", }); }); test("buildList respects traits with attr overrides", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), withContent: trait({ content: "content", }), }); server.loadFactories({ article: ArticleFactory, }); let overrides = { publishedAt: "2012-01-01 10:00:00" }; let articles = server.buildList( "article", 2, "published", "withContent", overrides ); expect(articles[0]).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); expect(articles[1]).toEqual({ title: "Lorem ipsum", isPublished: true, publishedAt: "2012-01-01 10:00:00", content: "content", }); }); test("buildList throws errors when using trait that is not defined and distinquishes between traits and non-traits", () => { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), private: { someAttr: "value", }, }); server.loadFactories({ article: ArticleFactory, }); expect(() => { server.buildList("article", 2, "private"); }).toThrow("'private' trait is not registered in 'article' factory"); }); test("buildList throws an error if the second argument is not an integer", function () { let ArticleFactory = Factory.extend({ title: "Lorem ipsum", published: trait({ isPublished: true, publishedAt: "2010-01-01 10:00:00", }), }); server.loadFactories({ article: ArticleFactory, }); expect(() => { server.buildList("article", "published"); }).toThrow( "Mirage: second argument has to be an integer, you passed: string" ); }); }); miragejs-0.1.42/babel.config.js000066400000000000000000000002321412317504700162470ustar00rootroot00000000000000module.exports = { presets: [ [ "@babel/preset-env", { targets: { node: "current", }, }, ], ], }; miragejs-0.1.42/index.js000066400000000000000000000001011412317504700150400ustar00rootroot00000000000000"use strict"; module.exports = require("./dist/mirage-cjs.js"); miragejs-0.1.42/jest.config.js000066400000000000000000000050711412317504700161550ustar00rootroot00000000000000let internal = { displayName: "internal", setupFilesAfterEnv: ["jest-extended"], testMatch: ["**/__tests__/internal/**/*-test.[jt]s?(x)"], moduleNameMapper: { "@lib(.*)": "/lib$1", "^miragejs$": "/lib/index", }, }; // External API, Create React App-like environment. let browserEnvironmentConsumingEsm = { displayName: "browserEnvironmentConsumingEsm", testEnvironment: "jsdom", setupFilesAfterEnv: ["jest-extended"], testMatch: [ "**/__tests__/external/shared/**/*-test.[jt]s?(x)", "**/__tests__/external/browser-only/**/*-test.[jt]s?(x)", ], moduleNameMapper: { "^miragejs$": "/dist/mirage-esm.js", }, }; // External API, Gatsby-like environment (SSR of client-side code) let nodeEnvironmentConsumingEsm = { displayName: "nodeEnvironmentConsumingEsm", testEnvironment: "node", setupFilesAfterEnv: ["jest-extended"], testMatch: [ "**/__tests__/external/shared/**/*-test.[jt]s?(x)", "**/__tests__/external/node-only/**/*-test.[jt]s?(x)", ], moduleNameMapper: { "^miragejs$": "/dist/mirage-esm.js", }, }; // External API, Create React App-like environment. let browserEnvironmentConsumingCjs = { displayName: "browserEnvironmentConsumingCjs", testEnvironment: "jsdom", setupFilesAfterEnv: ["jest-extended"], testMatch: [ "**/__tests__/external/shared/**/*-test.[jt]s?(x)", "**/__tests__/external/browser-only/**/*-test.[jt]s?(x)", ], moduleNameMapper: { "^miragejs$": "/dist/mirage-cjs", }, }; // External API, Gatsby-like environment (SSR of client-side code) let nodeEnvironmentConsumingCjs = { displayName: "nodeEnvironmentConsumingCjs", testEnvironment: "node", setupFilesAfterEnv: ["jest-extended"], testMatch: [ "**/__tests__/external/shared/**/*-test.[jt]s?(x)", "**/__tests__/external/node-only/**/*-test.[jt]s?(x)", ], moduleNameMapper: { "^miragejs$": "/dist/mirage-cjs", }, }; // External API, script tag or Code Sandbox let browserEnvironmentConsumingUmd = { displayName: "browserEnvironmentConsumingUmd", testEnvironment: "jsdom", setupFilesAfterEnv: ["jest-extended"], testMatch: [ "**/__tests__/external/shared/**/*-test.[jt]s?(x)", "**/__tests__/external/browser-only/**/*-test.[jt]s?(x)", ], moduleNameMapper: { "^miragejs$": "/dist/mirage-umd.js", }, }; module.exports = { projects: [ internal, browserEnvironmentConsumingEsm, nodeEnvironmentConsumingEsm, browserEnvironmentConsumingCjs, nodeEnvironmentConsumingCjs, browserEnvironmentConsumingUmd, ], }; miragejs-0.1.42/lib/000077500000000000000000000000001412317504700141515ustar00rootroot00000000000000miragejs-0.1.42/lib/assert.js000066400000000000000000000016621412317504700160150ustar00rootroot00000000000000/* eslint no-console: 0 */ let errorProps = [ "description", "fileName", "lineNumber", "message", "name", "number", "stack", ]; /** @hide */ export default function assert(bool, text) { if (typeof bool === "string" && !text) { // console.error(`Mirage: ${bool}`); throw new MirageError(bool); } if (!bool) { // console.error(`Mirage: ${text}`); throw new MirageError(text.replace(/^ +/gm, "") || "Assertion failed"); } } /** @public @hide Copied from ember-metal/error */ export function MirageError(message, stack) { let tmp = Error(message); if (stack) { tmp.stack = stack; } for (let idx = 0; idx < errorProps.length; idx++) { let prop = errorProps[idx]; if (["description", "message", "stack"].indexOf(prop) > -1) { this[prop] = `Mirage: ${tmp[prop]}`; } else { this[prop] = tmp[prop]; } } } MirageError.prototype = Object.create(Error.prototype); miragejs-0.1.42/lib/association.js000066400000000000000000000003041412317504700170200ustar00rootroot00000000000000/** @hide */ let association = function (...traitsAndOverrides) { let __isAssociation__ = true; return { __isAssociation__, traitsAndOverrides, }; }; export default association; miragejs-0.1.42/lib/container.js000066400000000000000000000030641412317504700164740ustar00rootroot00000000000000import { singularize, pluralize } from "inflected"; import Db from "./db"; import Association from "./orm/associations/association"; import RouteHandler from "./route-handler"; import BaseRouteHandler from "./route-handlers/base"; import Serializer from "./serializer"; import SerializerRegistry from "./serializer-registry"; import Schema from "./orm/schema"; const classes = { Db, Association, RouteHandler, BaseRouteHandler, Serializer, SerializerRegistry, Schema, }; let defaultInflector = { singularize, pluralize }; /** Lightweight DI container for customizable objects that are needed by deeply nested classes. @class Container @hide */ class Container { constructor() { this.inflector = defaultInflector; } register(key, value) { this[key] = value; } create(className, ...args) { let Class = classes[className]; Class.prototype._container = this; return new Class(...args); } } /** These are side effects. We give each class a default container so it can be easily unit tested. We should remove these once we have test coverage and can refactor to a proper DI system. */ let defaultContainer = new Container(); Db.prototype._container = defaultContainer; Association.prototype._container = defaultContainer; BaseRouteHandler.prototype._container = defaultContainer; RouteHandler.prototype._container = defaultContainer; Serializer.prototype._container = defaultContainer; SerializerRegistry.prototype._container = defaultContainer; Schema.prototype._container = defaultContainer; export default Container; miragejs-0.1.42/lib/db-collection.js000066400000000000000000000252041412317504700172300ustar00rootroot00000000000000import isEqual from "lodash.isequal"; import map from "lodash.map"; function duplicate(data) { if (Array.isArray(data)) { return data.map(duplicate); } else { return Object.assign({}, data); } } /** Mirage's `Db` has many `DbCollections`, which are equivalent to tables from traditional databases. They store specific types of data, for example `users` and `posts`. `DbCollections` have names, like `users`, which you use to access the collection from the `Db` object. Suppose you had a `user` model defined, and the following data had been inserted into your database (either through factories or fixtures): ```js export default [ { id: 1, name: 'Zelda' }, { id: 2, name: 'Link' } ]; ``` Then `db.contacts` would return this array. @class DbCollection @constructor @public */ class DbCollection { constructor(name, initialData, IdentityManager) { this.name = name; this._records = []; this.identityManager = new IdentityManager(); if (initialData) { this.insert(initialData); } } /** * Returns a copy of the data, to prevent inadvertent data manipulation. * @method all * @public * @hide */ all() { return duplicate(this._records); } /** Inserts `data` into the collection. `data` can be a single object or an array of objects. Returns the inserted record. ```js // Insert a single record let link = db.users.insert({ name: 'Link', age: 173 }); link; // { id: 1, name: 'Link', age: 173 } // Insert an array let users = db.users.insert([ { name: 'Zelda', age: 142 }, { name: 'Epona', age: 58 }, ]); users; // [ { id: 2, name: 'Zelda', age: 142 }, { id: 3, name: 'Epona', age: 58 } ] ``` @method insert @param data @public */ insert(data) { if (!Array.isArray(data)) { return this._insertRecord(data); } else { return map(data, (attrs) => this._insertRecord(attrs)); } } /** Returns a single record from the `collection` if `ids` is a single id, or an array of records if `ids` is an array of ids. Note each id can be an int or a string, but integer ids as strings (e.g. the string “1”) will be treated as integers. ```js // Given users = [{id: 1, name: 'Link'}, {id: 2, name: 'Zelda'}] db.users.find(1); // {id: 1, name: 'Link'} db.users.find([1, 2]); // [{id: 1, name: 'Link'}, {id: 2, name: 'Zelda'}] ``` @method find @param ids @public */ find(ids) { if (Array.isArray(ids)) { let records = this._findRecords(ids).filter(Boolean).map(duplicate); // Return a copy return records; } else { let record = this._findRecord(ids); if (!record) { return null; } // Return a copy return duplicate(record); } } /** Returns the first model from `collection` that matches the key-value pairs in the `query` object. Note that a string comparison is used. `query` is a POJO. ```js // Given users = [ { id: 1, name: 'Link' }, { id: 2, name: 'Zelda' } ] db.users.findBy({ name: 'Link' }); // { id: 1, name: 'Link' } ``` @method find @param query @public */ findBy(query) { let record = this._findRecordBy(query); if (!record) { return null; } // Return a copy return duplicate(record); } /** Returns an array of models from `collection` that match the key-value pairs in the `query` object. Note that a string comparison is used. `query` is a POJO. ```js // Given users = [ { id: 1, name: 'Link' }, { id: 2, name: 'Zelda' } ] db.users.where({ name: 'Zelda' }); // [ { id: 2, name: 'Zelda' } ] ``` @method where @param query @public */ where(query) { return this._findRecordsWhere(query).map(duplicate); } /** Finds the first record matching the provided _query_ in `collection`, or creates a new record using a merge of the `query` and optional `attributesForCreate`. Often times you may have a pattern like the following in your API stub: ```js // Given users = [ // { id: 1, name: 'Link' }, // { id: 2, name: 'Zelda' } // ] // Create Link if he doesn't yet exist let records = db.users.where({ name: 'Link' }); let record; if (records.length > 0) { record = records[0]; } else { record = db.users.insert({ name: 'Link' }); } ``` You can now replace this with the following: ```js let record = db.users.firstOrCreate({ name: 'Link' }); ``` An extended example using *attributesForCreate*: ```js let record = db.users.firstOrCreate({ name: 'Link' }, { evil: false }); ``` @method firstOrCreate @param query @param attributesForCreate @public */ firstOrCreate(query, attributesForCreate = {}) { let queryResult = this.where(query); let [record] = queryResult; if (record) { return record; } else { let mergedAttributes = Object.assign(attributesForCreate, query); let createdRecord = this.insert(mergedAttributes); return createdRecord; } } /** Updates one or more records in the collection. If *attrs* is the only arg present, updates all records in the collection according to the key-value pairs in *attrs*. If *target* is present, restricts updates to those that match *target*. If *target* is a number or string, finds a single record whose id is *target* to update. If *target* is a POJO, queries *collection* for records that match the key-value pairs in *target*, and updates their *attrs*. Returns the updated record or records. ```js // Given users = [ // {id: 1, name: 'Link'}, // {id: 2, name: 'Zelda'} // ] db.users.update({name: 'Ganon'}); // db.users = [{id: 1, name: 'Ganon'}, {id: 2, name: 'Ganon'}] db.users.update(1, {name: 'Young Link'}); // db.users = [{id: 1, name: 'Young Link'}, {id: 2, name: 'Zelda'}] db.users.update({name: 'Link'}, {name: 'Epona'}); // db.users = [{id: 1, name: 'Epona'}, {id: 2, name: 'Zelda'}] ``` @method update @param target @param attrs @public */ update(target, attrs) { let records; if (typeof attrs === "undefined") { attrs = target; let changedRecords = []; this._records.forEach((record) => { let oldRecord = Object.assign({}, record); this._updateRecord(record, attrs); if (!isEqual(oldRecord, record)) { changedRecords.push(record); } }); return changedRecords; } else if (typeof target === "number" || typeof target === "string") { let id = target; let record = this._findRecord(id); this._updateRecord(record, attrs); return record; } else if (Array.isArray(target)) { let ids = target; records = this._findRecords(ids); records.forEach((record) => { this._updateRecord(record, attrs); }); return records; } else if (typeof target === "object") { let query = target; records = this._findRecordsWhere(query); records.forEach((record) => { this._updateRecord(record, attrs); }); return records; } } /** Removes one or more records in *collection*. If *target* is undefined, removes all records. If *target* is a number or string, removes a single record using *target* as id. If *target* is a POJO, queries *collection* for records that match the key-value pairs in *target*, and removes them from the collection. ```js // Given users = [ // {id: 1, name: 'Link'}, // {id: 2, name: 'Zelda'} // ] db.users.remove(); // db.users = [] db.users.remove(1); // db.users = [{id: 2, name: 'Zelda'}] db.users.remove({name: 'Zelda'}); // db.users = [{id: 1, name: 'Link'}] ``` @method remove @param target @public */ remove(target) { let records; if (typeof target === "undefined") { this._records = []; this.identityManager.reset(); } else if (typeof target === "number" || typeof target === "string") { let record = this._findRecord(target); let index = this._records.indexOf(record); this._records.splice(index, 1); } else if (Array.isArray(target)) { records = this._findRecords(target); records.forEach((record) => { let index = this._records.indexOf(record); this._records.splice(index, 1); }); } else if (typeof target === "object") { records = this._findRecordsWhere(target); records.forEach((record) => { let index = this._records.indexOf(record); this._records.splice(index, 1); }); } } /* Private methods. These return the actual db objects, whereas the public API query methods return copies. */ /** @method _findRecord @param id @private @hide */ _findRecord(id) { id = id.toString(); return this._records.find((obj) => obj.id === id); } /** @method _findRecordBy @param query @private @hide */ _findRecordBy(query) { return this._findRecordsWhere(query)[0]; } /** @method _findRecords @param ids @private @hide */ _findRecords(ids) { return ids.map(this._findRecord, this); } /** @method _findRecordsWhere @param query @private @hide */ _findRecordsWhere(query) { let records = this._records; function defaultQueryFunction(record) { let keys = Object.keys(query); return keys.every(function (key) { return String(record[key]) === String(query[key]); }); } let queryFunction = typeof query === "object" ? defaultQueryFunction : query; return records.filter(queryFunction); } /** @method _insertRecord @param data @private @hide */ _insertRecord(data) { let attrs = duplicate(data); if (attrs && (attrs.id === undefined || attrs.id === null)) { attrs.id = this.identityManager.fetch(attrs); } else { attrs.id = attrs.id.toString(); this.identityManager.set(attrs.id); } this._records.push(attrs); return duplicate(attrs); } /** @method _updateRecord @param record @param attrs @private @hide */ _updateRecord(record, attrs) { let targetId = attrs && Object.prototype.hasOwnProperty.call(attrs, "id") ? attrs.id.toString() : null; let currentId = record.id; if (targetId && currentId !== targetId) { throw new Error("Updating the ID of a record is not permitted"); } for (let attr in attrs) { if (attr === "id") { continue; } record[attr] = attrs[attr]; } } } export default DbCollection; miragejs-0.1.42/lib/db.js000066400000000000000000000110221412317504700150700ustar00rootroot00000000000000import DbCollection from "./db-collection"; import IdentityManager from "./identity-manager"; import cloneDeep from "lodash.clonedeep"; /** Your Mirage server has a database which you can interact with in your route handlers. You’ll typically use models to interact with your database data, but you can always reach into the db directly in the event you want more control. Access the db from your route handlers via `schema.db`. You can access individual DbCollections by using `schema.db.name`: ```js schema.db.users // would return, e.g., [ { id: 1, name: 'Yehuda' }, { id: 2, name: 'Tom '} ] ``` @class Db @constructor @public */ class Db { constructor(initialData, identityManagers) { this._collections = []; this.registerIdentityManagers(identityManagers); if (initialData) { this.loadData(initialData); } } /** Loads an object of data into Mirage's database. The keys of the object correspond to the DbCollections, and the values are arrays of records. ```js server.db.loadData({ users: [ { name: 'Yehuda' }, { name: 'Tom' } ] }); ``` As with `db.collection.insert`, IDs will automatically be created for records that don't have them. @method loadData @param {Object} data - Data to load @public */ loadData(data) { for (let key in data) { this.createCollection(key, cloneDeep(data[key])); } } /** Logs out the contents of the Db. ```js server.db.dump() // { users: [ name: 'Yehuda', ... ``` @method dump @public */ dump() { return this._collections.reduce((data, collection) => { data[collection.name] = collection.all(); return data; }, {}); } /** Add an empty collection named _name_ to your database. Typically you won’t need to do this yourself, since collections are automatically created for any models you have defined. @method createCollection @param name @param initialData (optional) @public */ createCollection(name, initialData) { if (!this[name]) { let IdentityManager = this.identityManagerFor(name); let newCollection = new DbCollection(name, initialData, IdentityManager); // Public API has a convenient array interface. It comes at the cost of // returning a copy of all records to avoid accidental mutations. Object.defineProperty(this, name, { get() { let recordsCopy = newCollection.all(); [ "insert", "find", "findBy", "where", "update", "remove", "firstOrCreate", ].forEach(function (method) { recordsCopy[method] = function () { return newCollection[method](...arguments); }; }); return recordsCopy; }, }); // Private API does not have the array interface. This means internally, only // db-collection methods can be used. This is so records aren't copied redundantly // internally, which leads to accidental O(n^2) operations (e.g., createList). Object.defineProperty(this, `_${name}`, { get() { let recordsCopy = []; [ "insert", "find", "findBy", "where", "update", "remove", "firstOrCreate", ].forEach(function (method) { recordsCopy[method] = function () { return newCollection[method](...arguments); }; }); return recordsCopy; }, }); this._collections.push(newCollection); } else if (initialData) { this[name].insert(initialData); } return this; } /** @method createCollections @param ...collections @public @hide */ createCollections(...collections) { collections.forEach((c) => this.createCollection(c)); } /** Removes all data from Mirage's database. @method emptyData @public */ emptyData() { this._collections.forEach((c) => c.remove()); } /** @method identityManagerFor @param name @public @hide */ identityManagerFor(name) { return ( this._identityManagers[this._container.inflector.singularize(name)] || this._identityManagers.application || IdentityManager ); } /** @method registerIdentityManagers @public @hide */ registerIdentityManagers(identityManagers) { this._identityManagers = identityManagers || {}; } } export default Db; miragejs-0.1.42/lib/factory.js000066400000000000000000000066711412317504700161700ustar00rootroot00000000000000import isPlainObject from "lodash.isplainobject"; import isFunction from "lodash.isfunction"; import mapValues from "lodash.mapvalues"; import referenceSort from "./utils/reference-sort"; let Factory = function () { this.build = function (sequence) { let object = {}; let topLevelAttrs = Object.assign({}, this.attrs); delete topLevelAttrs.afterCreate; Object.keys(topLevelAttrs).forEach((attr) => { if (Factory.isTrait.call(this, attr)) { delete topLevelAttrs[attr]; } }); let keys = sortAttrs(topLevelAttrs, sequence); keys.forEach(function (key) { let buildAttrs, buildSingleValue; buildAttrs = function (attrs) { return mapValues(attrs, buildSingleValue); }; buildSingleValue = (value) => { if (Array.isArray(value)) { return value.map(buildSingleValue); } else if (isPlainObject(value)) { return buildAttrs(value); } else if (isFunction(value)) { return value.call(topLevelAttrs, sequence); } else { return value; } }; let value = topLevelAttrs[key]; if (isFunction(value)) { object[key] = value.call(object, sequence); } else { object[key] = buildSingleValue(value); } }); return object; }; }; Factory.extend = function (attrs) { // Merge the new attributes with existing ones. If conflict, new ones win. let newAttrs = Object.assign({}, this.attrs, attrs); let Subclass = function () { this.attrs = newAttrs; Factory.call(this); }; // Copy extend Subclass.extend = Factory.extend; Subclass.extractAfterCreateCallbacks = Factory.extractAfterCreateCallbacks; Subclass.isTrait = Factory.isTrait; // Store a reference on the class for future subclasses Subclass.attrs = newAttrs; return Subclass; }; Factory.extractAfterCreateCallbacks = function ({ traits } = {}) { let afterCreateCallbacks = []; let attrs = this.attrs || {}; let traitCandidates; if (attrs.afterCreate) { afterCreateCallbacks.push(attrs.afterCreate); } if (Array.isArray(traits)) { traitCandidates = traits; } else { traitCandidates = Object.keys(attrs); } traitCandidates .filter((attr) => { return this.isTrait(attr) && attrs[attr].extension.afterCreate; }) .forEach((attr) => { afterCreateCallbacks.push(attrs[attr].extension.afterCreate); }); return afterCreateCallbacks; }; Factory.isTrait = function (attrName) { let { attrs } = this; return isPlainObject(attrs[attrName]) && attrs[attrName].__isTrait__ === true; }; function sortAttrs(attrs, sequence) { let Temp = function () {}; let obj = new Temp(); let refs = []; let property; Object.keys(attrs).forEach(function (key) { let value; Object.defineProperty(obj.constructor.prototype, key, { get() { refs.push([property, key]); return value; }, set(newValue) { value = newValue; }, enumerable: false, configurable: true, }); }); Object.keys(attrs).forEach(function (key) { let value = attrs[key]; if (typeof value !== "function") { obj[key] = value; } }); Object.keys(attrs).forEach(function (key) { let value = attrs[key]; property = key; if (typeof value === "function") { obj[key] = value.call(obj, sequence); } refs.push([key]); }); return referenceSort(refs); } /** * @hide */ export default Factory; miragejs-0.1.42/lib/identity-manager.js000066400000000000000000000042331412317504700177520ustar00rootroot00000000000000function isNumber(n) { return (+n).toString() === n.toString(); } /** By default Mirage uses autoincrementing numbers starting with `1` as IDs for records. This can be customized by implementing one or more IdentityManagers for your application. An IdentityManager is a class that's responsible for generating unique identifiers. You can define a custom identity manager for your entire application, as well as on a per-model basis. A custom IdentityManager must implement these methods: - `fetch`, which must return an identifier not yet used - `set`, which is called with an `id` of a record being insert into Mirage's database - `reset`, which should reset database to initial state Check out the advanced guide on Mocking UUIDs to see a complete example of a custom IdentityManager. @class IdentityManager @constructor @public */ class IdentityManager { constructor() { this._nextId = 1; this._ids = {}; } /** @method get @hide @private */ get() { return this._nextId; } /** Registers `uniqueIdentifier` as used. This method should throw is `uniqueIdentifier` has already been taken. @method set @param {String|Number} uniqueIdentifier @public */ set(uniqueIdentifier) { if (this._ids[uniqueIdentifier]) { throw new Error( `Attempting to use the ID ${uniqueIdentifier}, but it's already been used` ); } if (isNumber(uniqueIdentifier) && +uniqueIdentifier >= this._nextId) { this._nextId = +uniqueIdentifier + 1; } this._ids[uniqueIdentifier] = true; } /** @method inc @hide @private */ inc() { let nextValue = this.get() + 1; this._nextId = nextValue; return nextValue; } /** Returns the next unique identifier. @method fetch @return {String} Unique identifier @public */ fetch() { let id = this.get(); this._ids[id] = true; this.inc(); return id.toString(); } /** Resets the identity manager, marking all unique identifiers as available. @method reset @public */ reset() { this._nextId = 1; this._ids = {}; } } export default IdentityManager; miragejs-0.1.42/lib/index.js000066400000000000000000000066771412317504700156360ustar00rootroot00000000000000import Factory from "./factory"; import IdentityManager from "./identity-manager"; import association from "./association"; import trait from "./trait"; import Response from "./response"; import Server, { createServer, defaultPassthroughs } from "./server"; import Model from "./orm/model"; import Collection from "./orm/collection"; import Serializer from "./serializer"; import ActiveModelSerializer from "./serializers/active-model-serializer"; import JSONAPISerializer from "./serializers/json-api-serializer"; import RestSerializer from "./serializers/rest-serializer"; import HasMany from "./orm/associations/has-many"; import BelongsTo from "./orm/associations/belongs-to"; /* These are solely for ember-cli-mirage, a "privileged consumer", and should be removed once those import paths are dropped. */ import _assert from "./assert"; import _DbCollection from "./db-collection"; import _Db from "./db"; import _RouteHandler from "./route-handler"; import _SerializerRegistry from "./serializer-registry"; import _ormAssociationsAssociation from "./orm/associations/association"; import _ormAssociationsBelongsTo from "./orm/associations/belongs-to"; import _ormAssociationsHasMany from "./orm/associations/has-many"; import _ormPolymorphicCollection from "./orm/polymorphic-collection"; import _ormSchema from "./orm/schema"; import _routeHandlersShorthandsBase from "./route-handlers/shorthands/base"; import _routeHandlersShorthandsDelete from "./route-handlers/shorthands/delete"; import _routeHandlersShorthandsGet from "./route-handlers/shorthands/get"; import _routeHandlersShorthandsHead from "./route-handlers/shorthands/head"; import _routeHandlersShorthandsPost from "./route-handlers/shorthands/post"; import _routeHandlersShorthandsPut from "./route-handlers/shorthands/put"; import _routeHandlersBase from "./route-handlers/base"; import _routeHandlersFunction from "./route-handlers/function"; import _routeHandlersObject from "./route-handlers/object"; import _utilsExtend from "./utils/extend"; import { camelize as _utilsInflectorCamelize, dasherize as _utilsInflectorDasherize, underscore as _utilsInflectorUnderscore, capitalize as _utilsInflectorCapitalize, } from "./utils/inflector"; import _utilsIsAssociation from "./utils/is-association"; import _utilsReferenceSort from "./utils/reference-sort"; import _utilsUuid from "./utils/uuid"; /** @hide */ function hasMany(...args) { return new HasMany(...args); } /** @hide */ function belongsTo(...args) { return new BelongsTo(...args); } export { association, trait, Model, Collection, Serializer, ActiveModelSerializer, JSONAPISerializer, RestSerializer, hasMany, belongsTo, defaultPassthroughs, createServer, Server, Factory, IdentityManager, Response, _assert, _DbCollection, _Db, _RouteHandler, _SerializerRegistry, _ormAssociationsAssociation, _ormAssociationsBelongsTo, _ormAssociationsHasMany, _ormPolymorphicCollection, _ormSchema, _routeHandlersShorthandsBase, _routeHandlersShorthandsDelete, _routeHandlersShorthandsGet, _routeHandlersShorthandsHead, _routeHandlersShorthandsPost, _routeHandlersShorthandsPut, _routeHandlersBase, _routeHandlersFunction, _routeHandlersObject, _utilsExtend, _utilsInflectorCamelize, _utilsInflectorDasherize, _utilsInflectorUnderscore, _utilsInflectorCapitalize, _utilsIsAssociation, _utilsReferenceSort, _utilsUuid, }; export default { Factory, Response, hasMany, belongsTo, }; miragejs-0.1.42/lib/orm/000077500000000000000000000000001412317504700147465ustar00rootroot00000000000000miragejs-0.1.42/lib/orm/associations/000077500000000000000000000000001412317504700174455ustar00rootroot00000000000000miragejs-0.1.42/lib/orm/associations/association.js000066400000000000000000000132471412317504700223260ustar00rootroot00000000000000import { dasherize } from "../../utils/inflector"; /** Associations represent relationships between your Models. The `hasMany` and `belongsTo` helpers are how you actually define relationships: ```js import { createServer, Model, hasMany, belongsTo } createServer({ models: { user: Model.extend({ comments: hasMany() }), comments: Model.extend({ user: belongsTo() }) } }) ``` View [the Relationships](https://miragejs.com/docs/main-concepts/relationships/) guide to learn more about setting up relationships. Each usage of the helper registers an Association (either a `HasMany` association or `BelongsTo` association) with your server's `Schema`. You can access these associations using either the `schema.associationsFor()` method, or the `associations` property on individual model instances. You can then introspect the associations to do things like dynamically build up your JSON response in your serializers. @class Association @constructor @public */ export default class Association { constructor(modelName, opts) { /** The modelName of the associated model. For example, given this configuration ```js createServer({ models: { user: Model, comment: Model.extend({ user: belongsTo() }) } }) ``` the association's `modelName` would be `user`. Note that an association's `modelName` and the `name` can be different. This is because Mirage supports multiple relationships of the same type: ```js createServer({ models: { user: Model, comment: Model.extend({ author: belongsTo('user'), reviewer: belongsTo('user') }) } }) ``` For both these relationships, the `modelName` is `user`, but the first association has a `name` of `author` while the second has a `name` of `reviewer`. @property @type {String} @public */ this.modelName = undefined; // hack to add ESDOC info. Any better way? if (typeof modelName === "object") { // Received opts only this.modelName = undefined; this.opts = modelName; } else { // The modelName of the association. (Might not be passed in - set later // by schema). this.modelName = modelName ? dasherize(modelName) : ""; this.opts = opts || {}; } /** The name of the association, which comes from the property name that was used to define it. For example, given this server definition ```js createServer({ models: { user: Model, comment: Model.extend({ author: belongsTo('user') }) } }) ``` the association's `name` would be `author`. The name is used by Mirage to define foreign keys on the model (`comment.authorId` in this case), among other things. @property @type {String} @public */ this.name = ""; // The modelName that owns this association this.ownerModelName = ""; } /** A setter for schema, since we don't have a reference at constuction time. @method setSchema @public @hide */ setSchema(schema) { this.schema = schema; } /** Returns a Boolean that's true if the association is self-referential, i.e. if a model has an association with itself. For example, given ```js createServer({ models: { user: Model.extend({ friends: hasMany('user') }) } }) ``` then ```js server.schema.associationsFor('user').friends.isReflexive // true ``` @method isReflexive @return {Boolean} @public */ isReflexive() { let isExplicitReflexive = !!( this.modelName === this.ownerModelName && this.opts.inverse ); let isImplicitReflexive = !!( this.opts.inverse === undefined && this.ownerModelName === this.modelName ); return isExplicitReflexive || isImplicitReflexive; } /** Returns a Boolean that's true if the association is polymorphic: For example, given ```js createServer({ models: { comment: Model.extend({ commentable: belongsTo({ polymorphic: true }) }) } }) ``` then ```js server.schema.associationsFor('comment').commentable.isPolymorphic // true ``` Check out [the guides on polymorphic associations](https://miragejs.com/docs/main-concepts/relationships/#polymorphic) to learn more. @accessor isPolymorphic @type {Boolean} @public */ get isPolymorphic() { return this.opts.polymorphic; } /** Returns either the string `"hasMany"` or `"belongsTo"`, based on the association type. @accessor @type {String} @public */ get type() { throw new Error( "Subclasses of Association must implement a getter for type" ); } /** Returns the name used for the association's foreign key. ```js let server = createServer({ models: { user: Model, post: Model.extend({ fineAuthor: belongsTo("user"), comments: hasMany() }), comment: Model } }); let associations = server.associationsFor('post') associations.fineAuthor.foreignKey // fineAuthorId associations.comments.foreignKey // commentIds ``` @accessor @type {String} @public */ get foreignKey() { return this.getForeignKey(); } /** @hide */ get identifier() { throw new Error( "Subclasses of Association must implement a getter for identifier" ); } } miragejs-0.1.42/lib/orm/associations/belongs-to.js000066400000000000000000000202361412317504700220570ustar00rootroot00000000000000import Association from "./association"; import { capitalize, camelize } from "../../utils/inflector"; import assert from "../../assert"; const identifierCache = {}; /** * The belongsTo association adds a fk to the owner of the association * * @class BelongsTo * @extends Association * @constructor * @public * @hide */ export default class BelongsTo extends Association { get identifier() { if (typeof identifierCache[this.name] !== "string") { const identifier = `${camelize(this.name)}Id`; identifierCache[this.name] = identifier; } return identifierCache[this.name]; } get type() { return "belongsTo"; } /** * @method getForeignKeyArray * @return {Array} Array of camelized name of the model owning the association * and foreign key for the association * @public */ getForeignKeyArray() { return [camelize(this.ownerModelName), this.getForeignKey()]; } /** * @method getForeignKey * @return {String} Foreign key for the association * @public */ getForeignKey() { // we reuse identifierCache because it's the same logic as get identifier if (typeof identifierCache[this.name] !== "string") { const foreignKey = `${camelize(this.name)}Id`; identifierCache[this.name] = foreignKey; } return identifierCache[this.name]; } /** * Registers belongs-to association defined by given key on given model, * defines getters / setters for associated parent and associated parent's id, * adds methods for creating unsaved parent record and creating a saved one * * @method addMethodsToModelClass * @param {Function} ModelClass * @param {String} key the named key for the association * @public */ addMethodsToModelClass(ModelClass, key) { let modelPrototype = ModelClass.prototype; let association = this; let foreignKey = this.getForeignKey(); let associationHash = { [key]: this }; modelPrototype.belongsToAssociations = Object.assign( modelPrototype.belongsToAssociations, associationHash ); // update belongsToAssociationFks Object.keys(modelPrototype.belongsToAssociations).forEach((key) => { const value = modelPrototype.belongsToAssociations[key]; modelPrototype.belongsToAssociationFks[value.getForeignKey()] = value; }); // Add to target's dependent associations array this.schema.addDependentAssociation(this, this.modelName); // TODO: look how this is used. Are these necessary, seems like they could be gotten from the above? // Or we could use a single data structure to store this information? modelPrototype.associationKeys.add(key); modelPrototype.associationIdKeys.add(foreignKey); Object.defineProperty(modelPrototype, foreignKey, { /* object.parentId - returns the associated parent's id */ get() { this._tempAssociations = this._tempAssociations || {}; let tempParent = this._tempAssociations[key]; let id; if (tempParent === null) { id = null; } else { if (association.isPolymorphic) { if (tempParent) { id = { id: tempParent.id, type: tempParent.modelName }; } else { id = this.attrs[foreignKey]; } } else { if (tempParent) { id = tempParent.id; } else { id = this.attrs[foreignKey]; } } } return id; }, /* object.parentId = (parentId) - sets the associated parent via id */ set(id) { let tempParent; if (id === null) { tempParent = null; } else if (id !== undefined) { if (association.isPolymorphic) { assert( typeof id === "object", `You're setting an ID on the polymorphic association '${association.name}' but you didn't pass in an object. Polymorphic IDs need to be in the form { type, id }.` ); tempParent = association.schema[ association.schema.toCollectionName(id.type) ].find(id.id); } else { tempParent = association.schema[ association.schema.toCollectionName(association.modelName) ].find(id); assert( tempParent, `Couldn't find ${association.modelName} with id = ${id}` ); } } this[key] = tempParent; }, }); Object.defineProperty(modelPrototype, key, { /* object.parent - returns the associated parent */ get() { this._tempAssociations = this._tempAssociations || {}; let tempParent = this._tempAssociations[key]; let foreignKeyId = this[foreignKey]; let model = null; if (tempParent) { model = tempParent; } else if (foreignKeyId !== null) { if (association.isPolymorphic) { model = association.schema[ association.schema.toCollectionName(foreignKeyId.type) ].find(foreignKeyId.id); } else { model = association.schema[ association.schema.toCollectionName(association.modelName) ].find(foreignKeyId); } } return model; }, /* object.parent = (parentModel) - sets the associated parent via model I want to jot some notes about hasInverseFor. There used to be an association.inverse() check, but adding polymorphic associations complicated this. `comment.commentable`, you can't easily check for an inverse since `comments: hasMany()` could be on any model. Instead of making it very complex and looking for an inverse on the association in isoaltion, it was much simpler to ask the model being passed in if it had an inverse for the setting model and with its association. */ set(model) { this._tempAssociations = this._tempAssociations || {}; this._tempAssociations[key] = model; if (model && model.hasInverseFor(association)) { let inverse = model.inverseFor(association); model.associate(this, inverse); } }, }); /* object.newParent - creates a new unsaved associated parent TODO: document polymorphic */ modelPrototype[`new${capitalize(key)}`] = function (...args) { let modelName, attrs; if (association.isPolymorphic) { modelName = args[0]; attrs = args[1]; } else { modelName = association.modelName; attrs = args[0]; } let parent = association.schema[ association.schema.toCollectionName(modelName) ].new(attrs); this[key] = parent; return parent; }; /* object.createParent - creates a new saved associated parent, and immediately persists both models TODO: document polymorphic */ modelPrototype[`create${capitalize(key)}`] = function (...args) { let modelName, attrs; if (association.isPolymorphic) { modelName = args[0]; attrs = args[1]; } else { modelName = association.modelName; attrs = args[0]; } let parent = association.schema[ association.schema.toCollectionName(modelName) ].create(attrs); this[key] = parent; this.save(); return parent.reload(); }; } /** * * * @public */ disassociateAllDependentsFromTarget(model) { let owner = this.ownerModelName; let fk; if (this.isPolymorphic) { fk = { type: model.modelName, id: model.id }; } else { fk = model.id; } let dependents = this.schema[this.schema.toCollectionName(owner)].where( (potentialOwner) => { let id = potentialOwner[this.getForeignKey()]; if (!id) { return false; } if (typeof id === "object") { return id.type === fk.type && id.id === fk.id; } else { return id === fk; } } ); dependents.models.forEach((dependent) => { dependent.disassociate(model, this); dependent.save(); }); } } miragejs-0.1.42/lib/orm/associations/has-many.js000066400000000000000000000230571412317504700215270ustar00rootroot00000000000000import Association from "./association"; import Collection from "../collection"; import PolymorphicCollection from "../polymorphic-collection"; import compact from "lodash.compact"; import { capitalize, camelize } from "../../utils/inflector"; import assert from "@lib/assert"; const identifierCache = {}; /** * @class HasMany * @extends Association * @constructor * @public * @hide */ export default class HasMany extends Association { get identifier() { if (typeof identifierCache[this.name] !== "string") { const identifier = `${camelize( this._container.inflector.singularize(this.name) )}Ids`; identifierCache[this.name] = identifier; } return identifierCache[this.name]; } get type() { return "hasMany"; } /** * @method getForeignKeyArray * @return {Array} Array of camelized model name of associated objects * and foreign key for the object owning the association * @public */ getForeignKeyArray() { return [camelize(this.ownerModelName), this.getForeignKey()]; } /** * @method getForeignKey * @return {String} Foreign key for the object owning the association * @public */ getForeignKey() { // we reuse identifierCache because it's the same logic as get identifier if (typeof identifierCache[this.name] !== "string") { const foreignKey = `${this._container.inflector.singularize( camelize(this.name) )}Ids`; identifierCache[this.name] = foreignKey; } return identifierCache[this.name]; } /** * Registers has-many association defined by given key on given model, * defines getters / setters for associated records and associated records' ids, * adds methods for creating unsaved child records and creating saved ones * * @method addMethodsToModelClass * @param {Function} ModelClass * @param {String} key * @public */ addMethodsToModelClass(ModelClass, key) { let modelPrototype = ModelClass.prototype; let association = this; let foreignKey = this.getForeignKey(); let associationHash = { [key]: this }; modelPrototype.hasManyAssociations = Object.assign( modelPrototype.hasManyAssociations, associationHash ); // update hasManyAssociationFks Object.keys(modelPrototype.hasManyAssociations).forEach((key) => { const value = modelPrototype.hasManyAssociations[key]; modelPrototype.hasManyAssociationFks[value.getForeignKey()] = value; }); // Add to target's dependent associations array this.schema.addDependentAssociation(this, this.modelName); // TODO: look how this is used. Are these necessary, seems like they could be gotten from the above? // Or we could use a single data structure to store this information? modelPrototype.associationKeys.add(key); modelPrototype.associationIdKeys.add(foreignKey); Object.defineProperty(modelPrototype, foreignKey, { /* object.childrenIds - returns an array of the associated children's ids */ get() { this._tempAssociations = this._tempAssociations || {}; let tempChildren = this._tempAssociations[key]; let ids = []; if (tempChildren) { if (association.isPolymorphic) { ids = tempChildren.models.map((model) => ({ type: model.modelName, id: model.id, })); } else { ids = tempChildren.models.map((model) => model.id); } } else { ids = this.attrs[foreignKey] || []; } return ids; }, /* object.childrenIds = ([childrenIds...]) - sets the associated children (via id) */ set(ids) { let tempChildren; if (ids === null) { tempChildren = []; } else if (ids !== undefined) { assert( Array.isArray(ids), `You must pass an array in when setting ${foreignKey} on ${this}` ); if (association.isPolymorphic) { assert( ids.every((el) => { return ( typeof el === "object" && typeof el.type !== undefined && typeof el.id !== undefined ); }), `You must pass in an array of polymorphic identifiers (objects of shape { type, id }) when setting ${foreignKey} on ${this}` ); let models = ids.map(({ type, id }) => { return association.schema[ association.schema.toCollectionName(type) ].find(id); }); tempChildren = new PolymorphicCollection(models); } else { tempChildren = association.schema[ association.schema.toCollectionName(association.modelName) ].find(ids); } } this[key] = tempChildren; }, }); Object.defineProperty(modelPrototype, key, { /* object.children - returns an array of associated children */ get() { this._tempAssociations = this._tempAssociations || {}; let collection = null; if (this._tempAssociations[key]) { collection = this._tempAssociations[key]; } else { if (association.isPolymorphic) { if (this[foreignKey]) { let polymorphicIds = this[foreignKey]; let models = polymorphicIds.map(({ type, id }) => { return association.schema[ association.schema.toCollectionName(type) ].find(id); }); collection = new PolymorphicCollection(models); } else { collection = new PolymorphicCollection(association.modelName); } } else { if (this[foreignKey]) { collection = association.schema[ association.schema.toCollectionName(association.modelName) ].find(this[foreignKey]); } else { collection = new Collection(association.modelName); } } this._tempAssociations[key] = collection; } return collection; }, /* object.children = [model1, model2, ...] - sets the associated children (via array of models or Collection) */ set(models) { if ( models instanceof Collection || models instanceof PolymorphicCollection ) { models = models.models; } models = models ? compact(models) : []; this._tempAssociations = this._tempAssociations || {}; let collection; if (association.isPolymorphic) { collection = new PolymorphicCollection(models); } else { collection = new Collection(association.modelName, models); } this._tempAssociations[key] = collection; models.forEach((model) => { if (model.hasInverseFor(association)) { let inverse = model.inverseFor(association); model.associate(this, inverse); } }); }, }); /* object.newChild - creates a new unsaved associated child */ modelPrototype[ `new${capitalize( camelize(this._container.inflector.singularize(association.name)) )}` ] = function (...args) { let modelName, attrs; if (association.isPolymorphic) { modelName = args[0]; attrs = args[1]; } else { modelName = association.modelName; attrs = args[0]; } let child = association.schema[ association.schema.toCollectionName(modelName) ].new(attrs); let children = this[key].models; children.push(child); this[key] = children; return child; }; /* object.createChild - creates a new saved associated child, and immediately persists both models TODO: forgot why this[key].add(child) doesn't work, most likely because these external APIs trigger saving cascades. Should probably have an internal method like this[key]._add. */ modelPrototype[ `create${capitalize( camelize(this._container.inflector.singularize(association.name)) )}` ] = function (...args) { let modelName, attrs; if (association.isPolymorphic) { modelName = args[0]; attrs = args[1]; } else { modelName = association.modelName; attrs = args[0]; } let child = association.schema[ association.schema.toCollectionName(modelName) ].create(attrs); let children = this[key].models; children.push(child); this[key] = children; this.save(); return child.reload(); }; } /** * * * @public */ disassociateAllDependentsFromTarget(model) { let owner = this.ownerModelName; let fk; if (this.isPolymorphic) { fk = { type: model.modelName, id: model.id }; } else { fk = model.id; } let dependents = this.schema[this.schema.toCollectionName(owner)].where( (potentialOwner) => { let currentIds = potentialOwner[this.getForeignKey()]; // Need this check because currentIds could be null return ( currentIds && currentIds.find((id) => { if (typeof id === "object") { return id.type === fk.type && id.id === fk.id; } else { return id === fk; } }) ); } ); dependents.models.forEach((dependent) => { dependent.disassociate(model, this); dependent.save(); }); } } miragejs-0.1.42/lib/orm/collection.js000066400000000000000000000156741412317504700174540ustar00rootroot00000000000000import assert from "../assert"; import invokeMap from "lodash.invokemap"; /** Collections represent arrays of models. They are returned by a hasMany association, or by one of the ModelClass query methods: ```js let posts = user.blogPosts; let posts = schema.blogPosts.all(); let posts = schema.blogPosts.find([1, 2, 4]); let posts = schema.blogPosts.where({ published: true }); ``` Note that there is also a `PolymorphicCollection` class that is identical to `Collection`, except it can contain a heterogeneous array of models. Thus, it has no `modelName` property. This lets serializers and other parts of the system interact with it differently. @class Collection @constructor @public */ export default class Collection { constructor(modelName, models = []) { assert( modelName && typeof modelName === "string", "You must pass a `modelName` into a Collection" ); /** The dasherized model name this Collection represents. ```js let posts = user.blogPosts; posts.modelName; // "blog-post" ``` The model name is separate from the actual models, since Collections can be empty. @property modelName @type {String} @public */ this.modelName = modelName; /** The underlying plain JavaScript array of Models in this Collection. ```js posts.models // [ post:1, post:2, ... ] ``` While Collections have many array-ish methods like `filter` and `sort`, it can be useful to work with the plain array if you want to work with methods like `map`, or use the `[]` accessor. For example, in testing you might want to assert against a model from the collection: ```js let newPost = user.posts.models[0].title; assert.equal(newPost, "My first post"); ``` @property models @type {Array} @public */ this.models = models; } /** The number of models in the collection. ```js user.posts.length; // 2 ``` @property length @type {Integer} @public */ get length() { return this.models.length; } /** Updates each model in the collection, and immediately persists all changes to the db. ```js let posts = user.blogPosts; posts.update('published', true); // the db was updated for all posts ``` @method update @param key @param val @return this @public */ update(...args) { invokeMap(this.models, "update", ...args); return this; } /** Saves all models in the collection. ```js let posts = user.blogPosts; posts.models[0].published = true; posts.save(); // all posts saved to db ``` @method save @return this @public */ save() { invokeMap(this.models, "save"); return this; } /** Reloads each model in the collection. ```js let posts = author.blogPosts; // ... posts.reload(); // reloads data for each post from the db ``` @method reload @return this @public */ reload() { invokeMap(this.models, "reload"); return this; } /** Destroys the db record for all models in the collection. ```js let posts = user.blogPosts; posts.destroy(); // all posts removed from db ``` @method destroy @return this @public */ destroy() { invokeMap(this.models, "destroy"); return this; } /** Adds a model to this collection. ```js posts.length; // 1 posts.add(newPost); posts.length; // 2 ``` @method add @param {Model} model @return this @public */ add(model) { this.models.push(model); return this; } /** Removes a model from this collection. ```js posts.length; // 5 let firstPost = posts.models[0]; posts.remove(firstPost); posts.save(); posts.length; // 4 ``` @method remove @param {Model} model @return this @public */ remove(model) { let match = this.models.find((m) => m.toString() === model.toString()); if (match) { let i = this.models.indexOf(match); this.models.splice(i, 1); } return this; } /** Checks if the Collection includes the given model. ```js posts.includes(newPost); ``` Works by checking if the given model name and id exists in the Collection, making it a bit more flexible than strict object equality. ```js let post = server.create('post'); let programming = server.create('tag', { text: 'Programming' }); visit(`/posts/${post.id}`); click('.tag-selector'); click('.tag:contains(Programming)'); post.reload(); assert.ok(post.tags.includes(programming)); ``` @method includes @return {Boolean} @public */ includes(model) { return this.models.some((m) => m.toString() === model.toString()); } /** Returns a new Collection with its models filtered according to the provided [callback function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). ```js let publishedPosts = user.posts.filter(post => post.isPublished); ``` @method filter @param {Function} f @return {Collection} @public */ filter(f) { let filteredModels = this.models.filter(f); return new Collection(this.modelName, filteredModels); } /** Returns a new Collection with its models sorted according to the provided [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters). ```js let postsByTitleAsc = user.posts.sort((a, b) => a.title > b.title ? 1 : -1 ); ``` @method sort @param {Function} f @return {Collection} @public */ sort(f) { let sortedModels = this.models.concat().sort(f); return new Collection(this.modelName, sortedModels); } /** Returns a new Collection with a subset of its models selected from `begin` to `end`. ```js let firstThreePosts = user.posts.slice(0, 3); ``` @method slice @param {Integer} begin @param {Integer} end @return {Collection} @public */ slice(...args) { let slicedModels = this.models.slice(...args); return new Collection(this.modelName, slicedModels); } /** Modifies the Collection by merging the models from another collection. ```js user.posts.mergeCollection(newPosts); user.posts.save(); ``` @method mergeCollection @param {Collection} collection @return this @public */ mergeCollection(collection) { this.models = this.models.concat(collection.models); return this; } /** Simple string representation of the collection and id. ```js user.posts.toString(); // collection:post(post:1,post:4) ``` @method toString @return {String} @public */ toString() { return `collection:${this.modelName}(${this.models .map((m) => m.id) .join(",")})`; } } miragejs-0.1.42/lib/orm/model.js000066400000000000000000000732411412317504700164130ustar00rootroot00000000000000import BelongsTo from "./associations/belongs-to"; import HasMany from "./associations/has-many"; import extend from "../utils/extend"; import assert from "../assert"; import Collection from "./collection"; import PolymorphicCollection from "./polymorphic-collection"; import values from "lodash.values"; import compact from "lodash.compact"; /** Models wrap your database, and allow you to define relationships. **Class vs. instance methods** The methods documented below apply to _instances_ of models, but you'll typically use the `Schema` to access the model _class_, which can be used to find or create instances. You can find the Class methods documented under the `Schema` API docs. **Accessing properties and relationships** You can access properites (fields) and relationships directly off of models. ```js user.name; // 'Sam' user.team; // Team model user.teamId; // Team id (foreign key) ``` Mirage Models are schemaless in their attributes, but their relationship schema is known. For example, ```js let user = schema.users.create(); user.attrs // { } user.name // undefined let user = schema.users.create({ name: 'Sam' }); user.attrs // { name: 'Sam' } user.name // 'Sam' ``` However, if a `user` has a `posts` relationships defined, ```js let user = schema.users.create(); user.posts // returns an empty Posts Collection ``` @class Model @constructor @public */ class Model { // TODO: schema and modelName now set statically at registration, need to remove /* Notes: - We need to pass in modelName, because models are created with .extend and anonymous functions, so you cannot use reflection to find the name of the constructor. */ constructor(schema, modelName, attrs, fks) { assert(schema, "A model requires a schema"); assert(modelName, "A model requires a modelName"); this._schema = schema; this.modelName = modelName; this.fks = fks || []; /** Returns the attributes of your model. ```js let post = schema.blogPosts.find(1); post.attrs; // {id: 1, title: 'Lorem Ipsum', publishedAt: '2012-01-01 10:00:00'} ``` Note that you can also access individual attributes directly off a model, e.g. `post.title`. @property attrs @public */ this.attrs = {}; attrs = attrs || {}; // Ensure fks are there this.fks.forEach((fk) => { this.attrs[fk] = attrs[fk] !== undefined ? attrs[fk] : null; }); Object.keys(attrs).forEach((name) => { const value = attrs[name]; this._validateAttr(name, value); this._setupAttr(name, value); this._setupRelationship(name, value); }); return this; } /** Create or saves the model. ```js let post = blogPosts.new({ title: 'Lorem ipsum' }); post.id; // null post.save(); post.id; // 1 post.title = 'Hipster ipsum'; // db has not been updated post.save(); // ...now the db is updated ``` @method save @return this @public */ save() { let collection = this._schema.toInternalCollectionName(this.modelName); if (this.isNew()) { // Update the attrs with the db response this.attrs = this._schema.db[collection].insert(this.attrs); // Ensure the id getter/setter is set this._definePlainAttribute("id"); } else { this._schema.isSaving[this.toString()] = true; this._schema.db[collection].update(this.attrs.id, this.attrs); } this._saveAssociations(); this._schema.isSaving[this.toString()] = false; return this; } /** Updates the record in the db. ```js let post = blogPosts.find(1); post.update('title', 'Hipster ipsum'); // the db was updated post.update({ title: 'Lorem ipsum', created_at: 'before it was cool' }); ``` @method update @param {String} key @param {String} val @return this @public */ update(key, val) { let attrs; if (key == null) { return this; } if (typeof key === "object") { attrs = key; } else { (attrs = {})[key] = val; } Object.keys(attrs).forEach(function (attr) { if ( !this.associationKeys.has(attr) && !this.associationIdKeys.has(attr) ) { this._definePlainAttribute(attr); } this[attr] = attrs[attr]; }, this); this.save(); return this; } /** Destroys the db record. ```js let post = blogPosts.find(1); post.destroy(); // removed from the db ``` @method destroy @public */ destroy() { if (this.isSaved()) { this._disassociateFromDependents(); let collection = this._schema.toInternalCollectionName(this.modelName); this._schema.db[collection].remove(this.attrs.id); } } /** Boolean, true if the model has not been persisted yet to the db. ```js let post = blogPosts.new({title: 'Lorem ipsum'}); post.isNew(); // true post.id; // null post.save(); // true post.isNew(); // false post.id; // 1 ``` @method isNew @return {Boolean} @public */ isNew() { let hasDbRecord = false; let hasId = this.attrs.id !== undefined && this.attrs.id !== null; if (hasId) { let collectionName = this._schema.toInternalCollectionName( this.modelName ); let record = this._schema.db[collectionName].find(this.attrs.id); if (record) { hasDbRecord = true; } } return !hasDbRecord; } /** Boolean, opposite of `isNew` @method isSaved @return {Boolean} @public */ isSaved() { return !this.isNew(); } /** Reload a model's data from the database. ```js let post = blogPosts.find(1); post.attrs; // {id: 1, title: 'Lorem ipsum'} post.title = 'Hipster ipsum'; post.title; // 'Hipster ipsum'; post.reload(); // true post.title; // 'Lorem ipsum' ``` @method reload @return this @public */ reload() { if (this.id) { let collection = this._schema.toInternalCollectionName(this.modelName); let attrs = this._schema.db[collection].find(this.id); Object.keys(attrs) .filter(function (attr) { return attr !== "id"; }) .forEach(function (attr) { this.attrs[attr] = attrs[attr]; }, this); } // Clear temp associations this._tempAssociations = {}; return this; } toJSON() { return { ...this.attrs }; } /** Returns a hash of this model's associations. ```js let server = createServer({ models: { user: Model, post: Model.extend({ user: belongsTo(), comments: hasMany() }), comment: Model }, seeds(server) { let peter = server.create("user", { name: "Peter" }); server.create("post", { user: peter }); } }); let post = server.schema.posts.find(1) post.associations // { // user: BelongsToAssociation, // comments: HasManyAssociation // } ``` Check out the docs on the Association class to see what fields are available for each association. @method associations @type {Object} @public */ get associations() { return this._schema.associationsFor(this.modelName); } /** Returns the association for the given key @method associationFor @param key @public @hide */ associationFor(key) { return this.associations[key]; } /** Returns this model's inverse association for the given model-type-association pair, if it exists. Example: post: Model.extend({ comments: hasMany() }), comments: Model.extend({ post: belongsTo() }) post.inversefor(commentsPostAssociation) would return the `post.comments` association object. Originally we had association.inverse() but that became impossible with the addition of polymorphic models. Consider the following: post: Model.extend({ comments: hasMany() }), picture: Model.extend({ comments: hasMany() }), comments: Model.extend({ commentable: belongsTo({ polymorphic: true }) }) `commentable.inverse()` is ambiguous - does it return `post.comments` or `picture.comments`? Instead we need to ask each model if it has an inverse for a given association. post.inverseFor(commentable) is no longer ambiguous. @method hasInverseFor @param {String} modelName The model name of the class we're scanning @param {ORM/Association} association @return {ORM/Association} @public @hide */ inverseFor(association) { return ( this._explicitInverseFor(association) || this._implicitInverseFor(association) ); } /** Finds the inverse for an association that explicity defines it's inverse @private @hide */ _explicitInverseFor(association) { this._checkForMultipleExplicitInverses(association); let associations = this._schema.associationsFor(this.modelName); let inverse = association.opts.inverse; let candidate = inverse ? associations[inverse] : null; let matchingPolymorphic = candidate && candidate.isPolymorphic; let matchingInverse = candidate && candidate.modelName === association.ownerModelName; let candidateInverse = candidate && candidate.opts.inverse; if (candidateInverse && candidate.opts.inverse !== association.name) { assert( false, `You specified an inverse of ${inverse} for ${association.name}, but it does not match ${candidate.modelName} ${candidate.name}'s inverse` ); } return matchingPolymorphic || matchingInverse ? candidate : null; } /** Ensures multiple explicit inverses don't exist on the current model for the given association. TODO: move this to compile-time check @private @hide */ _checkForMultipleExplicitInverses(association) { let associations = this._schema.associationsFor(this.modelName); let matchingExplicitInverses = Object.keys(associations).filter((key) => { let candidate = associations[key]; let modelMatches = association.ownerModelName === candidate.modelName; let inverseKeyMatches = association.name === candidate.opts.inverse; return modelMatches && inverseKeyMatches; }); assert( matchingExplicitInverses.length <= 1, `The ${this.modelName} model has defined multiple explicit inverse associations for the ${association.ownerModelName}.${association.name} association.` ); } /** Finds if there is an inverse for an association that does not explicitly define one. @private @hide */ _implicitInverseFor(association) { let associations = this._schema.associationsFor(this.modelName); let modelName = association.ownerModelName; return values(associations) .filter((candidate) => candidate.modelName === modelName) .reduce((inverse, candidate) => { let candidateInverse = candidate.opts.inverse; let candidateIsImplicitInverse = candidateInverse === undefined; let candidateIsExplicitInverse = candidateInverse === association.name; let candidateMatches = candidateIsImplicitInverse || candidateIsExplicitInverse; if (candidateMatches) { // Need to move this check to compile-time init assert( !inverse, `The ${this.modelName} model has multiple possible inverse associations for the ${association.ownerModelName}.${association.name} association.` ); inverse = candidate; } return inverse; }, null); } /** Returns whether this model has an inverse association for the given model-type-association pair. @method hasInverseFor @param {String} modelName @param {ORM/Association} association @return {Boolean} @public @hide */ hasInverseFor(association) { return !!this.inverseFor(association); } /** Used to check if models match each other. If models are saved, we check model type and id, since they could have other non-persisted properties that are different. @public @hide */ alreadyAssociatedWith(model, association) { let associatedModelOrCollection = this[association.name]; if (associatedModelOrCollection && model) { if (associatedModelOrCollection instanceof Model) { if (associatedModelOrCollection.isSaved() && model.isSaved()) { return associatedModelOrCollection.toString() === model.toString(); } else { return associatedModelOrCollection === model; } } else { return associatedModelOrCollection.includes(model); } } } associate(model, association) { if (this.alreadyAssociatedWith(model, association)) { return; } let { name } = association; if (association instanceof HasMany) { if (!this[name].includes(model)) { this[name].add(model); } } else { this[name] = model; } } disassociate(model, association) { let fk = association.getForeignKey(); if (association instanceof HasMany) { let i; if (association.isPolymorphic) { let found = this[fk].find( ({ type, id }) => type === model.modelName && id === model.id ); i = found && this[fk].indexOf(found); } else { i = this[fk].map((key) => key.toString()).indexOf(model.id.toString()); } if (i > -1) { this.attrs[fk].splice(i, 1); } } else { this.attrs[fk] = null; } } /** @hide */ get isSaving() { return this._schema.isSaving[this.toString()]; } // Private /** model.attrs represents the persistable attributes, i.e. your db table fields. @method _setupAttr @param attr @param value @private @hide */ _setupAttr(attr, value) { const isAssociation = this.associationKeys.has(attr) || this.associationIdKeys.has(attr); if (!isAssociation) { this.attrs[attr] = value; // define plain getter/setters for non-association keys this._definePlainAttribute(attr); } } /** Define getter/setter for a plain attribute @method _definePlainAttribute @param attr @private @hide */ _definePlainAttribute(attr) { // Ensure the property hasn't already been defined let existingProperty = Object.getOwnPropertyDescriptor(this, attr); if (existingProperty && existingProperty.get) { return; } // Ensure the attribute is on the attrs hash if (!Object.prototype.hasOwnProperty.call(this.attrs, attr)) { this.attrs[attr] = null; } // Define the getter/setter Object.defineProperty(this, attr, { get() { return this.attrs[attr]; }, set(val) { this.attrs[attr] = val; }, }); } /** Foreign keys get set on attrs directly (to avoid potential recursion), but model references use the setter. * We validate foreign keys during instantiation. * @method _setupRelationship @param attr @param value @private @hide */ _setupRelationship(attr, value) { const isFk = this.associationIdKeys.has(attr) || this.fks.includes(attr); const isAssociation = this.associationKeys.has(attr); if (isFk) { if (value !== undefined && value !== null) { this._validateForeignKeyExistsInDatabase(attr, value); } this.attrs[attr] = value; } if (isAssociation) { this[attr] = value; } } /** @method _validateAttr @private @hide */ _validateAttr(key, value) { // Verify attr passed in for associations is actually an association { if (this.associationKeys.has(key)) { let association = this.associationFor(key); let isNull = value === null; if (association instanceof HasMany) { let isCollection = value instanceof Collection || value instanceof PolymorphicCollection; let isArrayOfModels = Array.isArray(value) && value.every((item) => item instanceof Model); assert( isCollection || isArrayOfModels || isNull, `You're trying to create a ${this.modelName} model and you passed in "${value}" under the ${key} key, but that key is a HasMany relationship. You must pass in a Collection, PolymorphicCollection, array of Models, or null.` ); } else if (association instanceof BelongsTo) { assert( value instanceof Model || isNull, `You're trying to create a ${this.modelName} model and you passed in "${value}" under the ${key} key, but that key is a BelongsTo relationship. You must pass in a Model or null.` ); } } } // Verify attrs passed in for association foreign keys are actually fks { if (this.associationIdKeys.has(key)) { if (key.endsWith("Ids")) { let isArray = Array.isArray(value); let isNull = value === null; assert( isArray || isNull, `You're trying to create a ${this.modelName} model and you passed in "${value}" under the ${key} key, but that key is a foreign key for a HasMany relationship. You must pass in an array of ids or null.` ); } } } // Verify no undefined associations are passed in { let isModelOrCollection = value instanceof Model || value instanceof Collection || value instanceof PolymorphicCollection; let isArrayOfModels = Array.isArray(value) && value.length && value.every((item) => item instanceof Model); if (isModelOrCollection || isArrayOfModels) { let modelOrCollection = value; assert( this.associationKeys.has(key), `You're trying to create a ${ this.modelName } model and you passed in a ${modelOrCollection.toString()} under the ${key} key, but you haven't defined that key as an association on your model.` ); } } } /** Originally we validated this via association.setId method, but it triggered recursion. That method is designed for updating an existing model's ID so this method is needed during instantiation. * @method _validateForeignKeyExistsInDatabase @private @hide */ _validateForeignKeyExistsInDatabase(foreignKeyName, foreignKeys) { if (Array.isArray(foreignKeys)) { let association = this.hasManyAssociationFks[foreignKeyName]; let found; if (association.isPolymorphic) { found = foreignKeys.map(({ type, id }) => { return this._schema.db[ this._schema.toInternalCollectionName(type) ].find(id); }); found = compact(found); } else { found = this._schema.db[ this._schema.toInternalCollectionName(association.modelName) ].find(foreignKeys); } let foreignKeyLabel = association.isPolymorphic ? foreignKeys.map((fk) => `${fk.type}:${fk.id}`).join(",") : foreignKeys; assert( found.length === foreignKeys.length, `You're instantiating a ${this.modelName} that has a ${foreignKeyName} of ${foreignKeyLabel}, but some of those records don't exist in the database.` ); } else { let association = this.belongsToAssociationFks[foreignKeyName]; let found; if (association.isPolymorphic) { found = this._schema.db[ this._schema.toInternalCollectionName(foreignKeys.type) ].find(foreignKeys.id); } else { found = this._schema.db[ this._schema.toInternalCollectionName(association.modelName) ].find(foreignKeys); } let foreignKeyLabel = association.isPolymorphic ? `${foreignKeys.type}:${foreignKeys.id}` : foreignKeys; assert( found, `You're instantiating a ${this.modelName} that has a ${foreignKeyName} of ${foreignKeyLabel}, but that record doesn't exist in the database.` ); } } /** Update associated children when saving a collection * @method _saveAssociations @private @hide */ _saveAssociations() { this._saveBelongsToAssociations(); this._saveHasManyAssociations(); } _saveBelongsToAssociations() { values(this.belongsToAssociations).forEach((association) => { this._disassociateFromOldInverses(association); this._saveNewAssociates(association); this._associateWithNewInverses(association); }); } _saveHasManyAssociations() { values(this.hasManyAssociations).forEach((association) => { this._disassociateFromOldInverses(association); this._saveNewAssociates(association); this._associateWithNewInverses(association); }); } _disassociateFromOldInverses(association) { if (association instanceof HasMany) { this._disassociateFromHasManyInverses(association); } else if (association instanceof BelongsTo) { this._disassociateFromBelongsToInverse(association); } } // Disassociate currently persisted models that are no longer associated _disassociateFromHasManyInverses(association) { let fk = association.getForeignKey(); let tempAssociation = this._tempAssociations && this._tempAssociations[association.name]; let associateIds = this.attrs[fk]; if (tempAssociation && associateIds) { let models; if (association.isPolymorphic) { models = associateIds.map(({ type, id }) => { return this._schema[this._schema.toCollectionName(type)].find(id); }); } else { // TODO: prob should initialize hasMany fks with [] models = this._schema[ this._schema.toCollectionName(association.modelName) ].find(associateIds || []).models; } models .filter( (associate) => // filter out models that are already being saved !associate.isSaving && // filter out models that will still be associated !tempAssociation.includes(associate) && associate.hasInverseFor(association) ) .forEach((associate) => { let inverse = associate.inverseFor(association); associate.disassociate(this, inverse); associate.save(); }); } } /* Disassociate currently persisted models that are no longer associated. Example: post: Model.extend({ comments: hasMany() }), comment: Model.extend({ post: belongsTo() }) Assume `this` is comment:1. When saving, if comment:1 is no longer associated with post:1, we need to remove comment:1 from post:1.comments. In this example `association` would be `comment.post`. */ _disassociateFromBelongsToInverse(association) { let fk = association.getForeignKey(); let tempAssociation = this._tempAssociations && this._tempAssociations[association.name]; let associateId = this.attrs[fk]; if (tempAssociation !== undefined && associateId) { let associate; if (association.isPolymorphic) { associate = this._schema[ this._schema.toCollectionName(associateId.type) ].find(associateId.id); } else { associate = this._schema[ this._schema.toCollectionName(association.modelName) ].find(associateId); } if (associate.hasInverseFor(association)) { let inverse = associate.inverseFor(association); associate.disassociate(this, inverse); associate._updateInDb(associate.attrs); } } } // Find all other models that depend on me and update their foreign keys _disassociateFromDependents() { this._schema .dependentAssociationsFor(this.modelName) .forEach((association) => { association.disassociateAllDependentsFromTarget(this); }); } _saveNewAssociates(association) { let fk = association.getForeignKey(); let tempAssociate = this._tempAssociations && this._tempAssociations[association.name]; if (tempAssociate !== undefined) { this.__isSavingNewChildren = true; delete this._tempAssociations[association.name]; if (tempAssociate instanceof Collection) { tempAssociate.models .filter((model) => !model.isSaving) .forEach((child) => { child.save(); }); this._updateInDb({ [fk]: tempAssociate.models.map((child) => child.id), }); } else if (tempAssociate instanceof PolymorphicCollection) { tempAssociate.models .filter((model) => !model.isSaving) .forEach((child) => { child.save(); }); this._updateInDb({ [fk]: tempAssociate.models.map((child) => { return { type: child.modelName, id: child.id }; }), }); } else { // Clearing the association if (tempAssociate === null) { this._updateInDb({ [fk]: null }); // Self-referential } else if (this.equals(tempAssociate)) { this._updateInDb({ [fk]: this.id }); // Non-self-referential } else if (!tempAssociate.isSaving) { // Save the tempAssociate and update the local reference tempAssociate.save(); this._syncTempAssociations(tempAssociate); let fkValue; if (association.isPolymorphic) { fkValue = { id: tempAssociate.id, type: tempAssociate.modelName }; } else { fkValue = tempAssociate.id; } this._updateInDb({ [fk]: fkValue }); } } this.__isSavingNewChildren = false; } } /* Step 3 in saving associations. Example: // initial state post.author = steinbeck; // new state post.author = twain; 1. Disassociate from old inverse (remove post from steinbeck.posts) 2. Save new associates (if twain.isNew, save twain) -> 3. Associate with new inverse (add post to twain.posts) */ _associateWithNewInverses(association) { if (!this.__isSavingNewChildren) { let modelOrCollection = this[association.name]; if (modelOrCollection instanceof Model) { this._associateModelWithInverse(modelOrCollection, association); } else if ( modelOrCollection instanceof Collection || modelOrCollection instanceof PolymorphicCollection ) { modelOrCollection.models.forEach((model) => { this._associateModelWithInverse(model, association); }); } delete this._tempAssociations[association.name]; } } _associateModelWithInverse(model, association) { if (model.hasInverseFor(association)) { let inverse = model.inverseFor(association); let inverseFk = inverse.getForeignKey(); let ownerId = this.id; if (inverse instanceof BelongsTo) { let newId; if (inverse.isPolymorphic) { newId = { type: this.modelName, id: ownerId }; } else { newId = ownerId; } this._schema.db[ this._schema.toInternalCollectionName(model.modelName) ].update(model.id, { [inverseFk]: newId }); } else { let inverseCollection = this._schema.db[ this._schema.toInternalCollectionName(model.modelName) ]; let currentIdsForInverse = inverseCollection.find(model.id)[inverse.getForeignKey()] || []; let newIdsForInverse = Object.assign([], currentIdsForInverse); let newId, alreadyAssociatedWith; if (inverse.isPolymorphic) { newId = { type: this.modelName, id: ownerId }; alreadyAssociatedWith = newIdsForInverse.some( (key) => key.type == this.modelName && key.id == ownerId ); } else { newId = ownerId; alreadyAssociatedWith = newIdsForInverse.includes(ownerId); } if (!alreadyAssociatedWith) { newIdsForInverse.push(newId); } inverseCollection.update(model.id, { [inverseFk]: newIdsForInverse }); } } } // Used to update data directly, since #save and #update can retrigger saves, // which can cause cycles with associations. _updateInDb(attrs) { this.attrs = this._schema.db[ this._schema.toInternalCollectionName(this.modelName) ].update(this.attrs.id, attrs); } /* Super gnarly: after we save this tempAssociate, we we need to through all other tempAssociates for a reference to this same model, and update it. Otherwise those other references are stale, which could cause a bug when they are subsequently saved. This only works for belongsTo right now, should add hasMany logic to it. See issue #1613: https://github.com/samselikoff/ember-cli-mirage/pull/1613 */ _syncTempAssociations(tempAssociate) { Object.keys(this._tempAssociations).forEach((key) => { if ( this._tempAssociations[key] && this._tempAssociations[key].toString() === tempAssociate.toString() ) { this._tempAssociations[key] = tempAssociate; } }); } /** Simple string representation of the model and id. ```js let post = blogPosts.find(1); post.toString(); // "model:blogPost:1" ``` @method toString @return {String} @public */ toString() { let idLabel = this.id ? `(${this.id})` : ""; return `model:${this.modelName}${idLabel}`; } /** Checks the equality of this model and the passed-in model * @method equals @return boolean @public @hide */ equals(model) { return this.toString() === model.toString(); } } Model.extend = extend; Model.findBelongsToAssociation = function (associationType) { return this.prototype.belongsToAssociations[associationType]; }; export default Model; miragejs-0.1.42/lib/orm/polymorphic-collection.js000066400000000000000000000065301412317504700220060ustar00rootroot00000000000000import invokeMap from "lodash.invokemap"; import isEqual from "lodash.isequal"; /** * An array of models, returned from one of the schema query * methods (all, find, where). Knows how to update and destroy its models. * * Identical to Collection except it can contain a heterogeneous array of * models. Thus, it has no `modelName` property. This lets serializers and * other parts of the system interact with it differently. * * @class PolymorphicCollection * @constructor * @public * @hide */ export default class PolymorphicCollection { constructor(models = []) { this.models = models; } /** * Number of models in the collection. * * @property length * @type Number * @public */ get length() { return this.models.length; } /** * Updates each model in the collection (persisting immediately to the db). * @method update * @param key * @param val * @return this * @public */ update(...args) { invokeMap(this.models, "update", ...args); return this; } /** * Destroys the db record for all models in the collection. * @method destroy * @return this * @public */ destroy() { invokeMap(this.models, "destroy"); return this; } /** * Saves all models in the collection. * @method save * @return this * @public */ save() { invokeMap(this.models, "save"); return this; } /** * Reloads each model in the collection. * @method reload * @return this * @public */ reload() { invokeMap(this.models, "reload"); return this; } /** * Adds a model to this collection * * @method add * @return this * @public */ add(model) { this.models.push(model); return this; } /** * Removes a model to this collection * * @method remove * @return this * @public */ remove(model) { let match = this.models.find((m) => isEqual(m.attrs, model.attrs)); if (match) { let i = this.models.indexOf(match); this.models.splice(i, 1); } return this; } /** * Checks if the collection includes the model * * @method includes * @return boolean * @public */ includes(model) { return this.models.some((m) => isEqual(m.attrs, model.attrs)); } /** * @method filter * @param f * @return {Collection} * @public */ filter(f) { let filteredModels = this.models.filter(f); return new PolymorphicCollection(filteredModels); } /** * @method sort * @param f * @return {Collection} * @public */ sort(f) { let sortedModels = this.models.concat().sort(f); return new PolymorphicCollection(sortedModels); } /** * @method slice * @param {Integer} begin * @param {Integer} end * @return {Collection} * @public */ slice(...args) { let slicedModels = this.models.slice(...args); return new PolymorphicCollection(slicedModels); } /** * @method mergeCollection * @param collection * @return this * @public */ mergeCollection(collection) { this.models = this.models.concat(collection.models); return this; } /** * Simple string representation of the collection and id. * @method toString * @return {String} * @public */ toString() { return `collection:${this.modelName}(${this.models .map((m) => m.id) .join(",")})`; } } miragejs-0.1.42/lib/orm/schema.js000066400000000000000000000370731412317504700165560ustar00rootroot00000000000000import { camelize, dasherize } from "../utils/inflector"; import Association from "./associations/association"; import Collection from "./collection"; import assert from "../assert"; import forIn from "lodash.forin"; const collectionNameCache = {}; const internalCollectionNameCache = {}; const modelNameCache = {}; /** The primary use of the `Schema` class is to use it to find Models and Collections via the `Model` class methods. The `Schema` is most often accessed via the first parameter to a route handler: ```js this.get('posts', schema => { return schema.posts.where({ isAdmin: false }); }); ``` It is also available from the `.schema` property of a `server` instance: ```js server.schema.users.create({ name: 'Yehuda' }); ``` To work with the Model or Collection returned from one of the methods below, refer to the instance methods in the API docs for the `Model` and `Collection` classes. @class Schema @constructor @public */ export default class Schema { constructor(db, modelsMap = {}) { assert(db, "A schema requires a db"); /** Returns Mirage's database. See the `Db` docs for the db's API. @property db @type {Object} @public */ this.db = db; this._registry = {}; this._dependentAssociations = { polymorphic: [] }; this.registerModels(modelsMap); this.isSaving = {}; // a hash of models that are being saved, used to avoid cycles } /** @method registerModels @param hash @public @hide */ registerModels(hash = {}) { forIn(hash, (model, key) => { this.registerModel(key, hash[key]); }); } /** @method registerModel @param type @param ModelClass @public @hide */ registerModel(type, ModelClass) { let camelizedModelName = camelize(type); let modelName = dasherize(camelizedModelName); // Avoid mutating original class, because we may want to reuse it across many tests ModelClass = ModelClass.extend(); // Store model & fks in registry // TODO: don't think this is needed anymore this._registry[camelizedModelName] = this._registry[camelizedModelName] || { class: null, foreignKeys: [], }; // we may have created this key before, if another model added fks to it this._registry[camelizedModelName].class = ModelClass; // TODO: set here, remove from model#constructor ModelClass.prototype._schema = this; ModelClass.prototype.modelName = modelName; // Set up associations ModelClass.prototype.hasManyAssociations = {}; // a registry of the model's hasMany associations. Key is key from model definition, value is association instance itself ModelClass.prototype.hasManyAssociationFks = {}; // a lookup table to get the hasMany association by foreignKey ModelClass.prototype.belongsToAssociations = {}; // a registry of the model's belongsTo associations. Key is key from model definition, value is association instance itself ModelClass.prototype.belongsToAssociationFks = {}; // a lookup table to get the belongsTo association by foreignKey ModelClass.prototype.associationKeys = new Set(); // ex: address.user, user.addresses ModelClass.prototype.associationIdKeys = new Set(); // ex: address.user_id, user.address_ids ModelClass.prototype.dependentAssociations = []; // a registry of associations that depend on this model, needed for deletion cleanup. let fksAddedFromThisModel = {}; for (let associationProperty in ModelClass.prototype) { if (ModelClass.prototype[associationProperty] instanceof Association) { let association = ModelClass.prototype[associationProperty]; association.name = associationProperty; association.modelName = association.modelName || this.toModelName(associationProperty); association.ownerModelName = modelName; association.setSchema(this); // Update the registry with this association's foreign keys. This is // essentially our "db migration", since we must know about the fks. let [fkHolder, fk] = association.getForeignKeyArray(); fksAddedFromThisModel[fkHolder] = fksAddedFromThisModel[fkHolder] || []; assert( !fksAddedFromThisModel[fkHolder].includes(fk), `Your '${type}' model definition has multiple possible inverse relationships of type '${fkHolder}'. Please use explicit inverses.` ); fksAddedFromThisModel[fkHolder].push(fk); this._addForeignKeyToRegistry(fkHolder, fk); // Augment the Model's class with any methods added by this association association.addMethodsToModelClass(ModelClass, associationProperty); } } // Create a db collection for this model, if doesn't exist let collection = this.toCollectionName(modelName); if (!this.db[collection]) { this.db.createCollection(collection); } // Create the entity methods this[collection] = { camelizedModelName, new: (attrs) => this.new(camelizedModelName, attrs), create: (attrs) => this.create(camelizedModelName, attrs), all: (attrs) => this.all(camelizedModelName, attrs), find: (attrs) => this.find(camelizedModelName, attrs), findBy: (attrs) => this.findBy(camelizedModelName, attrs), findOrCreateBy: (attrs) => this.findOrCreateBy(camelizedModelName, attrs), where: (attrs) => this.where(camelizedModelName, attrs), none: (attrs) => this.none(camelizedModelName, attrs), first: (attrs) => this.first(camelizedModelName, attrs), }; return this; } /** @method modelFor @param type @public @hide */ modelFor(type) { return this._registry[type]; } /** Create a new unsaved model instance with attributes *attrs*. ```js let post = blogPosts.new({ title: 'Lorem ipsum' }); post.title; // Lorem ipsum post.id; // null post.isNew(); // true ``` @method new @param type @param attrs @public */ new(type, attrs) { return this._instantiateModel(dasherize(type), attrs); } /** Create a new model instance with attributes *attrs*, and insert it into the database. ```js let post = blogPosts.create({title: 'Lorem ipsum'}); post.title; // Lorem ipsum post.id; // 1 post.isNew(); // false ``` @method create @param type @param attrs @public */ create(type, attrs) { return this.new(type, attrs).save(); } /** Return all models in the database. ```js let posts = blogPosts.all(); // [post:1, post:2, ...] ``` @method all @param type @public */ all(type) { let collection = this.collectionForType(type); return this._hydrate(collection, dasherize(type)); } /** Return an empty collection of type `type`. @method none @param type @public */ none(type) { return this._hydrate([], dasherize(type)); } /** Return one or many models in the database by id. ```js let post = blogPosts.find(1); let posts = blogPosts.find([1, 3, 4]); ``` @method find @param type @param ids @public */ find(type, ids) { let collection = this.collectionForType(type); let records = collection.find(ids); if (Array.isArray(ids)) { assert( records.length === ids.length, `Couldn't find all ${this._container.inflector.pluralize( type )} with ids: (${ids.join(",")}) (found ${ records.length } results, but was looking for ${ids.length})` ); } return this._hydrate(records, dasherize(type)); } /** Returns the first model in the database that matches the key-value pairs in `attrs`. Note that a string comparison is used. ```js let post = blogPosts.findBy({ published: true }); let post = blogPosts.findBy({ authorId: 1, published: false }); let post = blogPosts.findBy({ author: janeSmith, featured: true }); ``` This will return `null` if the schema doesn't have any matching record. @method findBy @param type @param attributeName @public */ findBy(type, query) { let collection = this.collectionForType(type); let record = collection.findBy(query); return this._hydrate(record, dasherize(type)); } /** Returns the first model in the database that matches the key-value pairs in `attrs`, or creates a record with the attributes if one is not found. ```js // Find the first published blog post, or create a new one. let post = blogPosts.findOrCreateBy({ published: true }); ``` @method findOrCreateBy @param type @param attributeName @public */ findOrCreateBy(type, attrs) { let collection = this.collectionForType(type); let record = collection.findBy(attrs); let model; if (!record) { model = this.create(type, attrs); } else { model = this._hydrate(record, dasherize(type)); } return model; } /** Return an ORM/Collection, which represents an array of models from the database matching `query`. If `query` is an object, its key-value pairs will be compared against records using string comparison. `query` can also be a compare function. ```js let posts = blogPosts.where({ published: true }); let posts = blogPosts.where(post => post.published === true); ``` @method where @param type @param query @public */ where(type, query) { let collection = this.collectionForType(type); let records = collection.where(query); return this._hydrate(records, dasherize(type)); } /** Returns the first model in the database. ```js let post = blogPosts.first(); ``` N.B. This will return `null` if the schema doesn't contain any records. @method first @param type @public */ first(type) { let collection = this.collectionForType(type); let record = collection[0]; return this._hydrate(record, dasherize(type)); } /** @method modelClassFor @param modelName @public @hide */ modelClassFor(modelName) { let model = this._registry[camelize(modelName)]; assert(model, `Model not registered: ${modelName}`); return model.class.prototype; } /* This method updates the dependentAssociations registry, which is used to keep track of which models depend on a given association. It's used when deleting models - their dependents need to be looked up and foreign keys updated. For example, schema = { post: Model.extend(), comment: Model.extend({ post: belongsTo() }) }; comment1.post = post1; ... post1.destroy() Deleting this post should clear out comment1's foreign key. Polymorphic associations can have _any_ other model as a dependent, so we handle them separately. */ addDependentAssociation(association, modelName) { if (association.isPolymorphic) { this._dependentAssociations.polymorphic.push(association); } else { this._dependentAssociations[modelName] = this._dependentAssociations[modelName] || []; this._dependentAssociations[modelName].push(association); } } dependentAssociationsFor(modelName) { let directDependents = this._dependentAssociations[modelName] || []; let polymorphicAssociations = this._dependentAssociations.polymorphic || []; return directDependents.concat(polymorphicAssociations); } /** Returns an object containing the associations registered for the model of the given _modelName_. For example, given this configuration ```js import { createServer, Model, hasMany, belongsTo } from 'miragejs' let server = createServer({ models: { user: Model, article: Model.extend({ fineAuthor: belongsTo("user"), comments: hasMany() }), comment: Model } }) ``` each of the following would return empty objects ```js server.schema.associationsFor('user') // {} server.schema.associationsFor('comment') // {} ``` but the associations for the `article` would return ```js server.schema.associationsFor('article') // { // fineAuthor: BelongsToAssociation, // comments: HasManyAssociation // } ``` Check out the docs on the Association class to see what fields are available for each association. @method associationsFor @param {String} modelName @return {Object} @public */ associationsFor(modelName) { let modelClass = this.modelClassFor(modelName); return Object.assign( {}, modelClass.belongsToAssociations, modelClass.hasManyAssociations ); } hasModelForModelName(modelName) { return this.modelFor(camelize(modelName)); } /* Private methods */ /** @method collectionForType @param type @private @hide */ collectionForType(type) { let collection = this.toCollectionName(type); assert( this.db[collection], `You're trying to find model(s) of type ${type} but this collection doesn't exist in the database.` ); return this.db[collection]; } toCollectionName(type) { if (typeof collectionNameCache[type] !== "string") { let modelName = dasherize(type); const collectionName = camelize( this._container.inflector.pluralize(modelName) ); collectionNameCache[type] = collectionName; } return collectionNameCache[type]; } // This is to get at the underlying Db collection. Poorly named... need to // refactor to DbTable or something. toInternalCollectionName(type) { if (typeof internalCollectionNameCache[type] !== "string") { const internalCollectionName = `_${this.toCollectionName(type)}`; internalCollectionNameCache[type] = internalCollectionName; } return internalCollectionNameCache[type]; } toModelName(type) { if (typeof modelNameCache[type] !== "string") { let dasherized = dasherize(type); const modelName = this._container.inflector.singularize(dasherized); modelNameCache[type] = modelName; } return modelNameCache[type]; } /** @method _addForeignKeyToRegistry @param type @param fk @private @hide */ _addForeignKeyToRegistry(type, fk) { this._registry[type] = this._registry[type] || { class: null, foreignKeys: [], }; let fks = this._registry[type].foreignKeys; if (!fks.includes(fk)) { fks.push(fk); } } /** @method _instantiateModel @param modelName @param attrs @private @hide */ _instantiateModel(modelName, attrs) { let ModelClass = this._modelFor(modelName); let fks = this._foreignKeysFor(modelName); return new ModelClass(this, modelName, attrs, fks); } /** @method _modelFor @param modelName @private @hide */ _modelFor(modelName) { return this._registry[camelize(modelName)].class; } /** @method _foreignKeysFor @param modelName @private @hide */ _foreignKeysFor(modelName) { return this._registry[camelize(modelName)].foreignKeys; } /** Takes a record and returns a model, or an array of records and returns a collection. * @method _hydrate @param records @param modelName @private @hide */ _hydrate(records, modelName) { if (Array.isArray(records)) { let models = records.map(function (record) { return this._instantiateModel(modelName, record); }, this); return new Collection(modelName, models); } else if (records) { return this._instantiateModel(modelName, records); } else { return null; } } } miragejs-0.1.42/lib/response.js000066400000000000000000000031771412317504700163550ustar00rootroot00000000000000const warn = console.warn; // eslint-disable-line no-console /** You can use this class when you want more control over your route handlers response. Pass the `code`, `headers` and `data` into the constructor and return an instance from any route handler. ```js import { Response } from 'miragejs'; this.get('/users', () => { return new Response(400, { some: 'header' }, { errors: [ 'name cannot be blank'] }); }); ``` */ export default class Response { constructor(code, headers = {}, data) { this.code = code; this.headers = headers; // Default data for "undefined 204" responses to empty string (no content) if (code === 204) { if (data !== undefined && data !== "") { warn( `Mirage: One of your route handlers is returning a custom 204 Response that has data, but this is a violation of the HTTP spec and could lead to unexpected behavior. 204 responses should have no content (an empty string) as their body.` ); } else { this.data = ""; } // Default data for "empty untyped" responses to empty JSON object } else if ( (data === undefined || data === "") && !Object.prototype.hasOwnProperty.call(this.headers, "Content-Type") ) { this.data = {}; } else { this.data = data; } // Default "untyped" responses to application/json if ( code !== 204 && !Object.prototype.hasOwnProperty.call(this.headers, "Content-Type") ) { this.headers["Content-Type"] = "application/json"; } } toRackResponse() { return [this.code, this.headers, this.data]; } } miragejs-0.1.42/lib/route-handler.js000066400000000000000000000076041412317504700172670ustar00rootroot00000000000000import { MirageError } from "./assert"; import Response from "./response"; import FunctionHandler from "./route-handlers/function"; import ObjectHandler from "./route-handlers/object"; import GetShorthandHandler from "./route-handlers/shorthands/get"; import PostShorthandHandler from "./route-handlers/shorthands/post"; import PutShorthandHandler from "./route-handlers/shorthands/put"; import DeleteShorthandHandler from "./route-handlers/shorthands/delete"; import HeadShorthandHandler from "./route-handlers/shorthands/head"; const DEFAULT_CODES = { get: 200, put: 204, post: 201, delete: 204 }; function createHandler({ verb, schema, serializerOrRegistry, path, rawHandler, options, }) { let handler; let args = [schema, serializerOrRegistry, rawHandler, path, options]; let type = typeof rawHandler; if (type === "function") { handler = new FunctionHandler(...args); } else if (type === "object" && rawHandler) { handler = new ObjectHandler(...args); } else if (verb === "get") { handler = new GetShorthandHandler(...args); } else if (verb === "post") { handler = new PostShorthandHandler(...args); } else if (verb === "put" || verb === "patch") { handler = new PutShorthandHandler(...args); } else if (verb === "delete") { handler = new DeleteShorthandHandler(...args); } else if (verb === "head") { handler = new HeadShorthandHandler(...args); } return handler; } /** * @hide */ export default class RouteHandler { constructor({ schema, verb, rawHandler, customizedCode, options, path, serializerOrRegistry, }) { this.verb = verb; this.customizedCode = customizedCode; this.serializerOrRegistry = serializerOrRegistry; this.handler = createHandler({ verb, schema, path, serializerOrRegistry, rawHandler, options, }); } handle(request) { return this._getMirageResponseForRequest(request) .then((mirageResponse) => this.serialize(mirageResponse, request)) .then((serializedMirageResponse) => { return serializedMirageResponse.toRackResponse(); }); } _getMirageResponseForRequest(request) { let result; try { /* We need to do this for the #serialize convenience method. Probably is a better way. */ if (this.handler instanceof FunctionHandler) { this.handler.setRequest(request); } result = this.handler.handle(request); } catch (e) { if (e instanceof MirageError) { result = new Response(500, {}, e); } else { let message = e.message || e; result = new Response( 500, {}, { message, stack: `Mirage: Your ${request.method} handler for the url ${ request.url } threw an error:\n\n${e.stack || e}`, } ); } } return this._toMirageResponse(result); } _toMirageResponse(result) { let mirageResponse; return new Promise((resolve, reject) => { Promise.resolve(result) .then((response) => { if (response instanceof Response) { mirageResponse = result; } else { let code = this._getCodeForResponse(response); mirageResponse = new Response(code, {}, response); } resolve(mirageResponse); }) .catch(reject); }); } _getCodeForResponse(response) { let code; if (this.customizedCode) { code = this.customizedCode; } else { code = DEFAULT_CODES[this.verb]; // Returning any data for a 204 is invalid if (code === 204 && response !== undefined && response !== "") { code = 200; } } return code; } serialize(mirageResponse, request) { mirageResponse.data = this.serializerOrRegistry.serialize( mirageResponse.data, request ); return mirageResponse; } } miragejs-0.1.42/lib/route-handlers/000077500000000000000000000000001412317504700171055ustar00rootroot00000000000000miragejs-0.1.42/lib/route-handlers/base.js000066400000000000000000000072071412317504700203630ustar00rootroot00000000000000import assert from "../assert"; import { camelize, dasherize } from "../utils/inflector"; import HasMany from "../orm/associations/has-many"; const pathModelClassCache = {}; /** @hide */ export default class BaseRouteHandler { getModelClassFromPath(fullPath) { if (!fullPath) { return; } if (typeof pathModelClassCache[fullPath] !== "string") { let path = fullPath.split("/"); let lastPath; for (let i = path.length - 1; i >= 0; i--) { const segment = path[i]; if (segment.length && segment[0] !== ":") { lastPath = segment; break; } } pathModelClassCache[fullPath] = dasherize( camelize(this._container.inflector.singularize(lastPath)) ); } return pathModelClassCache[fullPath]; } _getIdForRequest(request, jsonApiDoc) { let id; if (request && request.params && request.params.id) { id = request.params.id; } else if (jsonApiDoc && jsonApiDoc.data && jsonApiDoc.data.id) { id = jsonApiDoc.data.id; } return id; } _getJsonApiDocForRequest(request, modelName) { let body; if (request && request.requestBody) { body = JSON.parse(request.requestBody); } return this.serializerOrRegistry.normalize(body, modelName); } _getAttrsForRequest(request, modelName) { let json = this._getJsonApiDocForRequest(request, modelName); let id = this._getIdForRequest(request, json); let attrs = {}; assert( json.data && (json.data.attributes || json.data.type || json.data.relationships), `You're using a shorthand or #normalizedRequestAttrs, but your serializer's normalize function did not return a valid JSON:API document. Consult the docs for the normalize hook on the Serializer class.` ); if (json.data.attributes) { attrs = Object.keys(json.data.attributes).reduce((sum, key) => { sum[camelize(key)] = json.data.attributes[key]; return sum; }, {}); } if (json.data.relationships) { Object.keys(json.data.relationships).forEach((relationshipName) => { let relationship = json.data.relationships[relationshipName]; let modelClass = this.schema.modelClassFor(modelName); let association = modelClass.associationFor(camelize(relationshipName)); let valueForRelationship; assert( association, `You're passing the relationship '${relationshipName}' to the '${modelName}' model via a ${request.method} to '${request.url}', but you did not define the '${relationshipName}' association on the '${modelName}' model.` ); if (association.isPolymorphic) { valueForRelationship = relationship.data; } else if (association instanceof HasMany) { valueForRelationship = relationship.data && relationship.data.map((rel) => rel.id); } else { valueForRelationship = relationship.data && relationship.data.id; } attrs[association.identifier] = valueForRelationship; }, {}); } if (id) { attrs.id = id; } return attrs; } _getAttrsForFormRequest({ requestBody }) { let attrs; let urlEncodedParts = []; assert( requestBody && typeof requestBody === "string", `You're using the helper method #normalizedFormData, but the request body is empty or not a valid url encoded string.` ); urlEncodedParts = requestBody.split("&"); attrs = urlEncodedParts.reduce((a, urlEncodedPart) => { let [key, value] = urlEncodedPart.split("="); a[key] = decodeURIComponent(value.replace(/\+/g, " ")); return a; }, {}); return attrs; } } miragejs-0.1.42/lib/route-handlers/function.js000066400000000000000000000041701412317504700212720ustar00rootroot00000000000000import BaseRouteHandler from "./base"; import assert from "../assert"; import { dasherize } from "../utils/inflector"; /** * @hide */ export default class FunctionRouteHandler extends BaseRouteHandler { constructor(schema, serializerOrRegistry, userFunction, path, server) { super(server); this.schema = schema; this.serializerOrRegistry = serializerOrRegistry; this.userFunction = userFunction; this.path = path; } handle(request) { return this.userFunction(this.schema, request); } setRequest(request) { this.request = request; } serialize(response, serializerType) { let serializer; if (serializerType) { serializer = this.serializerOrRegistry.serializerFor(serializerType, { explicit: true, }); } else { serializer = this.serializerOrRegistry; } return serializer.serialize(response, this.request); } normalizedRequestAttrs(modelName = null) { let { path, request, request: { requestHeaders }, } = this; let attrs; let lowerCaseHeaders = {}; for (let header in requestHeaders) { lowerCaseHeaders[header.toLowerCase()] = requestHeaders[header]; } if (/x-www-form-urlencoded/.test(lowerCaseHeaders["content-type"])) { attrs = this._getAttrsForFormRequest(request); } else { if (modelName) { assert( dasherize(modelName) === modelName, `You called normalizedRequestAttrs('${modelName}'), but normalizedRequestAttrs was intended to be used with the dasherized version of the model type. Please change this to normalizedRequestAttrs('${dasherize( modelName )}').` ); } else { modelName = this.getModelClassFromPath(path); } assert( this.schema.hasModelForModelName(modelName), `You're using a shorthand or the #normalizedRequestAttrs helper but the detected model of '${modelName}' does not exist. You might need to pass in the correct modelName as the first argument to #normalizedRequestAttrs.` ); attrs = this._getAttrsForRequest(request, modelName); } return attrs; } } miragejs-0.1.42/lib/route-handlers/object.js000066400000000000000000000004301412317504700207060ustar00rootroot00000000000000/** * @hide */ export default class ObjectRouteHandler { constructor(schema, serializerOrRegistry, object) { this.schema = schema; this.serializerOrRegistry = serializerOrRegistry; this.object = object; } handle(/* request */) { return this.object; } } miragejs-0.1.42/lib/route-handlers/shorthands/000077500000000000000000000000001412317504700212625ustar00rootroot00000000000000miragejs-0.1.42/lib/route-handlers/shorthands/base.js000066400000000000000000000020701412317504700225310ustar00rootroot00000000000000import BaseRouteHandler from "../base"; /** @hide */ export default class BaseShorthandRouteHandler extends BaseRouteHandler { constructor(schema, serializerOrRegistry, shorthand, path, options = {}) { super(); shorthand = shorthand || this.getModelClassFromPath(path); this.schema = schema; this.serializerOrRegistry = serializerOrRegistry; this.shorthand = shorthand; this.options = options; let type = Array.isArray(shorthand) ? "array" : typeof shorthand; if (type === "string") { let modelClass = this.schema[this.schema.toCollectionName(shorthand)]; this.handle = (request) => { return this.handleStringShorthand(request, modelClass); }; } else if (type === "array") { let modelClasses = shorthand.map( (modelName) => this.schema[this.schema.toCollectionName(modelName)] ); this.handle = (request) => { return this.handleArrayShorthand(request, modelClasses); }; } } // handleStringShorthand() { // // } // // handleArrayShorthand() { // // } } miragejs-0.1.42/lib/route-handlers/shorthands/delete.js000066400000000000000000000030411412317504700230600ustar00rootroot00000000000000import assert from "../../assert"; import BaseShorthandRouteHandler from "./base"; import { camelize } from "../../utils/inflector"; import Response from "../../response"; /** * @hide */ export default class DeleteShorthandRouteHandler extends BaseShorthandRouteHandler { /* Remove the model from the db of type *camelizedModelName*. This would remove the user with id :id: Ex: this.del('/contacts/:id', 'user'); */ handleStringShorthand(request, modelClass) { let modelName = this.shorthand; let camelizedModelName = camelize(modelName); assert( modelClass, `The route handler for ${request.url} is trying to access the ${camelizedModelName} model, but that model doesn't exist.` ); let id = this._getIdForRequest(request); let model = modelClass.find(id); if (!model) { return new Response(404); } model.destroy(); } /* Remove the model and child related models from the db. This would remove the contact with id `:id`, as well as this contact's addresses and phone numbers. Ex: this.del('/contacts/:id', ['contact', 'addresses', 'numbers'); */ handleArrayShorthand(request, modelClasses) { let id = this._getIdForRequest(request); let parent = modelClasses[0].find(id); let childTypes = modelClasses .slice(1) .map((modelClass) => this._container.inflector.pluralize(modelClass.camelizedModelName) ); // Delete related children childTypes.forEach((type) => parent[type].destroy()); parent.destroy(); } } miragejs-0.1.42/lib/route-handlers/shorthands/get.js000066400000000000000000000043331412317504700224020ustar00rootroot00000000000000import assert from "../../assert"; import BaseShorthandRouteHandler from "./base"; import Response from "../../response"; import { camelize } from "../../utils/inflector"; /** * @hide */ export default class GetShorthandRouteHandler extends BaseShorthandRouteHandler { /* Retrieve a model/collection from the db. Examples: this.get('/contacts', 'contact'); this.get('/contacts/:id', 'contact'); */ handleStringShorthand(request, modelClass) { let modelName = this.shorthand; let camelizedModelName = camelize(modelName); assert( modelClass, `The route handler for ${request.url} is trying to access the ${camelizedModelName} model, but that model doesn't exist.` ); let id = this._getIdForRequest(request); if (id) { let model = modelClass.find(id); if (!model) { return new Response(404); } else { return model; } } else if (this.options.coalesce) { let ids = this.serializerOrRegistry.getCoalescedIds( request, camelizedModelName ); if (ids) { return modelClass.find(ids); } } return modelClass.all(); } /* Retrieve an array of collections from the db. Ex: this.get('/home', ['contacts', 'pictures']); */ handleArrayShorthand(request, modelClasses) { let keys = this.shorthand; let id = this._getIdForRequest(request); /* If the first key is singular and we have an id param in the request, we're dealing with the version of the shorthand that has a parent model and several has-many relationships. We throw an error, because the serializer is the appropriate place for this now. */ assert( !id || this._container.inflector.singularize(keys[0]) !== keys[0], `It looks like you're using the "Single record with related records" version of the array shorthand, in addition to opting in to the model layer. This shorthand was made when there was no serializer layer. Now that you're using models, please ensure your relationships are defined, and create a serializer for the parent model, adding the relationships there.` ); return modelClasses.map((modelClass) => modelClass.all()); } } miragejs-0.1.42/lib/route-handlers/shorthands/head.js000066400000000000000000000024011412317504700225160ustar00rootroot00000000000000import assert from "../../assert"; import BaseShorthandRouteHandler from "./base"; import Response from "../../response"; import { camelize } from "../../utils/inflector"; /** * @hide */ export default class HeadShorthandRouteHandler extends BaseShorthandRouteHandler { /* Retrieve a model/collection from the db. Examples: this.head('/contacts', 'contact'); this.head('/contacts/:id', 'contact'); */ handleStringShorthand(request, modelClass) { let modelName = this.shorthand; let camelizedModelName = camelize(modelName); assert( modelClass, `The route handler for ${request.url} is trying to access the ${camelizedModelName} model, but that model doesn't exist.` ); let id = this._getIdForRequest(request); if (id) { let model = modelClass.find(id); if (!model) { return new Response(404); } else { return new Response(204); } } else if ( this.options.coalesce && request.queryParams && request.queryParams.ids ) { let model = modelClass.find(request.queryParams.ids); if (!model) { return new Response(404); } else { return new Response(204); } } else { return new Response(204); } } } miragejs-0.1.42/lib/route-handlers/shorthands/post.js000066400000000000000000000014751412317504700226140ustar00rootroot00000000000000import assert from "../../assert"; import BaseShorthandRouteHandler from "./base"; import { camelize } from "../../utils/inflector"; /** * @hide */ export default class PostShorthandRouteHandler extends BaseShorthandRouteHandler { /* Push a new model of type *camelizedModelName* to the db. For example, this will push a 'user': this.post('/contacts', 'user'); */ handleStringShorthand(request, modelClass) { let modelName = this.shorthand; let camelizedModelName = camelize(modelName); assert( modelClass, `The route handler for ${request.url} is trying to access the ${camelizedModelName} model, but that model doesn't exist.` ); let attrs = this._getAttrsForRequest( request, modelClass.camelizedModelName ); return modelClass.create(attrs); } } miragejs-0.1.42/lib/route-handlers/shorthands/put.js000066400000000000000000000016761412317504700224420ustar00rootroot00000000000000import assert from "../../assert"; import BaseShorthandRouteHandler from "./base"; import { camelize } from "../../utils/inflector"; import Response from "../../response"; /** * @hide */ export default class PutShorthandRouteHandler extends BaseShorthandRouteHandler { /* Update an object from the db, specifying the type. this.put('/contacts/:id', 'user'); */ handleStringShorthand(request, modelClass) { let modelName = this.shorthand; let camelizedModelName = camelize(modelName); assert( modelClass, `The route handler for ${request.url} is trying to access the ${camelizedModelName} model, but that model doesn't exist.` ); let id = this._getIdForRequest(request); let model = modelClass.find(id); if (!model) { return new Response(404); } let attrs = this._getAttrsForRequest( request, modelClass.camelizedModelName ); return model.update(attrs); } } miragejs-0.1.42/lib/serializer-registry.js000066400000000000000000000054761412317504700205420ustar00rootroot00000000000000import Model from "./orm/model"; import Collection from "./orm/collection"; import PolymorphicCollection from "./orm/polymorphic-collection"; import Serializer from "./serializer"; import JsonApiSerializer from "./serializers/json-api-serializer"; import { camelize } from "./utils/inflector"; import assert from "./assert"; /** * @hide */ export default class SerializerRegistry { constructor(schema, serializerMap = {}, server) { this.schema = schema; this._serializerMap = serializerMap; } normalize(payload, modelName) { return this.serializerFor(modelName).normalize(payload); } serialize(response, request) { this.request = request; if (this._isModelOrCollection(response)) { let serializer = this.serializerFor(response.modelName); return serializer.serialize(response, request); } else if (Array.isArray(response) && response.some(this._isCollection)) { return response.reduce((json, collection) => { let serializer = this.serializerFor(collection.modelName); if (serializer.embed) { json[ this._container.inflector.pluralize(collection.modelName) ] = serializer.serialize(collection, request); } else { json = Object.assign(json, serializer.serialize(collection, request)); } return json; }, {}); } else { return response; } } serializerFor(type, { explicit = false } = {}) { let SerializerForResponse = type && this._serializerMap && this._serializerMap[camelize(type)]; if (explicit) { assert( !!SerializerForResponse, `You passed in ${type} as an explicit serializer type but that serializer doesn't exist.` ); } else { SerializerForResponse = SerializerForResponse || this._serializerMap.application || Serializer; assert( !SerializerForResponse || SerializerForResponse.prototype.embed || SerializerForResponse.prototype.root || new SerializerForResponse() instanceof JsonApiSerializer, "You cannot have a serializer that sideloads (embed: false) and disables the root (root: false)." ); } return new SerializerForResponse(this, type, this.request); } _isModel(object) { return object instanceof Model; } _isCollection(object) { return ( object instanceof Collection || object instanceof PolymorphicCollection ); } _isModelOrCollection(object) { return this._isModel(object) || this._isCollection(object); } registerSerializers(newSerializerMaps) { let currentSerializerMap = this._serializerMap || {}; this._serializerMap = Object.assign( currentSerializerMap, newSerializerMaps ); } getCoalescedIds(request, modelName) { return this.serializerFor(modelName).getCoalescedIds(request); } } miragejs-0.1.42/lib/serializer.js000066400000000000000000000712351412317504700166700ustar00rootroot00000000000000import Model from "./orm/model"; import Collection from "./orm/collection"; import PolymorphicCollection from "./orm/polymorphic-collection"; import extend from "./utils/extend"; import { camelize } from "./utils/inflector"; import assert from "./assert"; import isFunction from "lodash.isfunction"; import isEmpty from "lodash.isempty"; import get from "lodash.get"; import flatten from "lodash.flatten"; import compact from "lodash.compact"; import uniqBy from "lodash.uniqby"; /** Serializers are responsible for formatting your route handler's response. The application serializer will apply to every response. To make specific customizations, define per-model serializers. ```js import { createServer, RestSerializer } from 'miragejs'; createServer({ serializers: { application: RestSerializer, user: RestSerializer.extend({ // user-specific customizations }) } }) ``` Any Model or Collection returned from a route handler will pass through the serializer layer. Highest priority will be given to a model-specific serializer, then the application serializer, then the default serializer. Mirage ships with three named serializers: - **JSONAPISerializer**, to simulate JSON:API compliant API servers: ```js import { createServer, JSONAPISerializer } from 'miragejs'; createServer({ serializers: { application: JSONAPISerializer } }) ``` - **ActiveModelSerializer**, to mock Rails APIs that use AMS-style responses: ```js import { createServer, ActiveModelSerializer } from 'miragejs'; createServer({ serializers: { application: ActiveModelSerializer } }) ``` - **RestSerializer**, a good starting point for many generic REST APIs: ```js import { createServer, RestSerializer } from 'miragejs'; createServer({ serializers: { application: RestSerializer } }) ``` Additionally, Mirage has a basic Serializer class which you can customize using the hooks documented below: ```js import { createServer, Serializer } from 'miragejs'; createServer({ serializers: { application: Serializer } }) ``` When writing model-specific serializers, remember to extend from your application serializer so shared logic is used by your model-specific classes: ```js import { createServer, Serializer } from 'miragejs'; const ApplicationSerializer = Serializer.extend() createServer({ serializers: { application: ApplicationSerializer, blogPost: ApplicationSerializer.extend({ include: ['comments'] }) } }) ``` @class Serializer @constructor @public */ class Serializer { constructor(registry, type, request = {}) { this.registry = registry; this.type = type; this.request = request; /** Use this property on a model serializer to whitelist attributes that will be used in your JSON payload. For example, if you had a `blog-post` model in your database that looked like ``` { id: 1, title: 'Lorem ipsum', createdAt: '2014-01-01 10:00:00', updatedAt: '2014-01-03 11:42:12' } ``` and you just wanted `id` and `title`, you could write ```js Serializer.extend({ attrs: ['id', 'title'] }); ``` and the payload would look like ``` { id: 1, title: 'Lorem ipsum' } ``` @property attrs @public */ this.attrs = this.attrs || undefined; // this is just here so I can add the doc comment. Better way? /** Use this property on a model serializer to specify related models you'd like to include in your JSON payload. (These can be considered default server-side includes.) For example, if you had an `author` with many `blog-post`s and you wanted to sideload these, specify so in the `include` key: ```js createServer({ models: { author: Model.extend({ blogPosts: hasMany() }) }, serializers: { author: Serializer.extend({ include: ['blogPosts'] }); } }) ``` Now a response to a request for an author would look like this: ``` GET /authors/1 { author: { id: 1, name: 'Link', blogPostIds: [1, 2] }, blogPosts: [ {id: 1, authorId: 1, title: 'Lorem'}, {id: 2, authorId: 1, title: 'Ipsum'} ] } ``` You can also define `include` as a function so it can be determined dynamically. For example, you could conditionally include a relationship based on an `include` query parameter: ```js // Include blog posts for a GET to /authors/1?include=blogPosts Serializer.extend({ include: function(request) { if (request.queryParams.include === "blogPosts") { return ['blogPosts']; } else { return []; } } }); ``` **Query param includes for JSONAPISerializer** The JSONAPISerializer supports the use of `include` query parameter to return compound documents out of the box. For example, if your app makes the following request ``` GET /api/authors?include=blogPosts ``` the `JSONAPISerializer` will inspect the query params of the request, see that the blogPosts relationship is present, and then proceed as if this relationship was specified directly in the include: [] array on the serializer itself. Note that, in accordance with the spec, Mirage gives precedence to an ?include query param over a default include: [] array that you might have specified directly on the serializer. Default includes will still be in effect, however, if a request does not have an ?include query param. Also note that default includes specified with the `include: []` array can only take a single model; they cannot take dot-separated paths to nested relationships. If you'd like to set a default dot-separated (nested) include path for a resource, you have to do it at the route level by setting a default value for `request.queryParams`: ```js this.get('/users', function(schema, request) => { request.queryParams = request.queryParams || {}; if (!request.queryParams.include) { request.queryParams.include = 'blog-posts.comments'; } // rest of route handler logic }); ``` @property include @public */ this.include = this.include || []; // this is just here so I can add the doc comment. Better way? /** Set whether your JSON response should have a root key in it. *Doesn't apply to JSONAPISerializer.* Defaults to true, so a request for an author looks like: ``` GET /authors/1 { author: { id: 1, name: 'Link' } } ``` Setting `root` to false disables this: ```js Serializer.extend({ root: false }); ``` Now the response looks like: ``` GET /authors/1 { id: 1, name: 'Link' } ``` @property root @public */ this.root = this.root || undefined; // this is just here so I can add the doc comment. Better way? /** Set whether related models should be embedded or sideloaded. *Doesn't apply to JSONAPISerializer.* By default this false, so relationships are sideloaded: ``` GET /authors/1 { author: { id: 1, name: 'Link', blogPostIds: [1, 2] }, blogPosts: [ { id: 1, authorId: 1, title: 'Lorem' }, { id: 2, authorId: 1, title: 'Ipsum' } ] } ``` Setting `embed` to true will embed related records: ```js Serializer.extend({ embed: true }); ``` Now the response looks like: ``` GET /authors/1 { author: { id: 1, name: 'Link', blogPosts: [ { id: 1, authorId: 1, title: 'Lorem' }, { id: 2, authorId: 1, title: 'Ipsum' } ] } } ``` */ this.embed = this.embed || undefined; // this is just here so I can add the doc comment. Better way? /** Use this to define how your serializer handles serializing relationship keys. It can take one of three values: - `included`, which is the default, will serialize the ids of a relationship if that relationship is included (sideloaded) along with the model or collection in the response - `always` will always serialize the ids of all relationships for the model or collection in the response - `never` will never serialize the ids of relationships for the model or collection in the response @property serializeIds @public */ this.serializeIds = this.serializeIds || undefined; // this is just here so I can add the doc comment. Better way? } /** Override this method to implement your own custom serialize function. *response* is whatever was returned from your route handler, and *request* is the Pretender request object. Returns a plain JavaScript object or array, which Mirage uses as the response data to your app's XHR request. You can also override this method, call super, and manipulate the data before Mirage responds with it. This is a great place to add metadata, or for one-off operations that don't fit neatly into any of Mirage's other abstractions: ```js serialize(object, request) { // This is how to call super, as Mirage borrows [Backbone's implementation of extend](http://backbonejs.org/#Model-extend) let json = Serializer.prototype.serialize.apply(this, arguments); // Add metadata, sort parts of the response, etc. return json; } ``` @param primaryResource @param request @return { Object } the json response */ serialize(primaryResource /* , request */) { this.primaryResource = primaryResource; return this.buildPayload(primaryResource); } /** This method is used by the POST and PUT shorthands. These shorthands expect a valid JSON:API document as part of the request, so that they know how to create or update the appropriate resouce. The *normalize* method allows you to transform your request body into a JSON:API document, which lets you take advantage of the shorthands when you otherwise may not be able to. Note that this method is a noop if you're using JSON:API already, since request payloads sent along with POST and PUT requests will already be in the correct format. Take a look at the included `ActiveModelSerializer`'s normalize method for an example. @method normalize @param json @public */ normalize(json) { return json; } buildPayload(primaryResource, toInclude, didSerialize, json) { if (!primaryResource && isEmpty(toInclude)) { return json; } else if (primaryResource) { let [resourceHash, newIncludes] = this.getHashForPrimaryResource( primaryResource ); let newDidSerialize = this.isCollection(primaryResource) ? primaryResource.models : [primaryResource]; return this.buildPayload( undefined, newIncludes, newDidSerialize, resourceHash ); } else { let nextIncludedResource = toInclude.shift(); let [resourceHash, newIncludes] = this.getHashForIncludedResource( nextIncludedResource ); let newToInclude = newIncludes .filter((resource) => { return !didSerialize .map((m) => m.toString()) .includes(resource.toString()); }) .concat(toInclude); let newDidSerialize = (this.isCollection(nextIncludedResource) ? nextIncludedResource.models : [nextIncludedResource] ).concat(didSerialize); let newJson = this.mergePayloads(json, resourceHash); return this.buildPayload( undefined, newToInclude, newDidSerialize, newJson ); } } getHashForPrimaryResource(resource) { let [hash, addToIncludes] = this.getHashForResource(resource); let hashWithRoot; if (this.root) { assert( !(resource instanceof PolymorphicCollection), `The base Serializer class cannot serialize a top-level PolymorphicCollection when root is true, since PolymorphicCollections have no type.` ); let serializer = this.serializerFor(resource.modelName); let rootKey = serializer.keyForResource(resource); hashWithRoot = { [rootKey]: hash }; } else { hashWithRoot = hash; } return [hashWithRoot, addToIncludes]; } getHashForIncludedResource(resource) { let hashWithRoot, addToIncludes; if (resource instanceof PolymorphicCollection) { hashWithRoot = {}; addToIncludes = resource.models; } else { let serializer = this.serializerFor(resource.modelName); let [hash, newModels] = serializer.getHashForResource(resource); // Included resources always have a root, and are always pushed to an array. let rootKey = serializer.keyForRelationship(resource.modelName); hashWithRoot = Array.isArray(hash) ? { [rootKey]: hash } : { [rootKey]: [hash] }; addToIncludes = newModels; } return [hashWithRoot, addToIncludes]; } getHashForResource( resource, removeForeignKeys = false, didSerialize = {}, lookupSerializer = false ) { let hash, serializer; if (!lookupSerializer) { serializer = this; // this is used for embedded responses } // PolymorphicCollection lacks a modelName, but is dealt with in the map // by looking up the serializer on a per-model basis if (lookupSerializer && resource.modelName) { serializer = this.serializerFor(resource.modelName); } if (this.isModel(resource)) { hash = serializer._hashForModel( resource, removeForeignKeys, didSerialize ); } else { hash = resource.models.map((m) => { let modelSerializer = serializer; if (!modelSerializer) { // Can't get here if lookupSerializer is false, so look it up modelSerializer = this.serializerFor(m.modelName); } return modelSerializer._hashForModel( m, removeForeignKeys, didSerialize ); }); } if (this.embed) { return [hash, []]; } else { let addToIncludes = uniqBy( compact( flatten( serializer.getKeysForIncluded().map((key) => { if (this.isCollection(resource)) { return resource.models.map((m) => m[key]); } else { return resource[key]; } }) ) ), (m) => m.toString() ); return [hash, addToIncludes]; } } /* Merges new resource hash into json. If json already has root key, pushes value of resourceHash onto that key. For example, json = { post: { id: 1, title: 'Lorem Ipsum', comment_ids: [1, 3] }, comments: [ { id: 1, text: 'foo' } ] }; resourceHash = { comments: [ { id: 2, text: 'bar' } ] }; would yield { post: { id: 1, title: 'Lorem Ipsum', comment_ids: [1, 3] }, comments: [ { id: 1, text: 'foo' }, { id: 2, text: 'bar' } ] }; */ mergePayloads(json, resourceHash) { let newJson; let [resourceHashKey] = Object.keys(resourceHash); if (json[resourceHashKey]) { newJson = json; newJson[resourceHashKey] = json[resourceHashKey].concat( resourceHash[resourceHashKey] ); } else { newJson = Object.assign(json, resourceHash); } return newJson; } keyForResource(resource) { let { modelName } = resource; return this.isModel(resource) ? this.keyForModel(modelName) : this.keyForCollection(modelName); } /** Used to define a custom key when serializing a primary model of modelName *modelName*. For example, the default Serializer will return something like the following: ``` GET /blogPosts/1 { blogPost: { id: 1, title: 'Lorem ipsum' } } ``` If your API uses hyphenated keys, you could overwrite `keyForModel`: ```js // serializers/application.js export default Serializer.extend({ keyForModel(modelName) { return hyphenate(modelName); } }); ``` Now the response will look like ``` { 'blog-post': { id: 1, title: 'Lorem ipsum' } } ``` @method keyForModel @param modelName @public */ keyForModel(modelName) { return camelize(modelName); } /** Used to customize the key when serializing a primary collection. By default this pluralizes the return value of `keyForModel`. For example, by default the following request may look like: ``` GET /blogPosts { blogPosts: [ { id: 1, title: 'Lorem ipsum' }, ... ] } ``` If your API hyphenates keys, you could overwrite `keyForCollection`: ```js // serializers/application.js export default Serializer.extend({ keyForCollection(modelName) { return this._container.inflector.pluralize(dasherize(modelName)); } }); ``` Now the response would look like: ``` { 'blog-posts': [ { id: 1, title: 'Lorem ipsum' }, ... ] } ``` @method keyForCollection @param modelName @public */ keyForCollection(modelName) { return this._container.inflector.pluralize(this.keyForModel(modelName)); } _hashForModel(model, removeForeignKeys, didSerialize = {}) { let attrs = this._attrsForModel(model); if (removeForeignKeys) { model.fks.forEach((fk) => { delete attrs[fk]; }); } if (this.embed) { let newDidSerialize = Object.assign({}, didSerialize); newDidSerialize[model.modelName] = newDidSerialize[model.modelName] || {}; newDidSerialize[model.modelName][model.id] = true; this.getKeysForIncluded().forEach((key) => { let associatedResource = model[key]; if ( associatedResource && !get( newDidSerialize, `${associatedResource.modelName}.${associatedResource.id}` ) ) { let [associatedResourceHash] = this.getHashForResource( associatedResource, true, newDidSerialize, true ); let formattedKey = this.keyForEmbeddedRelationship(key); attrs[formattedKey] = associatedResourceHash; if (this.isModel(associatedResource)) { let fk = `${camelize(key)}Id`; delete attrs[fk]; } } }); return attrs; } else { return this._maybeAddAssociationIds(model, attrs); } } /** @method _attrsForModel @param model @private @hide */ _attrsForModel(model) { let attrs = {}; if (this.attrs) { attrs = this.attrs.reduce((memo, attr) => { memo[attr] = model[attr]; return memo; }, {}); } else { attrs = Object.assign(attrs, model.attrs); } // Remove fks model.fks.forEach((key) => delete attrs[key]); return this._formatAttributeKeys(attrs); } /** @method _maybeAddAssociationIds @param model @param attrs @private @hide */ _maybeAddAssociationIds(model, attrs) { let newHash = Object.assign({}, attrs); if (this.serializeIds === "always") { model.associationKeys.forEach((key) => { let resource = model[key]; let association = model.associationFor(key); if (this.isCollection(resource)) { let formattedKey = this.keyForRelationshipIds(key); newHash[formattedKey] = model[`${this._container.inflector.singularize(key)}Ids`]; } else if (this.isModel(resource) && association.isPolymorphic) { let formattedTypeKey = this.keyForPolymorphicForeignKeyType(key); let formattedIdKey = this.keyForPolymorphicForeignKeyId(key); newHash[formattedTypeKey] = model[`${key}Id`].type; newHash[formattedIdKey] = model[`${key}Id`].id; } else if (resource) { let formattedKey = this.keyForForeignKey(key); newHash[formattedKey] = model[`${key}Id`]; } }); } else if (this.serializeIds === "included") { this.getKeysForIncluded().forEach((key) => { let resource = model[key]; let association = model.associationFor(key); if (this.isCollection(resource)) { let formattedKey = this.keyForRelationshipIds(key); newHash[formattedKey] = model[`${this._container.inflector.singularize(key)}Ids`]; } else if (this.isModel(resource) && association.isPolymorphic) { let formattedTypeKey = this.keyForPolymorphicForeignKeyType(key); let formattedIdKey = this.keyForPolymorphicForeignKeyId(key); newHash[formattedTypeKey] = model[`${key}Id`].type; newHash[formattedIdKey] = model[`${key}Id`].id; } else if (this.isModel(resource)) { let formattedKey = this.keyForForeignKey(key); newHash[formattedKey] = model[`${key}Id`]; } }); } return newHash; } /** Used to customize how a model's attribute is formatted in your JSON payload. By default, model attributes are camelCase: ``` GET /authors/1 { author: { firstName: 'Link', lastName: 'The WoodElf' } } ``` If your API expects snake case, you could write the following: ```js // serializers/application.js export default Serializer.extend({ keyForAttribute(attr) { return underscore(attr); } }); ``` Now the response would look like: ``` { author: { first_name: 'Link', last_name: 'The WoodElf' } } ``` @method keyForAttribute @param attr @public */ keyForAttribute(attr) { return attr; } /** Use this hook to format the key for collections related to this model. *modelName* is the named parameter for the relationship. For example, if you're serializing an `author` that sideloads many `blogPosts`, the default response will look like: ``` { author: {...}, blogPosts: [...] } ``` Overwrite `keyForRelationship` to format this key: ```js // serializers/application.js export default Serializer.extend({ keyForRelationship(modelName) { return underscore(modelName); } }); ``` Now the response will look like this: ``` { author: {...}, blog_posts: [...] } ``` @method keyForRelationship @param modelName @public */ keyForRelationship(modelName) { return camelize(this._container.inflector.pluralize(modelName)); } /** Like `keyForRelationship`, but for embedded relationships. @method keyForEmbeddedRelationship @param attributeName @public */ keyForEmbeddedRelationship(attributeName) { return camelize(attributeName); } /** Use this hook to format the key for the IDS of a `hasMany` relationship in this model's JSON representation. For example, if you're serializing an `author` that sideloads many `blogPosts`, by default your `author` JSON would include a `blogPostIds` key: ``` { author: { id: 1, blogPostIds: [1, 2, 3] }, blogPosts: [...] } ``` Overwrite `keyForRelationshipIds` to format this key: ```js // serializers/application.js export default Serializer.extend({ keyForRelationshipIds(relationship) { return underscore(relationship) + '_ids'; } }); ``` Now the response will look like: ``` { author: { id: 1, blog_post_ids: [1, 2, 3] }, blogPosts: [...] } ``` @method keyForRelationshipIds @param modelName @public */ keyForRelationshipIds(relationshipName) { return `${this._container.inflector.singularize( camelize(relationshipName) )}Ids`; } /** Like `keyForRelationshipIds`, but for `belongsTo` relationships. For example, if you're serializing a `blogPost` that sideloads one `author`, your `blogPost` JSON would include a `authorId` key: ``` { blogPost: { id: 1, authorId: 1 }, author: ... } ``` Overwrite `keyForForeignKey` to format this key: ```js // serializers/application.js export default Serializer.extend({ keyForForeignKey(relationshipName) { return underscore(relationshipName) + '_id'; } }); ``` Now the response will look like: ```js { blogPost: { id: 1, author_id: 1 }, author: ... } ``` @method keyForForeignKey @param relationshipName @public */ keyForForeignKey(relationshipName) { return `${camelize(relationshipName)}Id`; } /** Polymorphic relationships are represented with type-id pairs. Given the following model ```js Model.extend({ commentable: belongsTo({ polymorphic: true }) }); ``` the default Serializer would produce ```js { comment: { id: 1, commentableType: 'post', commentableId: '1' } } ``` This hook controls how the `id` field (`commentableId` in the above example) is serialized. By default it camelizes the relationship and adds `Id` as a suffix. @method keyForPolymorphicForeignKeyId @param {String} relationshipName @return {String} @public */ keyForPolymorphicForeignKeyId(relationshipName) { return `${camelize(relationshipName)}Id`; } /** Polymorphic relationships are represented with type-id pairs. Given the following model ```js Model.extend({ commentable: belongsTo({ polymorphic: true }) }); ``` the default Serializer would produce ```js { comment: { id: 1, commentableType: 'post', commentableId: '1' } } ``` This hook controls how the `type` field (`commentableType` in the above example) is serialized. By default it camelizes the relationship and adds `Type` as a suffix. @method keyForPolymorphicForeignKeyType @param {String} relationshipName @return {String} @public */ keyForPolymorphicForeignKeyType(relationshipName) { return `${camelize(relationshipName)}Type`; } /** @method isModel @param object @return {Boolean} @public @hide */ isModel(object) { return object instanceof Model; } /** @method isCollection @param object @return {Boolean} @public @hide */ isCollection(object) { return ( object instanceof Collection || object instanceof PolymorphicCollection ); } /** @method isModelOrCollection @param object @return {Boolean} @public @hide */ isModelOrCollection(object) { return this.isModel(object) || this.isCollection(object); } /** @method serializerFor @param type @public @hide */ serializerFor(type) { return this.registry.serializerFor(type); } getKeysForIncluded() { return isFunction(this.include) ? this.include(this.request, this.primaryResource) : this.include; } /** A reference to the schema instance. Useful to reference registered schema information, for example in a Serializer's include hook to include all a resource's associations: ```js Serializer.extend({ include(request, resource) { return Object.keys(this.schema.associationsFor(resource.modelName)); } }) ``` @property @type {Object} @public */ get schema() { return this.registry.schema; } /** @method _formatAttributeKeys @param attrs @private @hide */ _formatAttributeKeys(attrs) { let formattedAttrs = {}; for (let key in attrs) { let formattedKey = this.keyForAttribute(key); formattedAttrs[formattedKey] = attrs[key]; } return formattedAttrs; } getCoalescedIds(/* request */) {} } // Defaults Serializer.prototype.include = []; Serializer.prototype.root = true; Serializer.prototype.embed = false; Serializer.prototype.serializeIds = "included"; // can be 'included', 'always', or 'never' Serializer.extend = extend; export default Serializer; miragejs-0.1.42/lib/serializers/000077500000000000000000000000001412317504700165055ustar00rootroot00000000000000miragejs-0.1.42/lib/serializers/active-model-serializer.js000066400000000000000000000053761412317504700235760ustar00rootroot00000000000000import Serializer from "../serializer"; import { underscore, dasherize, camelize } from "../utils/inflector"; export default Serializer.extend({ serializeIds: "always", normalizeIds: true, keyForModel(type) { return underscore(type); }, keyForAttribute(attr) { return underscore(attr); }, keyForRelationship(type) { return this._container.inflector.pluralize(underscore(type)); }, keyForEmbeddedRelationship(attributeName) { return underscore(attributeName); }, keyForRelationshipIds(type) { return `${underscore(this._container.inflector.singularize(type))}_ids`; }, keyForForeignKey(relationshipName) { return `${underscore(relationshipName)}_id`; }, keyForPolymorphicForeignKeyId(relationshipName) { return `${underscore(relationshipName)}_id`; }, keyForPolymorphicForeignKeyType(relationshipName) { return `${underscore(relationshipName)}_type`; }, normalize(payload) { let type = Object.keys(payload)[0]; let attrs = payload[type]; let modelName = camelize(type); let modelClass = this.schema.modelClassFor(modelName); let { belongsToAssociations, hasManyAssociations } = modelClass; let belongsToKeys = Object.keys(belongsToAssociations); let hasManyKeys = Object.keys(hasManyAssociations); let jsonApiPayload = { data: { type: this._container.inflector.pluralize(type), attributes: {}, }, }; if (attrs.id) { jsonApiPayload.data.id = attrs.id; } let relationships = {}; Object.keys(attrs).forEach((key) => { if (key !== "id") { if (this.normalizeIds) { if (belongsToKeys.includes(key)) { let association = belongsToAssociations[key]; let associationModel = association.modelName; relationships[dasherize(key)] = { data: { type: associationModel, id: attrs[key], }, }; } else if (hasManyKeys.includes(key)) { let association = hasManyAssociations[key]; let associationModel = association.modelName; let data = attrs[key].map((id) => { return { type: associationModel, id, }; }); relationships[dasherize(key)] = { data }; } else { jsonApiPayload.data.attributes[dasherize(key)] = attrs[key]; } } else { jsonApiPayload.data.attributes[dasherize(key)] = attrs[key]; } } }); if (Object.keys(relationships).length) { jsonApiPayload.data.relationships = relationships; } return jsonApiPayload; }, getCoalescedIds(request) { return request.queryParams && request.queryParams.ids; }, }); miragejs-0.1.42/lib/serializers/json-api-serializer.js000066400000000000000000000415171412317504700227420ustar00rootroot00000000000000import Serializer from "../serializer"; import { dasherize, camelize } from "../utils/inflector"; import assert from "../assert"; import get from "lodash.get"; import flatten from "lodash.flatten"; import compact from "lodash.compact"; import uniqBy from "lodash.uniqby"; import isEmpty from "lodash.isempty"; /** The JSONAPISerializer. Subclass of Serializer. @class JSONAPISerializer @constructor @public */ class JSONAPISerializer extends Serializer { constructor() { super(...arguments); /** By default, JSON:API's linkage data is only added for relationships that are being included in the current request. That means given an `author` model with a `posts` relationship, a GET request to /authors/1 would return a JSON:API document with an empty `relationships` hash: ```js { data: { type: 'authors', id: '1', attributes: { ... } } } ``` but a request to GET /authors/1?include=posts would have linkage data added (in addition to the included resources): ```js { data: { type: 'authors', id: '1', attributes: { ... }, relationships: { data: [ { type: 'posts', id: '1' }, { type: 'posts', id: '2' }, { type: 'posts', id: '3' } ] } }, included: [ ... ] } ``` To add the linkage data for all relationships, you could set `alwaysIncludeLinkageData` to `true`: ```js JSONAPISerializer.extend({ alwaysIncludeLinkageData: true }); ``` Then, a GET to /authors/1 would respond with ```js { data: { type: 'authors', id: '1', attributes: { ... }, relationships: { posts: { data: [ { type: 'posts', id: '1' }, { type: 'posts', id: '2' }, { type: 'posts', id: '3' } ] } } } } ``` even though the related `posts` are not included in the same document. You can also use the `links` method (on the Serializer base class) to add relationship links (which will always be added regardless of the relationship is being included document), or you could use `shouldIncludeLinkageData` for more granular control. For more background on the behavior of this API, see [this blog post](http://www.ember-cli-mirage.com/blog/changing-mirages-default-linkage-data-behavior-1475). @property alwaysIncludeLinkageData @type {Boolean} @public */ this.alwaysIncludeLinkageData = this.alwaysIncludeLinkageData || undefined; // this is just here so I can add the doc comment. Better way? } // Don't think this is used? keyForModel(modelName) { return dasherize(modelName); } // Don't think this is used? keyForCollection(modelName) { return dasherize(modelName); } /** Used to customize the key for an attribute. By default, compound attribute names are dasherized. For example, the JSON:API document for a `post` model with a `commentCount` attribute would be: ```js { data: { id: 1, type: 'posts', attributes: { 'comment-count': 28 } } } ``` @method keyForAttribute @param {String} attr @return {String} @public */ keyForAttribute(attr) { return dasherize(attr); } /** Used to customize the key for a relationships. By default, compound relationship names are dasherized. For example, the JSON:API document for an `author` model with a `blogPosts` relationship would be: ```js { data: { id: 1, type: 'author', attributes: { ... }, relationships: { 'blog-posts': { ... } } } } ``` @method keyForRelationship @param {String} key @return {String} @public */ keyForRelationship(key) { return dasherize(key); } /** Use this hook to add top-level `links` data to JSON:API resource objects. The argument is the model being serialized. ```js // serializers/author.js import { JSONAPISerializer } from 'miragejs'; export default JSONAPISerializer.extend({ links(author) { return { 'posts': { related: `/api/authors/${author.id}/posts` } }; } }); ``` @method links @param model */ links() {} getHashForPrimaryResource(resource) { this._createRequestedIncludesGraph(resource); let resourceHash = this.getHashForResource(resource); let hashWithRoot = { data: resourceHash }; let addToIncludes = this.getAddToIncludesForResource(resource); return [hashWithRoot, addToIncludes]; } getHashForIncludedResource(resource) { let serializer = this.serializerFor(resource.modelName); let hash = serializer.getHashForResource(resource); let hashWithRoot = { included: this.isModel(resource) ? [hash] : hash }; let addToIncludes = []; if (!this.hasQueryParamIncludes()) { addToIncludes = this.getAddToIncludesForResource(resource); } return [hashWithRoot, addToIncludes]; } getHashForResource(resource) { let hash; if (this.isModel(resource)) { hash = this.getResourceObjectForModel(resource); } else { hash = resource.models.map((m) => this.getResourceObjectForModel(m)); } return hash; } /* Returns a flat unique list of resources that need to be added to includes */ getAddToIncludesForResource(resource) { let relationshipPaths; if (this.hasQueryParamIncludes()) { relationshipPaths = this.request.queryParams.include.split(","); } else { let serializer = this.serializerFor(resource.modelName); relationshipPaths = serializer.getKeysForIncluded(); } return this.getAddToIncludesForResourceAndPaths( resource, relationshipPaths ); } getAddToIncludesForResourceAndPaths(resource, relationshipPaths) { let includes = []; relationshipPaths.forEach((path) => { let relationshipNames = path.split("."); let newIncludes = this.getIncludesForResourceAndPath( resource, ...relationshipNames ); includes.push(newIncludes); }); return uniqBy(compact(flatten(includes)), (m) => m.toString()); } getIncludesForResourceAndPath(resource, ...names) { let nameForCurrentResource = camelize(names.shift()); let includes = []; let modelsToAdd = []; if (this.isModel(resource)) { let relationship = resource[nameForCurrentResource]; if (this.isModel(relationship)) { modelsToAdd = [relationship]; } else if (this.isCollection(relationship)) { modelsToAdd = relationship.models; } } else { resource.models.forEach((model) => { let relationship = model[nameForCurrentResource]; if (this.isModel(relationship)) { modelsToAdd.push(relationship); } else if (this.isCollection(relationship)) { modelsToAdd = modelsToAdd.concat(relationship.models); } }); } includes = includes.concat(modelsToAdd); if (names.length) { modelsToAdd.forEach((model) => { includes = includes.concat( this.getIncludesForResourceAndPath(model, ...names) ); }); } return includes; } getResourceObjectForModel(model) { let attrs = this._attrsForModel(model, true); delete attrs.id; let hash = { type: this.typeKeyForModel(model), id: model.id, attributes: attrs, }; return this._maybeAddRelationshipsToResourceObjectForModel(hash, model); } _maybeAddRelationshipsToResourceObjectForModel(hash, model) { const relationships = {}; model.associationKeys.forEach((key) => { let relationship = model[key]; let relationshipKey = this.keyForRelationship(key); let relationshipHash = {}; if (this.hasLinksForRelationship(model, key)) { let serializer = this.serializerFor(model.modelName); let links = serializer.links(model); relationshipHash.links = links[key]; } if ( this.alwaysIncludeLinkageData || this.shouldIncludeLinkageData(key, model) || this._relationshipIsIncludedForModel(key, model) ) { let data = null; if (this.isModel(relationship)) { data = { type: this.typeKeyForModel(relationship), id: relationship.id, }; } else if (this.isCollection(relationship)) { data = relationship.models.map((model) => { return { type: this.typeKeyForModel(model), id: model.id, }; }); } relationshipHash.data = data; } if (!isEmpty(relationshipHash)) { relationships[relationshipKey] = relationshipHash; } }); if (!isEmpty(relationships)) { hash.relationships = relationships; } return hash; } hasLinksForRelationship(model, relationshipKey) { let serializer = this.serializerFor(model.modelName); let links = serializer.links && serializer.links(model); return links && links[relationshipKey] != null; } /* This code (and a lot of this serializer) need to be re-worked according to the graph logic... */ _relationshipIsIncludedForModel(relationshipKey, model) { if (this.hasQueryParamIncludes()) { let graph = this.request._includesGraph; let graphKey = this._graphKeyForModel(model); // Find the resource in the graph let graphResource; // Check primary data if (graph.data[graphKey]) { graphResource = graph.data[graphKey]; // Check includes } else if ( graph.included[this._container.inflector.pluralize(model.modelName)] ) { graphResource = graph.included[this._container.inflector.pluralize(model.modelName)][ graphKey ]; } // If the model's in the graph, check if relationshipKey should be included return ( graphResource && graphResource.relationships && Object.prototype.hasOwnProperty.call( graphResource.relationships, dasherize(relationshipKey) ) ); } else { let relationshipPaths = this.getKeysForIncluded(); return relationshipPaths.includes(relationshipKey); } } /* This is needed for _relationshipIsIncludedForModel - see the note there for more background. If/when we can refactor this serializer, the logic in this method would probably be the basis for the new overall json/graph creation. */ _createRequestedIncludesGraph(primaryResource, secondaryResource = null) { let graph = { data: {}, }; if (this.isModel(primaryResource)) { let primaryResourceKey = this._graphKeyForModel(primaryResource); graph.data[primaryResourceKey] = {}; this._addPrimaryModelToRequestedIncludesGraph(graph, primaryResource); } else if (this.isCollection(primaryResource)) { primaryResource.models.forEach((model) => { let primaryResourceKey = this._graphKeyForModel(model); graph.data[primaryResourceKey] = {}; this._addPrimaryModelToRequestedIncludesGraph(graph, model); }); } // Hack :/ Need to think of a better palce to put this if // refactoring json:api serializer. this.request._includesGraph = graph; } _addPrimaryModelToRequestedIncludesGraph(graph, model) { if (this.hasQueryParamIncludes()) { let graphKey = this._graphKeyForModel(model); let queryParamIncludes = this.getQueryParamIncludes(); queryParamIncludes .split(",") .filter((item) => !!item.trim()) .forEach((includesPath) => { // includesPath is post.comments, for example graph.data[graphKey].relationships = graph.data[graphKey].relationships || {}; let relationshipKeys = includesPath.split(".").map(dasherize); let relationshipKey = relationshipKeys[0]; let graphRelationshipKey = relationshipKey; let normalizedRelationshipKey = camelize(relationshipKey); let hasAssociation = model.associationKeys.has( normalizedRelationshipKey ); assert( hasAssociation, `You tried to include "${relationshipKey}" with ${model} but no association named "${normalizedRelationshipKey}" is defined on the model.` ); let relationship = model[normalizedRelationshipKey]; let relationshipData; if (this.isModel(relationship)) { relationshipData = this._graphKeyForModel(relationship); } else if (this.isCollection(relationship)) { relationshipData = relationship.models.map(this._graphKeyForModel); } else { relationshipData = null; } graph.data[graphKey].relationships[ graphRelationshipKey ] = relationshipData; if (relationship) { this._addResourceToRequestedIncludesGraph( graph, relationship, relationshipKeys.slice(1) ); } }); } } _addResourceToRequestedIncludesGraph(graph, resource, relationshipNames) { graph.included = graph.included || {}; let models = this.isCollection(resource) ? resource.models : [resource]; models.forEach((model) => { let collectionName = this._container.inflector.pluralize(model.modelName); graph.included[collectionName] = graph.included[collectionName] || {}; this._addModelToRequestedIncludesGraph(graph, model, relationshipNames); }); } _addModelToRequestedIncludesGraph(graph, model, relationshipNames) { let collectionName = this._container.inflector.pluralize(model.modelName); let resourceKey = this._graphKeyForModel(model); graph.included[collectionName][resourceKey] = graph.included[collectionName][resourceKey] || {}; if (relationshipNames.length) { this._addResourceRelationshipsToRequestedIncludesGraph( graph, collectionName, resourceKey, model, relationshipNames ); } } /* Lot of the same logic here from _addPrimaryModelToRequestedIncludesGraph, could refactor & share */ _addResourceRelationshipsToRequestedIncludesGraph( graph, collectionName, resourceKey, model, relationshipNames ) { graph.included[collectionName][resourceKey].relationships = graph.included[collectionName][resourceKey].relationships || {}; let relationshipName = relationshipNames[0]; let relationship = model[camelize(relationshipName)]; let relationshipData; if (this.isModel(relationship)) { relationshipData = this._graphKeyForModel(relationship); } else if (this.isCollection(relationship)) { relationshipData = relationship.models.map(this._graphKeyForModel); } graph.included[collectionName][resourceKey].relationships[ relationshipName ] = relationshipData; if (relationship) { this._addResourceToRequestedIncludesGraph( graph, relationship, relationshipNames.slice(1) ); } } _graphKeyForModel(model) { return `${model.modelName}:${model.id}`; } getQueryParamIncludes() { return get(this, "request.queryParams.include"); } hasQueryParamIncludes() { return !!this.getQueryParamIncludes(); } /** Used to customize the `type` field of the document. By default, pluralizes and dasherizes the model's `modelName`. For example, the JSON:API document for a `blogPost` model would be: ```js { data: { id: 1, type: 'blog-posts' } } ``` @method typeKeyForModel @param {Model} model @return {String} @public */ typeKeyForModel(model) { return dasherize(this._container.inflector.pluralize(model.modelName)); } getCoalescedIds(request) { let ids = request.queryParams && request.queryParams["filter[id]"]; if (typeof ids === "string") { return ids.split(","); } return ids; } /** Allows for per-relationship inclusion of linkage data. Use this when `alwaysIncludeLinkageData` is not granular enough. ```js export default JSONAPISerializer.extend({ shouldIncludeLinkageData(relationshipKey, model) { if (relationshipKey === 'author' || relationshipKey === 'ghostWriter') { return true; } return false; } }); ``` @method shouldIncludeLinkageData @param {String} relationshipKey @param {Model} model @return {Boolean} @public */ shouldIncludeLinkageData(relationshipKey, model) { return false; } } JSONAPISerializer.prototype.alwaysIncludeLinkageData = false; export default JSONAPISerializer; miragejs-0.1.42/lib/serializers/rest-serializer.js000066400000000000000000000014471412317504700221750ustar00rootroot00000000000000import ActiveModelSerializer from "./active-model-serializer"; import { camelize } from "../utils/inflector"; export default ActiveModelSerializer.extend({ serializeIds: "always", keyForModel(type) { return camelize(type); }, keyForAttribute(attr) { return camelize(attr); }, keyForRelationship(type) { return camelize(this._container.inflector.pluralize(type)); }, keyForEmbeddedRelationship(attributeName) { return camelize(attributeName); }, keyForRelationshipIds(type) { return camelize(this._container.inflector.pluralize(type)); }, keyForForeignKey(relationshipName) { return camelize(this._container.inflector.singularize(relationshipName)); }, getCoalescedIds(request) { return request.queryParams && request.queryParams.ids; }, }); miragejs-0.1.42/lib/server.js000066400000000000000000001172041412317504700160220ustar00rootroot00000000000000/* eslint no-console: 0 */ import "@miragejs/pretender-node-polyfill/before"; import Pretender from "pretender"; import "@miragejs/pretender-node-polyfill/after"; import { camelize } from "./utils/inflector"; import isAssociation from "./utils/is-association"; import assert from "./assert"; import BelongsTo from "./orm/associations/belongs-to"; import Container from "./container"; import { singularize, pluralize } from "inflected"; import pick from "lodash.pick"; import assign from "lodash.assign"; import find from "lodash.find"; import isPlainObject from "lodash.isplainobject"; import isInteger from "lodash.isinteger"; const isPluralForModelCache = {}; /** * Creates a new Pretender instance. * * @method createPretender * @param {Server} server * @return {Object} A new Pretender instance. * @public */ function createPretender(server) { if (typeof window !== "undefined") { return new Pretender( function () { this.passthroughRequest = function (verb, path, request) { if (server.shouldLog()) { console.log( `Mirage: Passthrough request for ${verb.toUpperCase()} ${ request.url }` ); } }; this.handledRequest = function (verb, path, request) { if (server.shouldLog()) { console.groupCollapsed( `Mirage: [${request.status}] ${verb.toUpperCase()} ${request.url}` ); let { requestBody, responseText } = request; let loggedRequest, loggedResponse; try { loggedRequest = JSON.parse(requestBody); } catch (e) { loggedRequest = requestBody; } try { loggedResponse = JSON.parse(responseText); } catch (e) { loggedResponse = responseText; } console.groupCollapsed("Response"); console.log(loggedResponse); console.groupEnd(); console.groupCollapsed("Request (data)"); console.log(loggedRequest); console.groupEnd(); console.groupCollapsed("Request (raw)"); console.log(request); console.groupEnd(); console.groupEnd(); } }; let originalCheckPassthrough = this.checkPassthrough; this.checkPassthrough = function (request) { let shouldPassthrough = server.passthroughChecks.some( (passthroughCheck) => passthroughCheck(request) ); if (shouldPassthrough) { let url = request.url.includes("?") ? request.url.substr(0, request.url.indexOf("?")) : request.url; this[request.method.toLowerCase()](url, this.passthrough); } return originalCheckPassthrough.apply(this, arguments); }; this.unhandledRequest = function (verb, path) { path = decodeURI(path); assert( `Your app tried to ${verb} '${path}', but there was no route defined to handle this request. Define a route for this endpoint in your routes() config. Did you forget to define a namespace?` ); }; }, { trackRequests: server.shouldTrackRequests() } ); } } const defaultRouteOptions = { coalesce: false, timing: undefined, }; const defaultInflector = { singularize, pluralize }; /** @hide */ const defaultPassthroughs = [ "http://localhost:0/chromecheckurl", // mobile chrome "http://localhost:30820/socket.io", // electron (request) => { return /.+\.hot-update.json$/.test(request.url); }, ]; /** @hide */ export { defaultPassthroughs }; /** * Determine if the object contains a valid option. * * @method isOption * @param {Object} option An object with one option value pair. * @return {Boolean} True if option is a valid option, false otherwise. * @private */ function isOption(option) { if (!option || typeof option !== "object") { return false; } let allOptions = Object.keys(defaultRouteOptions); let optionKeys = Object.keys(option); for (let i = 0; i < optionKeys.length; i++) { let key = optionKeys[i]; if (allOptions.indexOf(key) > -1) { return true; } } return false; } /** * Extract arguments for a route. * * @method extractRouteArguments * @param {Array} args Of the form [options], [object, code], [function, code] * [shorthand, options], [shorthand, code, options] * @return {Array} [handler (i.e. the function, object or shorthand), code, * options]. * @private */ function extractRouteArguments(args) { let [lastArg] = args.splice(-1); if (isOption(lastArg)) { lastArg = assign({}, defaultRouteOptions, lastArg); } else { args.push(lastArg); lastArg = defaultRouteOptions; } let t = 2 - args.length; while (t-- > 0) { args.push(undefined); } args.push(lastArg); return args; } /** * Creates a Server * @param {Object} options Server's configuration object * @param {String} options.urlPrefix The base URL for the routes. Example: `http://miragejs.com`. * @param {String} options.namespace The default namespace for the `Server`. Example: `/api/v1`. * @param {Number} options.timing Default latency for the routes to respond to a request. * @param {String} options.environment Defines the environment of the `Server`. * @param {Boolean} options.trackRequests Pretender `trackRequests`. * @param {Boolean} options.useDefaultPassthroughs True to use mirage provided passthroughs * @param {Boolean} options.logging Set to true or false to explicitly specify logging behavior. * @param {Function} options.seeds Called on the seed phase. Should be used to seed the database. * @param {Function} options.scenarios Alias for seeds. * @param {Function} options.routes Should be used to define server routes. * @param {Function} options.baseConfig Alias for routes. * @param {Object} options.inflector Default inflector (used for pluralization and singularization). * @param {Object} options.identityManagers Database identity managers. * @param {Object} options.models Server models * @param {Object} options.serializers Server serializers * @param {Object} options.factories Server factories * @param {Object} options.pretender Pretender instance */ export function createServer(options) { return new Server(options); } /** The Mirage server. Note that `this` within your `routes` function refers to the server instance, which is the same instance that `server` refers to in your tests. @class Server @public */ export default class Server { /** * Creates a Server * @param {Object} options Server's configuration object * @param {String} options.urlPrefix The base URL for the routes. Example: `http://miragejs.com`. * @param {String} options.namespace The default namespace for the `Server`. Example: `/api/v1`. * @param {Number} options.timing Default latency for the routes to respond to a request. * @param {String} options.environment Defines the environment of the `Server`. * @param {Boolean} options.trackRequests Pretender `trackRequests`. * @param {Boolean} options.useDefaultPassthroughs True to use mirage provided passthroughs * @param {Boolean} options.logging Set to true or false to explicitly specify logging behavior. * @param {Function} options.seeds Called on the seed phase. Should be used to seed the database. * @param {Function} options.scenarios Alias for seeds. * @param {Function} options.routes Should be used to define server routes. * @param {Function} options.baseConfig Alias for routes. * @param {Object} options.inflector Default inflector (used for pluralization and singularization). * @param {Object} options.identityManagers Database identity managers. * @param {Object} options.models Server models * @param {Object} options.serializers Server serializers * @param {Object} options.factories Server factories * @param {Object} options.pretender Pretender instance */ constructor(options = {}) { this._container = new Container(); this.config(options); /** Returns the Mirage Db instance. @property db @return Db */ this.db = this.db || undefined; /** Returns the Mirage Schema (ORM) instance. @property schema @return Schema */ this.schema = this.schema || undefined; } config(config = {}) { this.passthroughChecks = this.passthroughChecks || []; let didOverrideConfig = config.environment && this.environment && this.environment !== config.environment; assert( !didOverrideConfig, "You cannot modify Mirage's environment once the server is created" ); this.environment = config.environment || this.environment || "development"; if (config.routes) { assert( !config.baseConfig, "The routes option is an alias for the baseConfig option. You can't pass both options into your server definition." ); config.baseConfig = config.routes; } if (config.seeds) { assert( !config.scenarios, "The seeds option is an alias for the scenarios.default option. You can't pass both options into your server definition." ); config.scenarios = { default: config.seeds }; } this._config = config; /** Set the base namespace used for all routes defined with `get`, `post`, `put` or `del`. For example, ```js createServer({ routes() { this.namespace = '/api'; // this route will handle the URL '/api/contacts' this.get('/contacts', 'contacts'); } }) ``` Note that only routes defined after `this.namespace` are affected. This is useful if you have a few one-off routes that you don't want under your namespace: ```js createServer({ routes() { // this route handles /auth this.get('/auth', function() { ...}); this.namespace = '/api'; // this route will handle the URL '/api/contacts' this.get('/contacts', 'contacts'); }; }) ``` If your app is loaded from the filesystem vs. a server (e.g. via Cordova or Electron vs. `localhost` or `https://yourhost.com/`), you will need to explicitly define a namespace. Likely values are `/` (if requests are made with relative paths) or `https://yourhost.com/api/...` (if requests are made to a defined server). For a sample implementation leveraging a configured API host & namespace, check out [this issue comment](https://github.com/miragejs/ember-cli-mirage/issues/497#issuecomment-183458721). @property namespace @type String @public */ this.namespace = this.namespace || config.namespace || ""; /** Mirage needs know the singular and plural versions of certain words for some of its APIs to work. For example, whenever you define a model ```js createServer({ models: { post: Model } }) ``` Mirage will pluralize the word "post" and use it to create a `db.posts` database collection. To accomplish this, Mirage uses an object called an Inflector. An Inflector is an object with two methods, `singularize` and `pluralize`, that Mirage will call whenever it needs to inflect a word. Mirage has a default inflector, so if you write ```js createServer() ``` you'll be using the node [inflected](https://github.com/martinandert/inflected#readme) package. This can be customized if you have irregular words or need to change the defaults. You can wead more in [the guide on customizing inflections](/docs/advanced/customizing-inflections). You typically should be able to make your customizations using the provided inflector. It's good to match any custom inflections your backend uses, as this will keep your Mirage code more consistent and simpler. You can also override the inflector completely and provide your own `pluralize` and `singularize` methods: ```js createServer({ inflector: { pluralize(word) { // your logic }, singularize(word) { // your logic } } }) ``` */ this.inflector = config.inflector || defaultInflector; this._container.register("inflector", this.inflector); /** Sets a string to prefix all route handler URLs with. Useful if your app makes API requests to a different port. ```js createServer({ routes() { this.urlPrefix = 'http://localhost:8080' } }) ``` */ this.urlPrefix = this.urlPrefix || config.urlPrefix || ""; /** Set the number of milliseconds for the the Server's response time. By default there's a 400ms delay during development, and 0 delay in testing (so your tests run fast). ```js createServer({ routes() { this.timing = 400; // default } }) ``` To set the timing for individual routes, see the `timing` option for route handlers. @property timing @type Number @public */ this.timing = this.timing || config.timing || 400; /** Set to `true` or `false` to explicitly specify logging behavior. By default, server responses are logged in non-testing environments. Logging is disabled by default in testing, so as not to clutter CI test runner output. For example, to enable logging in tests, write the following: ```js test('I can view all users', function() { server.logging = true; server.create('user'); visit('/users'); // ... }); ``` You can also write a custom log message using the [Pretender server's `handledRequest` hook](https://github.com/pretenderjs/pretender#handled-requests). (You can access the pretender server from your Mirage server via `server.pretender`.) To override, ```js createServer({ routes() { this.pretender.handledRequest = function(verb, path, request) { let { responseText } = request; // log request and response data } } }) ``` @property logging @return {Boolean} @public */ this.logging = this.logging !== undefined ? this.logging : undefined; this.testConfig = this.testConfig || undefined; this.trackRequests = config.trackRequests; this._defineRouteHandlerHelpers(); if (this.db) { this.db.registerIdentityManagers(config.identityManagers); } else { this.db = this._container.create( "Db", undefined, config.identityManagers ); } if (this.schema) { this.schema.registerModels(config.models); this.serializerOrRegistry.registerSerializers(config.serializers || {}); } else { this.schema = this._container.create("Schema", this.db, config.models); this.serializerOrRegistry = this._container.create( "SerializerRegistry", this.schema, config.serializers ); } let hasFactories = this._hasModulesOfType(config, "factories"); let hasDefaultScenario = config.scenarios && Object.prototype.hasOwnProperty.call(config.scenarios, "default"); let didOverridePretenderConfig = config.trackRequests !== undefined && this.pretender; assert( !didOverridePretenderConfig, "You cannot modify Pretender's request tracking once the server is created" ); /** Mirage uses [pretender.js](https://github.com/trek/pretender) as its xhttp interceptor. In your Mirage config, `this.pretender` refers to the actual Pretender instance, so any config options that work there will work here as well. ```js createServer({ routes() { this.pretender.handledRequest = (verb, path, request) => { console.log(`Your server responded to ${path}`); } } }) ``` Refer to [Pretender's docs](https://github.com/pretenderjs/pretender) if you want to change any options on your Pretender instance. @property pretender @return {Object} The Pretender instance @public */ this.pretender = this.pretender || config.pretender || createPretender(this); if (config.baseConfig) { this.loadConfig(config.baseConfig); } if (this.isTest()) { if (config.testConfig) { this.loadConfig(config.testConfig); } if (typeof window !== "undefined") { window.server = this; // TODO: Better way to inject server into test env } } if (this.isTest() && hasFactories) { this.loadFactories(config.factories); } else if (!this.isTest() && hasDefaultScenario) { this.loadFactories(config.factories); config.scenarios.default(this); } else { this.loadFixtures(); } let useDefaultPassthroughs = typeof config.useDefaultPassthroughs !== "undefined" ? config.useDefaultPassthroughs : true; if (useDefaultPassthroughs) { this._configureDefaultPassthroughs(); } } /** * Determines if the current environment is the testing environment. * * @method isTest * @return {Boolean} True if the environment is 'test', false otherwise. * @public * @hide */ isTest() { return this.environment === "test"; } /** Determines if the server should log. @method shouldLog @return The value of this.logging if defined, or false if in the testing environment, true otherwise. @public @hide */ shouldLog() { return typeof this.logging !== "undefined" ? this.logging : !this.isTest(); } /** * Determines if the server should track requests. * * @method shouldTrackRequests * @return The value of this.trackRequests if defined, false otherwise. * @public * @hide */ shouldTrackRequests() { return Boolean(this.trackRequests); } /** * Load the configuration given, setting timing to 0 if in the test * environment. * * @method loadConfig * @param {Object} config The configuration to load. * @public * @hide */ loadConfig(config) { config.call(this); this.timing = this.isTest() ? 0 : this.timing || 0; } /** By default, if your app makes a request that is not defined in your server config, Mirage will throw an error. You can use `passthrough` to whitelist requests, and allow them to pass through your Mirage server to the actual network layer. Note: Put all passthrough config at the bottom of your routes, to give your route handlers precedence. To ignore paths on your current host (as well as configured `namespace`), use a leading `/`: ```js this.passthrough('/addresses'); ``` You can also pass a list of paths, or call `passthrough` multiple times: ```js this.passthrough('/addresses', '/contacts'); this.passthrough('/something'); this.passthrough('/else'); ``` These lines will allow all HTTP verbs to pass through. If you want only certain verbs to pass through, pass an array as the last argument with the specified verbs: ```js this.passthrough('/addresses', ['post']); this.passthrough('/contacts', '/photos', ['get']); ``` You can pass a function to `passthrough` to do a runtime check on whether or not the request should be handled by Mirage. If the function returns `true` Mirage will not handle the request and let it pass through. ```js this.passthrough(request => { return request.queryParams.skipMirage; }); ``` If you want all requests on the current domain to pass through, simply invoke the method with no arguments: ```js this.passthrough(); ``` Note again that the current namespace (i.e. any `namespace` property defined above this call) will be applied. You can also allow other-origin hosts to passthrough. If you use a fully-qualified domain name, the `namespace` property will be ignored. Use two * wildcards to match all requests under a path: ```js this.passthrough('http://api.foo.bar/**'); this.passthrough('http://api.twitter.com/v1/cards/**'); ``` In versions of Pretender prior to 0.12, `passthrough` only worked with jQuery >= 2.x. As long as you're on Pretender@0.12 or higher, you should be all set. @method passthrough @param {String} [...paths] Any number of paths to whitelist @param {Array} options Unused @public */ passthrough(...paths) { // this only works in browser-like environments for now. in node users will have to configure // their own interceptor if they are using one. if (typeof window !== "undefined") { let verbs = ["get", "post", "put", "delete", "patch", "options", "head"]; let lastArg = paths[paths.length - 1]; if (paths.length === 0) { paths = ["/**", "/"]; } else if (Array.isArray(lastArg)) { verbs = paths.pop(); } paths.forEach((path) => { if (typeof path === "function") { this.passthroughChecks.push(path); } else { verbs.forEach((verb) => { let fullPath = this._getFullPath(path); this.pretender[verb](fullPath, this.pretender.passthrough); }); } }); } } /** By default, `fixtures` will be loaded during testing if you don't have factories defined, and during development if you don't have `seeds` defined. You can use `loadFixtures()` to also load fixture files in either of these environments, in addition to using factories to seed your database. `server.loadFixtures()` loads all the files, and `server.loadFixtures(file1, file2...)` loads selective fixture files. For example, in a test you may want to start out with all your fixture data loaded: ```js test('I can view the photos', function() { server.loadFixtures(); server.createList('photo', 10); visit('/'); andThen(() => { equal( find('img').length, 10 ); }); }); ``` or in development, you may want to load a few reference fixture files, and use factories to define the rest of your data: ```js createServer({ ..., seeds(server) { server.loadFixtures('countries', 'states'); let author = server.create('author'); server.createList('post', 10, {author_id: author.id}); } }) ``` @method loadFixtures @param {String} [...args] The name of the fixture to load. @public */ loadFixtures(...args) { let { fixtures } = this._config; if (args.length) { let camelizedArgs = args.map(camelize); let missingKeys = camelizedArgs.filter((key) => !fixtures[key]); if (missingKeys.length) { throw new Error(`Fixtures not found: ${missingKeys.join(", ")}`); } fixtures = pick(fixtures, ...camelizedArgs); } this.db.loadData(fixtures); } /* Factory methods */ /** * Load factories into Mirage's database. * * @method loadFactories * @param {Object} factoryMap * @public * @hide */ loadFactories(factoryMap = {}) { // Store a reference to the factories let currentFactoryMap = this._factoryMap || {}; this._factoryMap = assign(currentFactoryMap, factoryMap); // Create a collection for each factory Object.keys(factoryMap).forEach((type) => { let collectionName = this.schema.toCollectionName(type); this.db.createCollection(collectionName); }); } /** * Get the factory for a given type. * * @method factoryFor * @param {String} type * @private * @hide */ factoryFor(type) { let camelizedType = camelize(type); if (this._factoryMap && this._factoryMap[camelizedType]) { return this._factoryMap[camelizedType]; } } build(type, ...traitsAndOverrides) { let traits = traitsAndOverrides.filter( (arg) => arg && typeof arg === "string" ); let overrides = find(traitsAndOverrides, (arg) => isPlainObject(arg)); let camelizedType = camelize(type); // Store sequence for factory type as instance variable this.factorySequences = this.factorySequences || {}; this.factorySequences[camelizedType] = this.factorySequences[camelizedType] + 1 || 0; let OriginalFactory = this.factoryFor(type); if (OriginalFactory) { OriginalFactory = OriginalFactory.extend({}); let attrs = OriginalFactory.attrs || {}; this._validateTraits(traits, OriginalFactory, type); let mergedExtensions = this._mergeExtensions(attrs, traits, overrides); this._mapAssociationsFromAttributes(type, attrs, overrides); this._mapAssociationsFromAttributes(type, mergedExtensions); let Factory = OriginalFactory.extend(mergedExtensions); let factory = new Factory(); let sequence = this.factorySequences[camelizedType]; return factory.build(sequence); } else { return overrides; } } buildList(type, amount, ...traitsAndOverrides) { assert( isInteger(amount), `second argument has to be an integer, you passed: ${typeof amount}` ); let list = []; const buildArgs = [type, ...traitsAndOverrides]; for (let i = 0; i < amount; i++) { list.push(this.build.apply(this, buildArgs)); } return list; } /** Generates a single model of type *type*, inserts it into the database (giving it an id), and returns the data that was added. ```js test("I can view a contact's details", function() { let contact = server.create('contact'); visit('/contacts/' + contact.id); andThen(() => { equal( find('h1').text(), 'The contact is Link'); }); }); ``` You can override the attributes from the factory definition with a hash passed in as the second parameter. For example, if we had this factory ```js export default Factory.extend({ name: 'Link' }); ``` we could override the name like this: ```js test("I can view the contacts", function() { server.create('contact', {name: 'Zelda'}); visit('/'); andThen(() => { equal( find('p').text(), 'Zelda' ); }); }); ``` @method create @param type the singularized type of the model @param traitsAndOverrides @public */ create(type, ...options) { assert( this._modelOrFactoryExistsForType(type), `You called server.create('${type}') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name.` ); // When there is a Model defined, we should return an instance // of it instead of returning the bare attributes. let traits = options.filter((arg) => arg && typeof arg === "string"); let overrides = find(options, (arg) => isPlainObject(arg)); let collectionFromCreateList = find( options, (arg) => arg && Array.isArray(arg) ); let attrs = this.build(type, ...traits, overrides); let modelOrRecord; if (this.schema && this.schema[this.schema.toCollectionName(type)]) { let modelClass = this.schema[this.schema.toCollectionName(type)]; modelOrRecord = modelClass.create(attrs); } else { let collection, collectionName; if (collectionFromCreateList) { collection = collectionFromCreateList; } else { collectionName = this.schema ? this.schema.toInternalCollectionName(type) : `_${this.inflector.pluralize(type)}`; collection = this.db[collectionName]; } assert( collection, `You called server.create('${type}') but no model or factory was found.` ); modelOrRecord = collection.insert(attrs); } let OriginalFactory = this.factoryFor(type); if (OriginalFactory) { OriginalFactory.extractAfterCreateCallbacks({ traits }).forEach( (afterCreate) => { afterCreate(modelOrRecord, this); } ); } return modelOrRecord; } /** Creates *amount* models of type *type*, optionally overriding the attributes from the factory with *attrs*. Returns the array of records that were added to the database. Here's an example from a test: ```js test("I can view the contacts", function() { server.createList('contact', 5); let youngContacts = server.createList('contact', 5, {age: 15}); visit('/'); andThen(function() { equal(currentRouteName(), 'index'); equal( find('p').length, 10 ); }); }); ``` And one from setting up your development database: ```js createServer({ seeds(server) { let contact = server.create('contact') server.createList('address', 5, { contact }) } }) ``` @method createList @param type @param amount @param traitsAndOverrides @public */ createList(type, amount, ...traitsAndOverrides) { assert( this._modelOrFactoryExistsForType(type), `You called server.createList('${type}') but no model or factory was found. Make sure you're passing in the singularized version of the model or factory name.` ); assert( isInteger(amount), `second argument has to be an integer, you passed: ${typeof amount}` ); let list = []; let collectionName = this.schema ? this.schema.toInternalCollectionName(type) : `_${this.inflector.pluralize(type)}`; let collection = this.db[collectionName]; const createArguments = [type, ...traitsAndOverrides, collection]; for (let i = 0; i < amount; i++) { list.push(this.create.apply(this, createArguments)); } return list; } /** Shutdown the server and stop intercepting network requests. @method shutdown @public */ shutdown() { if (typeof window !== "undefined") { this.pretender.shutdown(); } if (typeof window !== "undefined" && this.environment === "test") { window.server = undefined; } } resource(resourceName, { only, except, path } = {}) { resourceName = this.inflector.pluralize(resourceName); path = path || `/${resourceName}`; only = only || []; except = except || []; if (only.length > 0 && except.length > 0) { throw "cannot use both :only and :except options"; } let actionsMethodsAndsPathsMappings = { index: { methods: ["get"], path: `${path}` }, show: { methods: ["get"], path: `${path}/:id` }, create: { methods: ["post"], path: `${path}` }, update: { methods: ["put", "patch"], path: `${path}/:id` }, delete: { methods: ["del"], path: `${path}/:id` }, }; let allActions = Object.keys(actionsMethodsAndsPathsMappings); let actions = (only.length > 0 && only) || (except.length > 0 && allActions.filter((action) => except.indexOf(action) === -1)) || allActions; actions.forEach((action) => { let methodsWithPath = actionsMethodsAndsPathsMappings[action]; methodsWithPath.methods.forEach((method) => { return path === resourceName ? this[method](methodsWithPath.path) : this[method](methodsWithPath.path, resourceName); }); }); } /** * * @private * @hide */ _defineRouteHandlerHelpers() { [ ["get"], ["post"], ["put"], ["delete", "del"], ["patch"], ["head"], ["options"], ].forEach(([verb, alias]) => { this[verb] = (path, ...args) => { let [rawHandler, customizedCode, options] = extractRouteArguments(args); return this._registerRouteHandler( verb, path, rawHandler, customizedCode, options ); }; if (alias) { this[alias] = this[verb]; } }); } _serialize(body) { if (typeof body === "string") { return body; } else { return JSON.stringify(body); } } _registerRouteHandler(verb, path, rawHandler, customizedCode, options) { let routeHandler = this._container.create("RouteHandler", { schema: this.schema, verb, rawHandler, customizedCode, options, path, serializerOrRegistry: this.serializerOrRegistry, }); let fullPath = this._getFullPath(path); let timing = options.timing !== undefined ? options.timing : () => this.timing; if (this.pretender) { return this.pretender[verb]( fullPath, (request) => { return routeHandler.handle(request).then((mirageResponse) => { let [code, headers, response] = mirageResponse; return [code, headers, this._serialize(response)]; }); }, timing ); } } /** * * @private * @hide */ _hasModulesOfType(modules, type) { let modulesOfType = modules[type]; return modulesOfType ? Object.keys(modulesOfType).length > 0 : false; } /** * Builds a full path for Pretender to monitor based on the `path` and * configured options (`urlPrefix` and `namespace`). * * @private * @hide */ _getFullPath(path) { path = path[0] === "/" ? path.slice(1) : path; let fullPath = ""; let urlPrefix = this.urlPrefix ? this.urlPrefix.trim() : ""; let namespace = ""; // if there is a urlPrefix and a namespace if (this.urlPrefix && this.namespace) { if ( this.namespace[0] === "/" && this.namespace[this.namespace.length - 1] === "/" ) { namespace = this.namespace .substring(0, this.namespace.length - 1) .substring(1); } if ( this.namespace[0] === "/" && this.namespace[this.namespace.length - 1] !== "/" ) { namespace = this.namespace.substring(1); } if ( this.namespace[0] !== "/" && this.namespace[this.namespace.length - 1] === "/" ) { namespace = this.namespace.substring(0, this.namespace.length - 1); } if ( this.namespace[0] !== "/" && this.namespace[this.namespace.length - 1] !== "/" ) { namespace = this.namespace; } } // if there is a namespace and no urlPrefix if (this.namespace && !this.urlPrefix) { if ( this.namespace[0] === "/" && this.namespace[this.namespace.length - 1] === "/" ) { namespace = this.namespace.substring(0, this.namespace.length - 1); } if ( this.namespace[0] === "/" && this.namespace[this.namespace.length - 1] !== "/" ) { namespace = this.namespace; } if ( this.namespace[0] !== "/" && this.namespace[this.namespace.length - 1] === "/" ) { let namespaceSub = this.namespace.substring( 0, this.namespace.length - 1 ); namespace = `/${namespaceSub}`; } if ( this.namespace[0] !== "/" && this.namespace[this.namespace.length - 1] !== "/" ) { namespace = `/${this.namespace}`; } } // if no namespace if (!this.namespace) { namespace = ""; } // check to see if path is a FQDN. if so, ignore any urlPrefix/namespace that was set if (/^https?:\/\//.test(path)) { fullPath += path; } else { // otherwise, if there is a urlPrefix, use that as the beginning of the path if (urlPrefix.length) { fullPath += urlPrefix[urlPrefix.length - 1] === "/" ? urlPrefix : `${urlPrefix}/`; } // add the namespace to the path fullPath += namespace; // add a trailing slash to the path if it doesn't already contain one if (fullPath[fullPath.length - 1] !== "/") { fullPath += "/"; } // finally add the configured path fullPath += path; // if we're making a same-origin request, ensure a / is prepended and // dedup any double slashes if (!/^https?:\/\//.test(fullPath)) { fullPath = `/${fullPath}`; fullPath = fullPath.replace(/\/+/g, "/"); } } return fullPath; } /** * * @private * @hide */ _configureDefaultPassthroughs() { defaultPassthroughs.forEach((passthroughUrl) => { this.passthrough(passthroughUrl); }); } /** * * @private * @hide */ _typeIsPluralForModel(typeOrCollectionName) { if (typeof isPluralForModelCache[typeOrCollectionName] !== "boolean") { let modelOrFactoryExists = this._modelOrFactoryExistsForTypeOrCollectionName( typeOrCollectionName ); let isPlural = typeOrCollectionName === this.inflector.pluralize(typeOrCollectionName); let isUncountable = this.inflector.singularize(typeOrCollectionName) === this.inflector.pluralize(typeOrCollectionName); const isPluralForModel = isPlural && !isUncountable && modelOrFactoryExists; isPluralForModelCache[typeOrCollectionName] = isPluralForModel; } return isPluralForModelCache[typeOrCollectionName]; } /** * * @private * @hide */ _modelOrFactoryExistsForType(type) { let modelExists = this.schema && this.schema.modelFor(camelize(type)); let dbCollectionExists = this.db[ this.schema.toInternalCollectionName(type) ]; return ( (modelExists || dbCollectionExists) && !this._typeIsPluralForModel(type) ); } /** * * @private * @hide */ _modelOrFactoryExistsForTypeOrCollectionName(typeOrCollectionName) { let modelExists = this.schema && this.schema.modelFor(camelize(typeOrCollectionName)); let dbCollectionExists = this.db[ this.schema.toInternalCollectionName(typeOrCollectionName) ]; return modelExists || dbCollectionExists; } /** * * @private * @hide */ _validateTraits(traits, factory, type) { traits.forEach((traitName) => { if (!factory.isTrait(traitName)) { throw new Error( `'${traitName}' trait is not registered in '${type}' factory` ); } }); } /** * * @private * @hide */ _mergeExtensions(attrs, traits, overrides) { let allExtensions = traits.map((traitName) => { return attrs[traitName].extension; }); allExtensions.push(overrides || {}); return allExtensions.reduce((accum, extension) => { return assign(accum, extension); }, {}); } /** * * @private * @hide */ _mapAssociationsFromAttributes(modelName, attributes, overrides = {}) { Object.keys(attributes || {}) .filter((attr) => { return isAssociation(attributes[attr]); }) .forEach((attr) => { let modelClass = this.schema.modelClassFor(modelName); let association = modelClass.associationFor(attr); assert( association && association instanceof BelongsTo, `You're using the \`association\` factory helper on the '${attr}' attribute of your ${modelName} factory, but that attribute is not a \`belongsTo\` association.` ); let isSelfReferentialBelongsTo = association && association instanceof BelongsTo && association.modelName === modelName; assert( !isSelfReferentialBelongsTo, `You're using the association() helper on your ${modelName} factory for ${attr}, which is a belongsTo self-referential relationship. You can't do this as it will lead to infinite recursion. You can move the helper inside of a trait and use it selectively.` ); let isPolymorphic = association && association.opts && association.opts.polymorphic; assert( !isPolymorphic, `You're using the association() helper on your ${modelName} factory for ${attr}, which is a polymorphic relationship. This is not currently supported.` ); let factoryAssociation = attributes[attr]; let foreignKey = `${camelize(attr)}Id`; if (!overrides[attr]) { attributes[foreignKey] = this.create( association.modelName, ...factoryAssociation.traitsAndOverrides ).id; } delete attributes[attr]; }); } } miragejs-0.1.42/lib/trait.js000066400000000000000000000002261412317504700156320ustar00rootroot00000000000000let trait = function (extension) { let __isTrait__ = true; return { extension, __isTrait__, }; }; /** @hide */ export default trait; miragejs-0.1.42/lib/utils/000077500000000000000000000000001412317504700153115ustar00rootroot00000000000000miragejs-0.1.42/lib/utils/extend.js000066400000000000000000000013241412317504700171360ustar00rootroot00000000000000import has from "lodash.has"; /** @hide */ export default function extend(protoProps, staticProps) { class Child extends this { constructor(...args) { super(...args); // The constructor function for the new subclass is optionally defined by you // in your `extend` definition if (protoProps && has(protoProps, "constructor")) { protoProps.constructor.call(this, ...args); } } } // Add static properties to the constructor function, if supplied. Object.assign(Child, this, staticProps); // Add prototype properties (instance properties) to the subclass, // if supplied. if (protoProps) { Object.assign(Child.prototype, protoProps); } return Child; } miragejs-0.1.42/lib/utils/inflector.js000066400000000000000000000031711412317504700176360ustar00rootroot00000000000000import { underscore as _underscore, capitalize as _capitalize, camelize as _camelize, dasherize as _dasherize, } from "inflected"; import lowerFirst from "lodash.lowerfirst"; const camelizeCache = {}; const dasherizeCache = {}; const underscoreCache = {}; const capitalizeCache = {}; /** * @param {String} word * @hide */ export function camelize(word) { if (typeof camelizeCache[word] !== "string") { let camelizedWord = _camelize(underscore(word), false); /* The `ember-inflector` package's version of camelize lower-cases the first word after a slash, e.g. camelize('my-things/nice-watch'); // 'myThings/niceWatch' The `inflected` package doesn't, so we make that change here to not break existing functionality. (This affects the name of the schema collections.) */ const camelized = camelizedWord.split("/").map(lowerFirst).join("/"); camelizeCache[word] = camelized; } return camelizeCache[word]; } /** * @param {String} word * @hide */ export function dasherize(word) { if (typeof dasherizeCache[word] !== "string") { const dasherized = _dasherize(underscore(word)); dasherizeCache[word] = dasherized; } return dasherizeCache[word]; } export function underscore(word) { if (typeof underscoreCache[word] !== "string") { const underscored = _underscore(word); underscoreCache[word] = underscored; } return underscoreCache[word]; } export function capitalize(word) { if (typeof capitalizeCache[word] !== "string") { const capitalized = _capitalize(word); capitalizeCache[word] = capitalized; } return capitalizeCache[word]; } miragejs-0.1.42/lib/utils/is-association.js000066400000000000000000000002541412317504700205750ustar00rootroot00000000000000import isPlainObject from "lodash.isplainobject"; /** @hide */ export default function (object) { return isPlainObject(object) && object.__isAssociation__ === true; } miragejs-0.1.42/lib/utils/reference-sort.js000066400000000000000000000021221412317504700205670ustar00rootroot00000000000000// jscs:disable disallowVar, requireArrayDestructuring import uniq from "lodash.uniq"; import flatten from "lodash.flatten"; /** @hide */ export default function (edges) { let nodes = uniq(flatten(edges)); let cursor = nodes.length; let sorted = new Array(cursor); let visited = {}; let i = cursor; let visit = function (node, i, predecessors) { if (predecessors.indexOf(node) >= 0) { throw new Error( `Cyclic dependency in properties ${JSON.stringify(predecessors)}` ); } if (visited[i]) { return; } else { visited[i] = true; } let outgoing = edges.filter(function (edge) { return edge && edge[0] === node; }); i = outgoing.length; if (i) { let preds = predecessors.concat(node); do { let pair = outgoing[--i]; let child = pair[1]; if (child) { visit(child, nodes.indexOf(child), preds); } } while (i); } sorted[--cursor] = node; }; while (i--) { if (!visited[i]) { visit(nodes[i], i, []); } } return sorted.reverse(); } miragejs-0.1.42/lib/utils/uuid.js000066400000000000000000000004041412317504700166130ustar00rootroot00000000000000/** UUID generator @hide */ export default function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { let r = (Math.random() * 16) | 0; let v = c === "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); } miragejs-0.1.42/package.json000066400000000000000000000055331412317504700156770ustar00rootroot00000000000000{ "name": "miragejs", "version": "0.1.42", "description": "A client-side server to help you build, test and demo your JavaScript app", "main": "dist/mirage-cjs.js", "module": "dist/mirage-esm.js", "sideEffects": false, "types": "types/index.d.ts", "keywords": [ "pretender", "prototype", "server", "testing" ], "repository": { "type": "git", "url": "https://github.com/miragejs/miragejs.git" }, "license": "MIT", "author": "Sam Selikoff", "homepage": "https://github.com/miragejs/miragejs", "bugs": { "url": "https://github.com/miragejs/miragejs/issues" }, "scripts": { "lint": "eslint .", "lint:ts": "dtslint types --expectOnly", "prettier:check": "prettier --list-different '**/*.js'", "prettier:update": "prettier --write .", "dev": "rollup -c -w", "build": "rollup -c", "prepublishOnly": "yarn run build", "test:run": "jest", "test": "run-s build test:run", "ci": "run-s lint lint:ts prettier:check test" }, "dependencies": { "@miragejs/pretender-node-polyfill": "^0.1.0", "inflected": "^2.0.4", "lodash.assign": "^4.2.0", "lodash.camelcase": "^4.3.0", "lodash.clonedeep": "^4.5.0", "lodash.compact": "^3.0.1", "lodash.find": "^4.6.0", "lodash.flatten": "^4.4.0", "lodash.forin": "^4.4.0", "lodash.get": "^4.4.2", "lodash.has": "^4.5.2", "lodash.invokemap": "^4.6.0", "lodash.isempty": "^4.4.0", "lodash.isequal": "^4.5.0", "lodash.isfunction": "^3.0.9", "lodash.isinteger": "^4.0.4", "lodash.isplainobject": "^4.0.6", "lodash.lowerfirst": "^4.3.1", "lodash.map": "^4.6.0", "lodash.mapvalues": "^4.6.0", "lodash.pick": "^4.4.0", "lodash.snakecase": "^4.1.1", "lodash.uniq": "^4.5.0", "lodash.uniqby": "^4.7.0", "lodash.values": "^4.3.0", "pretender": "^3.4.7" }, "devDependencies": { "@babel/core": "^7.5.5", "@babel/preset-env": "^7.9.0", "babel-eslint": "^10.0.2", "babel-jest": "^26.0.1", "core-js": "^3", "dtslint": "^4.0.2", "eslint": "^7.4.0", "eslint-config-prettier": "^6.3.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-node": "^0.3.2", "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^24.0.2", "eslint-plugin-node": "^11.0.0", "eslint-plugin-prettier": "^3.1.0", "jest": "^26.0.1", "jest-extended": "^0.11.2", "npm-run-all": "^4.1.5", "prettier": "^2.0.2", "rollup": "^2.3.2", "rollup-plugin-alias": "^2.0.1", "rollup-plugin-async": "^1.2.0", "rollup-plugin-babel": "^4.3.3", "rollup-plugin-commonjs": "^10.0.1", "rollup-plugin-multi-entry": "^2.1.0", "rollup-plugin-node-resolve": "^5.2.0", "tslint": "^6.1.1", "tslint-config-prettier": "^1.18.0", "typescript": "^4.0.3" }, "engines": { "node": "6.* || 8.* || >= 10.*" } } miragejs-0.1.42/prettier.config.js000066400000000000000000000000251412317504700170400ustar00rootroot00000000000000module.exports = {}; miragejs-0.1.42/rollup.config.js000066400000000000000000000051121412317504700165210ustar00rootroot00000000000000import path from "path"; import babel from "rollup-plugin-babel"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import alias from "rollup-plugin-alias"; let aliases = { entries: [ { find: /@lib(.*)/, replacement: path.resolve(process.cwd(), "./lib$1.js"), }, ], }; function isExternal(id) { /* Here, `id` is "./db", as in import db from './db' */ let isRelativeInternalModulePath = id.startsWith("."); /* Here, `id` is something like "/Users/samselikoff/Projects/oss/miragejs/miragejs/lib/identity-manager.js" I'm not sure how this happens, but it's referencing an internal module, so it shouldn't be treated as external. */ let isAbsoluteInternalModulePath = id.includes( path.join(process.cwd(), "lib") ); /* Here, `id` is something like '@lib/assert', which is not a path but does reference an internal module. So it shouldn't be treated as external. */ let isAlias = Boolean( aliases.entries.find((entry) => { if (entry.find instanceof RegExp) { return entry.find.test(id); } else if (typeof entry.find === "string") { return id.startsWith(entry.find); } }) ); return ( !isRelativeInternalModulePath && !isAbsoluteInternalModulePath && !isAlias ); } let esm = { input: "lib/index.js", output: { file: `dist/mirage-esm.js`, sourcemap: true, format: "esm" }, external: isExternal, plugins: [ alias(aliases), babel({ exclude: "node_modules/**", sourceMaps: true, presets: [["@babel/preset-env", {}]], }), ], }; let cjs = { input: "lib/index.js", output: { file: `dist/mirage-cjs.js`, sourcemap: true, format: "cjs", esModule: true, }, external: isExternal, plugins: [ alias(aliases), babel({ exclude: "node_modules/**", sourceMaps: true, presets: [ [ "@babel/preset-env", { targets: { node: "current" }, }, ], ], }), resolve(), ], }; let umd = { input: "lib/index.js", output: { file: "dist/mirage-umd.js", format: "umd", name: "MirageJS.Server", }, plugins: [ commonjs(), alias(aliases), resolve(), babel({ exclude: "node_modules/**", sourceMaps: true, presets: [ [ "@babel/preset-env", { useBuiltIns: "usage", corejs: 3, modules: false, targets: "ie 11", }, ], ], }), ], }; export default [esm, cjs, umd]; miragejs-0.1.42/types/000077500000000000000000000000001412317504700145475ustar00rootroot00000000000000miragejs-0.1.42/types/index.d.ts000066400000000000000000000456171412317504700164650ustar00rootroot00000000000000// Minimum TypeScript Version: 3.7 /* * Inspired by Dan Freeman * https://github.com/dfreeman/ * * Source: https://gist.github.com/dfreeman/33fc80164c0ad91d5e9480a94aa6454c#file-tests-model-ts */ declare module "miragejs" { import { FactoryDefinition, ModelDefinition, BelongsTo, HasMany, } from "miragejs/-types"; export { Server, createServer } from "miragejs/server"; export { Registry, Instantiate, ModelInstance } from "miragejs/-types"; export { Serializer, ActiveModelSerializer, JSONAPISerializer, RestSerializer, } from "miragejs/serializer"; /** * A fake HTTP request */ export class Request { /** The request body, if defined */ readonly requestBody: string; /** The URL of the request */ readonly url: string; /** Any headers associated with the request, with downcased names */ readonly requestHeaders: Record; /** Any parameter specified via dynamic route segments */ readonly params: Record; /** Any query parameters associated with the request */ readonly queryParams: Record; } /** * A fake HTTP response. May be returned from a Mirage route * handler for finer-grained control over the response behavior. */ export class Response { /** * @param code The HTTP status code for this response * @param headers Any custom headers to set in this response * @param body Data to send in the response body */ constructor( code: number, headers?: Record, body?: string | {} ); toRackResponse(): [ number, Record | undefined, string | {} | undefined ]; } /** * The base definition for Mirage models. * * Use `Model.extend({ ... })` to define a model's relationships * (via `belongsTo()` and `hasMany()`) and any static default * attribute values. */ export const Model: ModelDefinition; /** * The base definition for Mirage factories. * * Use `Factory.extend({ ... })` to define methods that * will generate default attribute values when `server.create` * or the corresponding `schema` method is called for this * type. */ export const Factory: FactoryDefinition; /** * A collection of zero or more Mirage model instances. */ export class Collection { length: number; modelName: string; models: T[]; } export interface RelationshipOptions { inverse?: string | null; polymorphic?: boolean; } /** Declares a one-to-one relationship to another Mirage model type. */ export function belongsTo( key?: K, options?: RelationshipOptions ): BelongsTo; export function belongsTo( options?: RelationshipOptions ): BelongsTo; /** Declares a one-to-many relationship to another Mirage model type. */ export function hasMany( key?: K, options?: RelationshipOptions ): HasMany; export function hasMany( options?: RelationshipOptions ): HasMany; } declare module "miragejs/-types" { import { Collection } from "miragejs"; /* A 1:1 relationship between models */ export class BelongsTo { private name: Name; } /* A 1:many relationship between models */ export class HasMany { private name: Name; } // Captures the result of a `Model.extend()` call interface ModelDefinition { extend(data: NewData): ModelDefinition>; } // Captures the result of a `Factory.extend()` call interface FactoryDefinition { extend( data: WithFactoryMethods ): FactoryDefinition>>; } type WithFactoryMethods = { [K in keyof T]: T[K] | ((n: number) => T[K]); }; // Extract factory method return values from a factory definition type FlattenFactoryMethods = { [K in keyof T]: T[K] extends (n: number) => infer V ? V : T[K]; }; /** * Given a registry and the name of one of the models defined in it, * returns the type of that model as instantiated by Mirage. */ export type Instantiate< Registry, ModelName extends keyof Registry > = ModelInstance< { // Splitting and rejoining on `ModelName` ensures that unions distribute // properly, so that `Instantiate` expands out like // `Instantiate | Instantiate` rather than something // that only has the intersection of `foo` and `bar`'s keys. [Model in ModelName]: { [Key in keyof Registry[Model]]: InstantiateValue< Registry, Registry[Model][Key] >; }; }[ModelName] >; // Given a registry and value type, checks whether that type represents // if Mirage relationship. If so, returns the corresponding model or // collection type from the registry; otherwise returns the type unchanged. type InstantiateValue = T extends BelongsTo ? InstantiateIfDefined | null : T extends HasMany ? Collection> : T; // Returns the instantiated type of the given model if it exists in the // given registry, or `unknown` otherwise. type InstantiateIfDefined< Registry, ModelName > = ModelName extends keyof Registry ? Instantiate : unknown; // The type-level equivalent of `Object.assign` type Assign = U & Omit; // Extracts model definition info for the given key, if a corresponding model is defined type ExtractModelData = K extends keyof Models ? Models[K] extends ModelDefinition ? Data : {} : {}; // Extracts factory definition info for the given key, if a corresponding factory is defined type ExtractFactoryData = K extends keyof Factories ? Factories[K] extends FactoryDefinition ? FlattenFactoryMethods : {} : {}; /** * Models all available information about a given set of model and * factory definitions, determining the behavior of ORM methods on * a `Server` and its corresponding `Schema` instance. */ export type Registry< Models extends AnyModels, Factories extends AnyFactories > = { [K in keyof Models | keyof Factories]: ExtractModelData & ExtractFactoryData; }; export type AnyModels = Record; export type AnyFactories = Record; /** A marker type for easily constraining type parameters that must be shaped like a Registry */ export type AnyRegistry = Registry; /** Represents the type of an instantiated Mirage model. */ export type ModelInstance = Data & { id?: string; attrs: Record; modelName: string; /** Persists any updates on this model back to the Mirage database. */ save(): void; /** Updates and immediately persists a single or multiple attr(s) on this model. */ update(key: K, value: Data[K]): void; update(changes: Partial): void; /** Removes this model from the Mirage database. */ destroy(): void; /** Reloads this model's data from the Mirage database. */ reload(): void; }; } declare module "miragejs/server" { import { Request, Response, Registry as MirageRegistry } from "miragejs"; import { AnyRegistry, AnyModels, AnyFactories, Instantiate, } from "miragejs/-types"; import { ModelInstance } from "miragejs/-types"; import Db from "miragejs/db"; import IdentityManager from "miragejs/identity-manager"; import Schema from "miragejs/orm/schema"; import PretenderServer from "pretender"; type MaybePromise = T | PromiseLike; /** A callback that will be invoked when a given Mirage route is hit. */ export type RouteHandler = ( schema: Schema, request: Request ) => MaybePromise; export interface HandlerOptions { /** A number of ms to artificially delay responses to this route. */ timing?: number; } export interface ServerConfig< Models extends AnyModels, Factories extends AnyFactories > { urlPrefix?: string; fixtures?: any; namespace?: string; timing?: number; environment?: string; trackRequests?: boolean; useDefaultPassthroughs?: boolean; logging?: boolean; seeds?: (server: Server>) => void; scenarios?: (server: Server>) => void; routes?: (this: Server>) => void; baseConfig?: (this: Server>) => void; testConfig?: (this: Server>) => void; inflector?: object; identityManagers?: IdentityManager; models?: Models; serializers?: any; factories?: Factories; pretender?: PretenderServer; } /** * Starts up a Mirage server with the given configuration. */ export function createServer< Models extends AnyModels, Factories extends AnyFactories >( config: ServerConfig ): Server>; export class Server { constructor(options?: ServerConfig); /** The underlying in-memory database instance for this server. */ readonly db: Db; /** An interface to the Mirage ORM that allows for querying and creating records. */ readonly schema: Schema; /** Creates a model of the given type. */ readonly create: Schema["create"]; /** Whether or not Mirage should log all requests/response cycles. */ logging: boolean; /** A default number of ms to artificially delay responses for all routes. */ timing: number; /** A default prefix applied to all subsequent route definitions. */ namespace: string; /** Sets a string to prefix all route handler URLs with. */ urlPrefix: string; /** Actual Pretender instance */ pretender: PretenderServer; /** Creates multiple models of the given type. */ createList< K extends keyof Registry, Init extends Instantiate, Data extends Partial >(modelName: K, count: number, data?: Data): Array; /** Handle a GET request to the given path. */ get( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle a POST request to the given path. */ post( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle a PUT request to the given path. */ put( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle a PATCH request to the given path. */ patch( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle an OPTIONS request to the given path. */ options( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle a DELETE request to the given path. */ del( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; delete( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Handle a HEAD request to the given path. */ head( path: string, handler?: RouteHandler, options?: HandlerOptions ): void; /** Pass through one or more URLs to make real requests. */ passthrough(urls?: ((request: Request) => any) | string | string[]): void; /** Load all available fixture data matching the given name(s). */ loadFixtures(...names: string[]): void; seeds(server: Server): void; routes(): void; /** Shutdown the server and stop intercepting network requests. */ shutdown(): void; } } declare module "miragejs/db" { import DbCollection from "miragejs/db-collection"; import IdentityManager from "miragejs/identity-manager"; type DbLookup = { [key: string]: ReturnType & Omit; }; class DbClass { constructor(initialData: [], identityManagers?: IdentityManager[]); createCollection(name: string, initialData?: any[]): void; dump(): void; emptyData(): void; loadData(data: any): void; } /** The in-memory database containing all currently active data keyed by collection name. */ export type Db = DbClass & DbLookup; export const Db: Db; export default Db; } declare module "miragejs/db-collection" { import IdentityManager from "miragejs/identity-manager"; export default class DbCollection { constructor( name: string, initialData: any[], identityManager?: IdentityManager ); /** Returns a copy of the data, to prevent inadvertent data manipulation. */ all(): any[]; /** Returns a single record from the `collection` if `ids` is a single id, or an array of records if `ids` is an array of ids. */ find(id: number | string | number[] | string[]): any; /** Returns the first model from `collection` that matches the key-value pairs in the `query` object. */ findBy(query: object): any; /** Finds the first record matching the provided _query_ in `collection`, or creates a new record using a merge of the `query` and optional `attributesForCreate`. */ firstOrCreate(query: object, attributesForCreate?: object): any; /** Inserts `data` into the collection. `data` can be a single object or an array of objects. */ insert(data: any): any; /** Removes one or more records in *collection*. */ remove(target?: object | number | string): void; /** Updates one or more records in the collection. */ update(target: object | number | string, attrs?: object): any; /** Returns an array of models from `collection` that match the key-value pairs in the `query` object. */ where(query: object): any; } } declare module "miragejs/identity-manager" { /** An IdentityManager is a class that's responsible for generating unique identifiers. You can define a custom identity manager for your entire application, as well as on a per-model basis. */ export default class IdentityManager { constructor(); get(): number; /** Registers `uniqueIdentifier` as used. */ set(uniqueIdentifier: string | number): void; inc(): number; /** Returns the next unique identifier. */ fetch(): string; /** Resets the identity manager, marking all unique identifiers as available. */ reset(): void; } } declare module "miragejs/orm/schema" { import { Collection } from "miragejs"; import { AnyRegistry, Instantiate } from "miragejs/-types"; import Db from "miragejs/db"; type ModelInitializer = { [K in keyof Data]: Data[K] extends Collection ? Collection | M[] : Data[K]; }; /** * An interface to the Mirage ORM that allows for querying and creating records. */ export default class Schema { /** Mirage's in-memory database */ readonly db: Db; /** * Creates a model of the given type. * @param modelName The type of model to instantiate * @param data Optional initial values for model attributes/relationships */ create< K extends keyof Registry, Init extends Instantiate, Data extends Partial> >( modelName: K, data?: Data ): Init & { [K in keyof Init & keyof Data]: Exclude }; /** Locates one or more existing models of the given type by ID(s). */ find( type: K, id: string ): Instantiate | null; find( type: K, ids: string[] ): Collection>; /** Locates an existing model of the given type by attribute value(s), if one exists. */ findBy( type: K, attributes: Partial> ): Instantiate | null; /** Locates an existing model of the given type by attribute value(s), creating one if it doesn't exist. */ findOrCreateBy( type: K, attributes: Partial> ): Instantiate; /** Locates an existing model of the given type by attribute value(s), if one exists. */ where( type: K, attributes: | Partial> | ((item: Instantiate) => unknown) ): Collection>; /** Returns a collection of all known records of the given type */ all( type: K ): Collection>; /** Returns an empty collection of the given type */ none( type: K ): Collection>; /** Returns the first model instance found of the given type */ first(type: K): Instantiate | null; } } declare module "miragejs/serializer" { import Schema from "miragejs/orm/schema"; interface SerializerInterface { schema?: Schema; attrs?: any; embed?: any; root?: any; serializeIds?: any; include?: any; keyForAttribute?(attr: any): any; keyForCollection?(modelName: any): any; keyForEmbeddedRelationship?(attributeName: any): any; keyForForeignKey?(relationshipName: any): any; keyForModel?(modelName: any): any; keyForPolymorphicForeignKeyId?(relationshipName: string): string; keyForPolymorphicForeignKeyType?(relationshipName: string): string; keyForRelationship?(modelName: any): any; keyForRelationshipIds?(modelName: any): any; normalize?(json: any): any; serialize?(primaryResource: any, request: any): any; extend?(param?: SerializerInterface): SerializerInterface; } class Serializer implements SerializerInterface { static extend(param?: SerializerInterface | {}): SerializerInterface | {}; } interface JSONAPISerializerInterface extends SerializerInterface { alwaysIncludeLinkageData?: boolean; links?(model: any): any; shouldIncludeLinkageData?(relationshipKey: string, model: any): boolean; typeKeyForModel?(model: any): string; } class JSONAPISerializer extends Serializer implements JSONAPISerializerInterface { static extend( param?: JSONAPISerializerInterface | {} ): JSONAPISerializerInterface; } class ActiveModelSerializer extends Serializer {} class RestSerializer extends Serializer {} } miragejs-0.1.42/types/tests/000077500000000000000000000000001412317504700157115ustar00rootroot00000000000000miragejs-0.1.42/types/tests/db-test.ts000066400000000000000000000024071412317504700176260ustar00rootroot00000000000000import DbCollection from "miragejs/db-collection"; import { Server } from "miragejs/server"; const server: Server = new Server(); server.db.loadData({ movies: [ { title: "Interstellar" }, { title: "Inception" }, { title: "Dunkirk" }, ], }); const myDb = server.db; // $ExpectType Db interface Movie { title: string; } myDb.createCollection("movies", [{ title: "Interstellar" }]); // $ExpectType void myDb.dump(); // $ExpectType void myDb.emptyData(); // $ExpectType void myDb.loadData({}); // $ExpectType void const dbCollection = new DbCollection("movies", [{ title: "Dunkirk" }]); myDb.users.find(1); // $ExpectType any myDb.users.find([1, 2]); // $ExpectType any myDb.users.findBy({ name: "Link" }); // $ExpectType any myDb.users.where({ name: "Link" }); // $ExpectType any myDb.users.insert({}); // $ExpectType any myDb.users.insert([]); // $ExpectType any myDb.users.firstOrCreate({ name: "Link" }); // $ExpectType any myDb.users.remove(); // $ExpectType void myDb.users.remove(1); // $ExpectType void myDb.users.remove({ name: "Zelda" }); // $ExpectType void myDb.users.update({ name: "Ganon" }); // $ExpectType any myDb.users.update(1, { name: "Young Link" }); // $ExpectType any myDb.users.update({ name: "Link" }, { name: "Epona" }); // $ExpectType any miragejs-0.1.42/types/tests/factory-test.ts000066400000000000000000000052301412317504700207050ustar00rootroot00000000000000import { Factory, Model, Registry } from "miragejs"; import Schema from "miragejs/orm/schema"; const PersonModel = Model.extend({ name: "hello", }); interface Person { age: number; height: string; } /** * We show two methods of using the factories here: * - For PersonFactoryInferred, we show that we can infer * the properties from your typedefs. This is appropriate * if all of the properties on your object can be auto-generated with a factory * - For PersonFactoryExplicit, we demonstrate passing an actual type argument to * Factory.extend, so that you can have extra properties on the model without having * to create generators. */ const PersonFactoryInferred = Factory.extend({ age: 42, height(n: number) { return `${n}'`; }, }); const PersonFactoryExplicit = Factory.extend>({ height(n: number) { return `${n}'`; }, }); declare const schema: Schema>; { const people = schema.all("personExplicit"); people.length; // $ExpectType number people.modelName; // $ExpectType string people.models.map((model) => { model.id; // $ExpectType string | undefined model.name; // $ExpectType string model.attrs; // $ExpectType Record model.age; // $ExpectType number | undefined model.height; // $ExpectType string | undefined model.foo; // $ExpectError }); schema.create("personExplicit").height; // $ExpectType string schema.create("personExplicit", {}).height; // $ExpectType string | undefined schema.create("personExplicit", { height: "custom" }).height; // $ExpectType string schema.create("personExplicit", { height: 123 }); // $ExpectError schema.create("personExplicit", { foo: "bar" }); // $ExpectError } { const people = schema.all("personInferred"); people.length; // $ExpectType number people.modelName; // $ExpectType string people.models.map((model) => { model.id; // $ExpectType string | undefined model.name; // $ExpectType string model.attrs; // $ExpectType Record model.age; // $ExpectType number model.height; // $ExpectType string model.foo; // $ExpectError }); schema.create("personInferred").height; // $ExpectType string schema.create("personInferred", {}).height; // $ExpectType string schema.create("personInferred", { height: "custom" }).height; // $ExpectType string schema.create("personInferred", { height: 123 }); // $ExpectError schema.create("personInferred", { foo: "bar" }); // $ExpectError } miragejs-0.1.42/types/tests/identity-manager-test.ts000066400000000000000000000005171412317504700225020ustar00rootroot00000000000000import IdentityManager from "miragejs/identity-manager"; const identityManager = new IdentityManager(); identityManager.get(); // $ExpectType number identityManager.set("id"); // $ExpectType void identityManager.inc(); // $ExpectType number identityManager.fetch(); // $ExpectType string identityManager.reset(); // $ExpectType void miragejs-0.1.42/types/tests/model-test.ts000066400000000000000000000021561412317504700203420ustar00rootroot00000000000000import { Model, Registry } from "miragejs"; import Schema from "miragejs/orm/schema"; const PersonModel = Model.extend({ name: "hello", }); declare const schema: Schema>; const people = schema.all("person"); people.length; // $ExpectType number people.modelName; // $ExpectType string people.models.map((model) => { model.id; // $ExpectType string | undefined model.name; // $ExpectType string model.modelName; // $ExpectType string model.attrs; // $ExpectType Record model.foo; // $ExpectError model.save(); // $ExpectType void model.reload(); // $ExpectType void model.destroy(); // $ExpectType void model.update("name", "goodbye"); // $ExpectType void model.update("name", false); // $ExpectError model.update("bad", "ok"); // $ExpectError }); schema.create("person").name; // $ExpectType string schema.create("person", {}).name; // $ExpectType string schema.create("person", { name: "custom" }).name; // $ExpectType string schema.create("person", { name: 123 }); // $ExpectError schema.create("person", { foo: "bar" }); // $ExpectError miragejs-0.1.42/types/tests/overview-test.ts000066400000000000000000000044661412317504700211160ustar00rootroot00000000000000/** * Code samples from the official documentation: "Overview" page */ import { belongsTo, Factory, hasMany, Model, Response, Server } from "miragejs"; new Server({ routes() { this.namespace = "api"; // Responding to a POST request this.post("/movies", (schema, request) => { const attrs = JSON.parse(request.requestBody); attrs.id = Math.floor(Math.random() * 100); return { movie: attrs }; }); // Using the `timing` option to slow down the response this.get( "/movies", () => { return { movies: [ { id: 1, name: "Inception", year: 2010 }, { id: 2, name: "Interstellar", year: 2014 }, { id: 3, name: "Dunkirk", year: 2017 }, ], }; }, { timing: 4000 } ); // Using the `Response` class to return a 500 this.delete("/movies/1", () => { const headers = {}; const data = { errors: ["Server did not respond"] }; return new Response(500, headers, data); }); }, }); new Server({ models: { movie: Model, }, routes() { this.namespace = "api"; this.get("/movies", () => { return { movies: [ { id: 1, name: "Inception", year: 2010 }, { id: 2, name: "Interstellar", year: 2014 }, { id: 3, name: "Dunkirk", year: 2017 }, ], }; }); }, seeds(server) { server.createList("movie", 10); }, }); new Server({ models: { movie: Model, }, routes() { this.namespace = "api"; this.get("/movies"); this.get("/movies/:id"); this.post("/movies"); this.patch("/movies/:id"); this.del("/movies/:id"); }, factories: { movie: Factory.extend({ title(i: number) { return `Movie ${i}`; // Movie 1, Movie 2, etc. }, year() { const min = 1950; const max = 2019; return Math.floor(Math.random() * (max - min + 1)) + min; }, rating: "PG-13", }), }, }); new Server({ models: { movie: Model.extend({ castMembers: hasMany(), }), castMember: Model.extend({ movie: belongsTo(), }), }, routes() { this.get("/movies/:id/cast-members", (schema, request) => { const movie = schema.db.movies.find(request.params.id); return movie.castMembers; }); }, }); miragejs-0.1.42/types/tests/relationships-test.ts000066400000000000000000000046041412317504700221260ustar00rootroot00000000000000import { belongsTo, hasMany, Model, Registry } from "miragejs"; import Schema from "miragejs/orm/schema"; const PersonModel = Model.extend({ name: "hello", parent: belongsTo("person"), pets: hasMany("pet"), friends: hasMany<"pet" | "person">({ polymorphic: true }), nothing: belongsTo("nonexistent"), muchAdoAboutNothing: hasMany("nonexistent"), }); const PetModel = Model.extend({ name: "fido", owner: belongsTo("person"), }); type PersonRegistry = Registry< { person: typeof PersonModel; pet: typeof PetModel }, {} >; declare const schema: Schema; const people = schema.all("person"); people.length; // $ExpectType number people.modelName; // $ExpectType string people.models.map((model) => { model.nothing; // $ExpectType unknown model.muchAdoAboutNothing; // $ExpectType Collection model.parent?.name; // $ExpectType string | undefined model.parent?.parent?.name; // $ExpectType string | undefined model.pets.models[0].name; // $ExpectType string // Polymorphic relationship const friend = model.friends.models[0]; // Both 'pet' and 'person' models have a name, but no other shared fields friend.name; // $ExpectType string friend.parent; // $ExpectError friend.friends; // $ExpectError friend.owner; // $ExpectError if ("parent" in friend) { // Here we know friend is a person friend.parent!.name; // $ExpectType string friend.friends.length; // $ExpectType number } else { // Here we know friend is a pet friend.owner!.name; // $ExpectType string } }); const child = schema.create("person", { parent: schema.create("person"), }); // Here we know `parent` is defined because it was just passed in child.parent.name; // $ExpectType string schema.create("person", { parent: "hi" }); // $ExpectError const pet1 = schema.create("pet"); const pet2 = schema.create("pet"); // We can instantiate a hasMany with either an array or a collection // Either way, the instance should have a collection. const personWithPetsArray = schema.create("person", { pets: [pet1, pet2], }); personWithPetsArray.pets.modelName; // $ExpectType string const personWithPetsCollection = schema.create("person", { pets: schema.all("pet"), }); personWithPetsCollection.pets.modelName; // $ExpectType string schema.create("person", { pets: [child] }); // $ExpectError schema.create("person", { pets: schema.all("person") }); // $ExpectError miragejs-0.1.42/types/tests/schema-test.ts000066400000000000000000000030211412317504700204720ustar00rootroot00000000000000import { Factory, Model, Registry } from "miragejs"; import Schema from "miragejs/orm/schema"; const FooModel = Model.extend({ attr: "text", }); const FooFactory = Factory.extend({ attr: "text", }); declare const schema: Schema>; schema.create("foo").attr; // $ExpectType string schema.create("foo", { attr: "ok" }).attr; // $ExpectType string schema.create("foo", { attr: 123 }); // $ExpectError schema.create("foo", { x: true }); // $ExpectError schema.create("cow"); // $ExpectError schema.find("foo", "123")?.attr; // $ExpectType string | undefined schema.find("foo", ["123"]).models[0].attr; // $ExpectType string schema.find("cow", "123"); // $ExpectError schema.findOrCreateBy("foo", { attr: "hi" }).attr; // $ExpectType string schema.findOrCreateBy("foo", { bar: true }); // $ExpectError schema.findOrCreateBy("cow", { attr: "bar" }); // $ExpectError schema.where("foo", { attr: "bar" }).models[0].attr; // $ExpectType string schema.where("foo", { bar: true }); // $ExpectError schema.where("foo", (foo) => foo.attr === "ok").models[0].attr; // $ExpectType string schema.where("foo", (foo) => foo.x === "ok"); // $ExpectError schema.where("cow", { attr: "bar" }); // $ExpectError schema.all("foo").models[0].attr; // $ExpectType string schema.all("cow"); // $ExpectError schema.none("foo").models[0].attr; // $ExpectType string schema.none("cow"); // $ExpectError schema.first("foo")?.attr; // $ExpectType string | undefined schema.first("cow"); // $ExpectError miragejs-0.1.42/types/tests/serializer-test.ts000066400000000000000000000020041412317504700214030ustar00rootroot00000000000000import { Serializer, ActiveModelSerializer, JSONAPISerializer, RestSerializer, Server, Model, hasMany, } from "miragejs"; new Server({ serializers: { application: RestSerializer, user: RestSerializer.extend({ // user-specific customizations }), }, }); new Server({ serializers: { application: JSONAPISerializer, }, }); new Server({ serializers: { application: ActiveModelSerializer, }, }); new Server({ serializers: { application: Serializer, }, }); new Server({ models: { author: Model.extend({ blogPosts: hasMany(), }), }, serializers: { author: Serializer.extend({ include: ["blogPosts"], }), }, }); Serializer.extend({ attrs: ["id", "title"], }); JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }); const ApplicationSerializer = Serializer.extend(); JSONAPISerializer.extend({ alwaysIncludeLinkageData: true, }); export default Serializer.extend({ keyForAttribute(attr) { return "key"; }, }); miragejs-0.1.42/types/tests/server-test.ts000066400000000000000000000065701412317504700205540ustar00rootroot00000000000000import { Response, Server, JSONAPISerializer, createServer, Model, belongsTo, hasMany, Factory, } from "miragejs"; export default function config(this: Server): void { this.namespace = "foo"; this.urlPrefix = "/api"; this.timing = 123; this.logging = true; this.get("/foo"); // $ExpectType void this.put("/foo"); // $ExpectType void this.post("/foo"); // $ExpectType void this.patch("/foo"); // $ExpectType void this.options("/foo"); // $ExpectType void this.del("/foo"); // $ExpectType void this.passthrough("/_coverage/upload"); // $ExpectType void this.passthrough((request) => request.queryParams.skipMirage); // $ExpectType void this.loadFixtures(); // $ExpectType void this.seeds(this); // $ExpectType void this.routes(); // $ExpectType void this.shutdown(); // $ExpectType void this.get("/test/:segment", (schema, request) => { schema.db; // $ExpectType Db request.params; // $ExpectType Record request.queryParams; // $ExpectType Record request.requestBody; // $ExpectType string request.requestHeaders; // $ExpectType Record request.url; // $ExpectType string return new Response(200, { "Content-Type": "application/json" }, "{}"); }); this.get("/test/:segment", (schema) => Promise.resolve(schema.create("foo"))); // $ExpectType void } // In `new Server`, models and factories are untyped, and you can // therefore use any model names you want when interacting with the // schema; the return values just won't necessarily have a lot of // type information. new Server({ serializers: { application: JSONAPISerializer, }, fixtures: { countries: [ { id: 1, name: "China" }, { id: 2, name: "India" }, { id: 3, name: "United States" }, ], }, routes() { this.namespace = "api"; this.schema.all("asfd"); this.get("/todos", () => { return { todos: [{ id: "1", text: "Migrate to TypeScript", isDone: false }], }; }); }, baseConfig() { this.pretender.handledRequest = (verb, path, request) => {}; this.get("/contacts", () => { return ["Interstellar", "Inception", "Dunkirk"]; }); }, testConfig() { this.namespace = "/test-api"; this.get("/movies"); this.post("/movies"); }, }); // In contrast to `new Server`, `createServer` is able to infer // type info from the models and factories you pass it createServer({ models: { pet: Model.extend({ owner: belongsTo("person"), }), person: Model.extend({ children: hasMany("person"), friends: hasMany<"person" | "pet">({ polymorphic: true }), }), }, factories: { pet: Factory.extend({ name: (n: number) => `Pet ${n}`, }), person: Factory.extend({ name: (n: number) => `Pet ${n}`, }), }, routes() { this.get("people/:id", (schema, request) => { let person = this.schema.find("person", request.params.id); person?.name; // $ExpectType string | undefined let friend = person?.friends.models[0]; friend?.name; // $ExpectType string | undefined friend?.children; // $ExpectError if (friend && "friends" in friend) { friend.children.modelName; // $ExpectType string } return person ?? new Response(404); }); this.get("bad", () => { return this.schema.all("typo"); // $ExpectError }); }, }); miragejs-0.1.42/types/tsconfig.json000066400000000000000000000004211412317504700172530ustar00rootroot00000000000000{ "compilerOptions": { "target": "es6", "lib": ["es6", "dom"], "module": "ES6", "noEmit": true, "strict": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "miragejs": ["."] }, "moduleResolution": "Node" } } miragejs-0.1.42/types/tslint.json000066400000000000000000000001041412317504700167520ustar00rootroot00000000000000{ "extends": ["dtslint/dtslint.json", "tslint-config-prettier"] } miragejs-0.1.42/yarn.lock000066400000000000000000010732471412317504700152440ustar00rootroot00000000000000# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== dependencies: "@babel/highlight" "^7.10.4" "@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41" integrity sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw== "@babel/core@^7.1.0", "@babel/core@^7.5.5", "@babel/core@^7.7.5": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== dependencies: "@babel/code-frame" "^7.10.4" "@babel/generator" "^7.12.10" "@babel/helper-module-transforms" "^7.12.1" "@babel/helpers" "^7.12.5" "@babel/parser" "^7.12.10" "@babel/template" "^7.12.7" "@babel/traverse" "^7.12.10" "@babel/types" "^7.12.10" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" json5 "^2.1.2" lodash "^4.17.19" semver "^5.4.1" source-map "^0.5.0" "@babel/generator@^7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.10.tgz#2b188fc329fb8e4f762181703beffc0fe6df3460" integrity sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww== dependencies: "@babel/types" "^7.12.10" jsesc "^2.5.1" source-map "^0.5.0" "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== dependencies: "@babel/types" "^7.10.4" "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== dependencies: "@babel/helper-explode-assignable-expression" "^7.10.4" "@babel/types" "^7.10.4" "@babel/helper-compilation-targets@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz#cb470c76198db6a24e9dbc8987275631e5d29831" integrity sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw== dependencies: "@babel/compat-data" "^7.12.5" "@babel/helper-validator-option" "^7.12.1" browserslist "^4.14.5" semver "^5.5.0" "@babel/helper-create-class-features-plugin@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e" integrity sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w== dependencies: "@babel/helper-function-name" "^7.10.4" "@babel/helper-member-expression-to-functions" "^7.12.1" "@babel/helper-optimise-call-expression" "^7.10.4" "@babel/helper-replace-supers" "^7.12.1" "@babel/helper-split-export-declaration" "^7.10.4" "@babel/helper-create-regexp-features-plugin@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz#18b1302d4677f9dc4740fe8c9ed96680e29d37e8" integrity sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-regex" "^7.10.4" regexpu-core "^4.7.1" "@babel/helper-define-map@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz#f037ad794264f729eda1889f4ee210b870999092" integrity sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA== dependencies: "@babel/helper-function-name" "^7.10.4" "@babel/types" "^7.10.4" lodash "^4.17.13" "@babel/helper-explode-assignable-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c" integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A== dependencies: "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" "@babel/helper-function-name@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== dependencies: "@babel/helper-get-function-arity" "^7.10.4" "@babel/template" "^7.10.4" "@babel/types" "^7.10.4" "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== dependencies: "@babel/types" "^7.10.4" "@babel/helper-hoist-variables@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== dependencies: "@babel/types" "^7.10.4" "@babel/helper-member-expression-to-functions@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz#fba0f2fcff3fba00e6ecb664bb5e6e26e2d6165c" integrity sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ== dependencies: "@babel/types" "^7.12.1" "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== dependencies: "@babel/types" "^7.12.5" "@babel/helper-module-transforms@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== dependencies: "@babel/helper-module-imports" "^7.12.1" "@babel/helper-replace-supers" "^7.12.1" "@babel/helper-simple-access" "^7.12.1" "@babel/helper-split-export-declaration" "^7.11.0" "@babel/helper-validator-identifier" "^7.10.4" "@babel/template" "^7.10.4" "@babel/traverse" "^7.12.1" "@babel/types" "^7.12.1" lodash "^4.17.19" "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== dependencies: "@babel/types" "^7.10.4" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== "@babel/helper-regex@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.4.tgz#59b373daaf3458e5747dece71bbaf45f9676af6d" integrity sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ== dependencies: lodash "^4.17.13" "@babel/helper-remap-async-to-generator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz#8c4dbbf916314f6047dc05e6a2217074238347fd" integrity sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-wrap-function" "^7.10.4" "@babel/types" "^7.12.1" "@babel/helper-replace-supers@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz#f15c9cc897439281891e11d5ce12562ac0cf3fa9" integrity sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw== dependencies: "@babel/helper-member-expression-to-functions" "^7.12.1" "@babel/helper-optimise-call-expression" "^7.10.4" "@babel/traverse" "^7.12.1" "@babel/types" "^7.12.1" "@babel/helper-simple-access@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== dependencies: "@babel/types" "^7.12.1" "@babel/helper-skip-transparent-expression-wrappers@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== dependencies: "@babel/types" "^7.12.1" "@babel/helper-split-export-declaration@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1" integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg== dependencies: "@babel/types" "^7.10.4" "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== dependencies: "@babel/types" "^7.11.0" "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== "@babel/helper-validator-identifier@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== "@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f" integrity sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw== "@babel/helper-wrap-function@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== dependencies: "@babel/helper-function-name" "^7.10.4" "@babel/template" "^7.10.4" "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" "@babel/helpers@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== dependencies: "@babel/template" "^7.10.4" "@babel/traverse" "^7.12.5" "@babel/types" "^7.12.5" "@babel/highlight@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== dependencies: "@babel/helper-validator-identifier" "^7.10.4" chalk "^2.0.0" js-tokens "^4.0.0" "@babel/parser@^7.1.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.7", "@babel/parser@^7.7.0", "@babel/parser@^7.7.5": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.10.tgz#824600d59e96aea26a5a2af5a9d812af05c3ae81" integrity sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA== "@babel/plugin-proposal-async-generator-functions@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e" integrity sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.12.1" "@babel/plugin-syntax-async-generators" "^7.8.0" "@babel/plugin-proposal-class-properties@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz#a082ff541f2a29a4821065b8add9346c0c16e5de" integrity sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w== dependencies: "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-proposal-dynamic-import@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz#43eb5c2a3487ecd98c5c8ea8b5fdb69a2749b2dc" integrity sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-proposal-export-namespace-from@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz#8b9b8f376b2d88f5dd774e4d24a5cc2e3679b6d4" integrity sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-proposal-json-strings@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz#d45423b517714eedd5621a9dfdc03fa9f4eb241c" integrity sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-proposal-logical-assignment-operators@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz#f2c490d36e1b3c9659241034a5d2cd50263a2751" integrity sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" integrity sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" "@babel/plugin-proposal-numeric-separator@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz#8bf253de8139099fea193b297d23a9d406ef056b" integrity sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-proposal-object-rest-spread@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-transform-parameters" "^7.12.1" "@babel/plugin-proposal-optional-catch-binding@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz#ccc2421af64d3aae50b558a71cede929a5ab2942" integrity sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-proposal-optional-chaining@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz#e02f0ea1b5dc59d401ec16fb824679f683d3303c" integrity sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.0" "@babel/plugin-proposal-private-methods@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz#86814f6e7a21374c980c10d38b4493e703f4a389" integrity sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w== dependencies: "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-proposal-unicode-property-regex@^7.12.1", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz#2a183958d417765b9eae334f47758e5d6a82e072" integrity sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-async-generators@^7.8.0", "@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" 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" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz#bcb297c5366e79bebadef509549cd93b04f19978" integrity sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== dependencies: "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.0", "@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" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@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" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@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" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^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" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^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" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-top-level-await@^7.12.1", "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz#dd6c0b357ac1bb142d98537450a319625d13d2a0" integrity sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-arrow-functions@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz#8083ffc86ac8e777fbe24b5967c4b2521f3cb2b3" integrity sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-async-to-generator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" integrity sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A== dependencies: "@babel/helper-module-imports" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.12.1" "@babel/plugin-transform-block-scoped-functions@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz#f2a1a365bde2b7112e0a6ded9067fdd7c07905d9" integrity sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-block-scoping@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.11.tgz#83ae92a104dbb93a7d6c6dd1844f351083c46b4f" integrity sha512-atR1Rxc3hM+VPg/NvNvfYw0npQEAcHuJ+MGZnFn6h3bo+1U3BWXMdFMlvVRApBTWKQMX7SOwRJZA5FBF/JQbvA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-classes@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz#65e650fcaddd3d88ddce67c0f834a3d436a32db6" integrity sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-define-map" "^7.10.4" "@babel/helper-function-name" "^7.10.4" "@babel/helper-optimise-call-expression" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.12.1" "@babel/helper-split-export-declaration" "^7.10.4" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz#d68cf6c9b7f838a8a4144badbe97541ea0904852" integrity sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-destructuring@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz#b9a570fe0d0a8d460116413cb4f97e8e08b2f847" integrity sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-dotall-regex@^7.12.1", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz#a1d16c14862817b6409c0a678d6f9373ca9cd975" integrity sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-duplicate-keys@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz#745661baba295ac06e686822797a69fbaa2ca228" integrity sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-exponentiation-operator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz#b0f2ed356ba1be1428ecaf128ff8a24f02830ae0" integrity sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-for-of@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz#07640f28867ed16f9511c99c888291f560921cfa" integrity sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-function-name@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz#2ec76258c70fe08c6d7da154003a480620eba667" integrity sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw== dependencies: "@babel/helper-function-name" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-literals@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz#d73b803a26b37017ddf9d3bb8f4dc58bfb806f57" integrity sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-member-expression-literals@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz#496038602daf1514a64d43d8e17cbb2755e0c3ad" integrity sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-modules-amd@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz#3154300b026185666eebb0c0ed7f8415fefcf6f9" integrity sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ== dependencies: "@babel/helper-module-transforms" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz#fa403124542636c786cf9b460a0ffbb48a86e648" integrity sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag== dependencies: "@babel/helper-module-transforms" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-simple-access" "^7.12.1" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz#663fea620d593c93f214a464cd399bf6dc683086" integrity sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q== dependencies: "@babel/helper-hoist-variables" "^7.10.4" "@babel/helper-module-transforms" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-validator-identifier" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-umd@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz#eb5a218d6b1c68f3d6217b8fa2cc82fec6547902" integrity sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q== dependencies: "@babel/helper-module-transforms" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz#b407f5c96be0d9f5f88467497fa82b30ac3e8753" integrity sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/plugin-transform-new-target@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz#80073f02ee1bb2d365c3416490e085c95759dec0" integrity sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-object-super@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz#4ea08696b8d2e65841d0c7706482b048bed1066e" integrity sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.12.1" "@babel/plugin-transform-parameters@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz#d2e963b038771650c922eff593799c96d853255d" integrity sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-property-literals@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz#41bc81200d730abb4456ab8b3fbd5537b59adecd" integrity sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-regenerator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz#5f0a28d842f6462281f06a964e88ba8d7ab49753" integrity sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng== dependencies: regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz#6fdfc8cc7edcc42b36a7c12188c6787c873adcd8" integrity sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-shorthand-properties@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz#0bf9cac5550fce0cfdf043420f661d645fdc75e3" integrity sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-spread@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz#527f9f311be4ec7fdc2b79bb89f7bf884b3e1e1e" integrity sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-transform-sticky-regex@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz#560224613ab23987453948ed21d0b0b193fa7fad" integrity sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-template-literals@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz#b43ece6ed9a79c0c71119f576d299ef09d942843" integrity sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-typeof-symbol@^7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz#de01c4c8f96580bd00f183072b0d0ecdcf0dec4b" integrity sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-unicode-escapes@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz#5232b9f81ccb07070b7c3c36c67a1b78f1845709" integrity sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-unicode-regex@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz#cc9661f61390db5c65e3febaccefd5c6ac3faecb" integrity sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" "@babel/preset-env@^7.9.0": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw== dependencies: "@babel/compat-data" "^7.12.7" "@babel/helper-compilation-targets" "^7.12.5" "@babel/helper-module-imports" "^7.12.5" "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-validator-option" "^7.12.11" "@babel/plugin-proposal-async-generator-functions" "^7.12.1" "@babel/plugin-proposal-class-properties" "^7.12.1" "@babel/plugin-proposal-dynamic-import" "^7.12.1" "@babel/plugin-proposal-export-namespace-from" "^7.12.1" "@babel/plugin-proposal-json-strings" "^7.12.1" "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" "@babel/plugin-proposal-numeric-separator" "^7.12.7" "@babel/plugin-proposal-object-rest-spread" "^7.12.1" "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" "@babel/plugin-proposal-optional-chaining" "^7.12.7" "@babel/plugin-proposal-private-methods" "^7.12.1" "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" "@babel/plugin-syntax-async-generators" "^7.8.0" "@babel/plugin-syntax-class-properties" "^7.12.1" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" "@babel/plugin-syntax-top-level-await" "^7.12.1" "@babel/plugin-transform-arrow-functions" "^7.12.1" "@babel/plugin-transform-async-to-generator" "^7.12.1" "@babel/plugin-transform-block-scoped-functions" "^7.12.1" "@babel/plugin-transform-block-scoping" "^7.12.11" "@babel/plugin-transform-classes" "^7.12.1" "@babel/plugin-transform-computed-properties" "^7.12.1" "@babel/plugin-transform-destructuring" "^7.12.1" "@babel/plugin-transform-dotall-regex" "^7.12.1" "@babel/plugin-transform-duplicate-keys" "^7.12.1" "@babel/plugin-transform-exponentiation-operator" "^7.12.1" "@babel/plugin-transform-for-of" "^7.12.1" "@babel/plugin-transform-function-name" "^7.12.1" "@babel/plugin-transform-literals" "^7.12.1" "@babel/plugin-transform-member-expression-literals" "^7.12.1" "@babel/plugin-transform-modules-amd" "^7.12.1" "@babel/plugin-transform-modules-commonjs" "^7.12.1" "@babel/plugin-transform-modules-systemjs" "^7.12.1" "@babel/plugin-transform-modules-umd" "^7.12.1" "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" "@babel/plugin-transform-new-target" "^7.12.1" "@babel/plugin-transform-object-super" "^7.12.1" "@babel/plugin-transform-parameters" "^7.12.1" "@babel/plugin-transform-property-literals" "^7.12.1" "@babel/plugin-transform-regenerator" "^7.12.1" "@babel/plugin-transform-reserved-words" "^7.12.1" "@babel/plugin-transform-shorthand-properties" "^7.12.1" "@babel/plugin-transform-spread" "^7.12.1" "@babel/plugin-transform-sticky-regex" "^7.12.7" "@babel/plugin-transform-template-literals" "^7.12.1" "@babel/plugin-transform-typeof-symbol" "^7.12.10" "@babel/plugin-transform-unicode-escapes" "^7.12.1" "@babel/plugin-transform-unicode-regex" "^7.12.1" "@babel/preset-modules" "^0.1.3" "@babel/types" "^7.12.11" core-js-compat "^3.8.0" semver "^5.5.0" "@babel/preset-modules@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" "@babel/plugin-transform-dotall-regex" "^7.4.4" "@babel/types" "^7.4.4" esutils "^2.0.2" "@babel/runtime@^7.8.4": version "7.9.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== dependencies: regenerator-runtime "^0.13.4" "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3", "@babel/template@^7.7.4": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== dependencies: "@babel/code-frame" "^7.10.4" "@babel/parser" "^7.12.7" "@babel/types" "^7.12.7" "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.10.tgz#2d1f4041e8bf42ea099e5b2dc48d6a594c00017a" integrity sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg== dependencies: "@babel/code-frame" "^7.10.4" "@babel/generator" "^7.12.10" "@babel/helper-function-name" "^7.10.4" "@babel/helper-split-export-declaration" "^7.11.0" "@babel/parser" "^7.12.10" "@babel/types" "^7.12.10" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" "@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.11.tgz#a86e4d71e30a9b6ee102590446c98662589283ce" integrity sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA== dependencies: "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" to-fast-properties "^2.0.0" "@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" 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" integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== dependencies: exec-sh "^0.3.2" minimist "^1.2.0" "@definitelytyped/header-parser@0.0.34": version "0.0.34" resolved "https://registry.yarnpkg.com/@definitelytyped/header-parser/-/header-parser-0.0.34.tgz#892c83ae0cdbc52ee439dfc3ac34244903b8a5ee" integrity sha512-/yTifMAhYKB8SFH3pSlAQmcBzrk7UyqpEz9/vJKaMKdzRpJrxmc1zWMP+hwJtJTVCjAK+Ul4m3i1GZQrTZfymw== dependencies: "@definitelytyped/typescript-versions" "^0.0.34" "@types/parsimmon" "^1.10.1" parsimmon "^1.13.0" "@definitelytyped/header-parser@latest": version "0.0.35" resolved "https://registry.yarnpkg.com/@definitelytyped/header-parser/-/header-parser-0.0.35.tgz#3184ec205c4f5254c33cc34ca720dc9dbdc0176d" integrity sha512-tlfQzjptRPS7ukWzOyUB/srJ3HuQf6OIkK4OOu5kVX6pS+oQRKqCBDS7afwKsGOCP198jT6gwDuuGJeojmFCBg== dependencies: "@definitelytyped/typescript-versions" "^0.0.35" "@types/parsimmon" "^1.10.1" parsimmon "^1.13.0" "@definitelytyped/typescript-versions@^0.0.34": version "0.0.34" resolved "https://registry.yarnpkg.com/@definitelytyped/typescript-versions/-/typescript-versions-0.0.34.tgz#6167363d378670ad7ef9485b7cff7d198106dcdf" integrity sha512-7IqWcbHKYbfY8Lt7AigXDa29cbz3gynzBHMjwMUCeLnex8D682M6OW8uBLouvVHCr+YENL58tQB3dn0Zos8mFQ== "@definitelytyped/typescript-versions@^0.0.35", "@definitelytyped/typescript-versions@latest": version "0.0.35" resolved "https://registry.yarnpkg.com/@definitelytyped/typescript-versions/-/typescript-versions-0.0.35.tgz#f58d22d3f1141f5832e17f5b033ec80559eb8e51" integrity sha512-avSJ8C5KPAYjAF2BkJbrIP3WaTKWM10LT+PepKFr0WXAjObUp8Ds7k8yweEpsRdUTjcL1YIzsusk9NOvAIVY2w== "@definitelytyped/utils@latest": version "0.0.35" resolved "https://registry.yarnpkg.com/@definitelytyped/utils/-/utils-0.0.35.tgz#edd672d463cbfb6351d06f2e02e27be1fd8e549b" integrity sha512-dw5sLbmyiPG0vFmrSe7cNpPWd1XgKWVT4FzRvZuf7L3heAzx+tshGs8vU5t8tAuQNFCvbtvacXRhN0OywqogTg== dependencies: "@definitelytyped/typescript-versions" "^0.0.35" "@types/node" "^12.12.29" charm "^1.0.2" fs-extra "^8.1.0" fstream "^1.0.12" npm-registry-client "^8.6.0" tar "^2.2.2" tar-stream "1.6.2" "@eslint/eslintrc@^0.2.2": version "0.2.2" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== dependencies: ajv "^6.12.4" debug "^4.1.1" espree "^7.3.0" globals "^12.1.0" ignore "^4.0.6" import-fresh "^3.2.1" js-yaml "^3.13.1" lodash "^4.17.19" minimatch "^3.0.4" strip-json-comments "^3.1.1" "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg== dependencies: camelcase "^5.3.1" find-up "^4.1.0" js-yaml "^3.13.1" resolve-from "^5.0.0" "@istanbuljs/schema@^0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== "@jest/console@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== dependencies: "@jest/source-map" "^24.9.0" chalk "^2.0.1" slash "^2.0.0" "@jest/console@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: "@jest/types" "^26.6.2" "@types/node" "*" chalk "^4.0.0" jest-message-util "^26.6.2" jest-util "^26.6.2" slash "^3.0.0" "@jest/core@^26.6.3": version "26.6.3" resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: "@jest/console" "^26.6.2" "@jest/reporters" "^26.6.2" "@jest/test-result" "^26.6.2" "@jest/transform" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" jest-changed-files "^26.6.2" jest-config "^26.6.3" jest-haste-map "^26.6.2" jest-message-util "^26.6.2" jest-regex-util "^26.0.0" jest-resolve "^26.6.2" jest-resolve-dependencies "^26.6.3" jest-runner "^26.6.3" jest-runtime "^26.6.3" jest-snapshot "^26.6.2" jest-util "^26.6.2" jest-validate "^26.6.2" jest-watcher "^26.6.2" micromatch "^4.0.2" p-each-series "^2.1.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" "@jest/environment@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: "@jest/fake-timers" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" jest-mock "^26.6.2" "@jest/fake-timers@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: "@jest/types" "^26.6.2" "@sinonjs/fake-timers" "^6.0.1" "@types/node" "*" jest-message-util "^26.6.2" jest-mock "^26.6.2" jest-util "^26.6.2" "@jest/globals@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== dependencies: "@jest/environment" "^26.6.2" "@jest/types" "^26.6.2" expect "^26.6.2" "@jest/reporters@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" "@jest/console" "^26.6.2" "@jest/test-result" "^26.6.2" "@jest/transform" "^26.6.2" "@jest/types" "^26.6.2" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" jest-haste-map "^26.6.2" jest-resolve "^26.6.2" jest-util "^26.6.2" jest-worker "^26.6.2" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" terminal-link "^2.0.0" v8-to-istanbul "^7.0.0" optionalDependencies: node-notifier "^8.0.0" "@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== dependencies: callsites "^3.0.0" graceful-fs "^4.1.15" source-map "^0.6.0" "@jest/source-map@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" source-map "^0.6.0" "@jest/test-result@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== dependencies: "@jest/console" "^24.9.0" "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" "@jest/test-result@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: "@jest/console" "^26.6.2" "@jest/types" "^26.6.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" "@jest/test-sequencer@^26.6.3": version "26.6.3" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: "@jest/test-result" "^26.6.2" graceful-fs "^4.2.4" jest-haste-map "^26.6.2" jest-runner "^26.6.3" jest-runtime "^26.6.3" "@jest/transform@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" "@jest/types" "^26.6.2" babel-plugin-istanbul "^6.0.0" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" jest-haste-map "^26.6.2" jest-regex-util "^26.0.0" jest-util "^26.6.2" micromatch "^4.0.2" pirates "^4.0.1" slash "^3.0.0" source-map "^0.6.1" write-file-atomic "^3.0.0" "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" "@types/yargs" "^15.0.0" chalk "^4.0.0" "@miragejs/pretender-node-polyfill@^0.1.0": version "0.1.2" resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2" integrity sha512-M/BexG/p05C5lFfMunxo/QcgIJnMT2vDVCd00wNqK2ImZONIlEETZwWJu1QtLxtmYlSHlCFl3JNzp0tLe7OJ5g== "@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" integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== dependencies: "@nodelib/fs.stat" "2.0.3" run-parallel "^1.1.9" "@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" integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== "@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" integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== dependencies: "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" "@sinonjs/commons@^1.7.0": version "1.7.2" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2" integrity sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw== 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" integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== dependencies: "@sinonjs/commons" "^1.7.0" "@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" integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__generator" "*" "@types/babel__template" "*" "@types/babel__traverse" "*" "@types/babel__generator@*": version "7.6.1" resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" 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" integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.11.tgz#1ae3010e8bf8851d324878b42acec71986486d18" integrity sha512-ddHK5icION5U6q11+tV2f9Mo6CZVuT8GJKld2q9LqHSZbvLbH34Kcu2yFGckZut453+eQU6btIA3RihmnRgI+Q== dependencies: "@babel/types" "^7.3.0" "@types/babel__traverse@^7.0.4": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.15.tgz#db9e4238931eb69ef8aab0ad6523d4d4caa39d03" integrity sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A== 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" 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" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@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" 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.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== "@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" integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" "@types/istanbul-reports@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== dependencies: "@types/istanbul-lib-report" "*" "@types/json-schema@^7.0.3": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/node@*": version "13.13.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c" integrity sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA== "@types/node@^12.12.29": version "12.12.37" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.37.tgz#cb4782d847f801fa58316da5b4801ca3a59ae790" integrity sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg== "@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" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== "@types/parsimmon@^1.10.1": version "1.10.1" resolved "https://registry.yarnpkg.com/@types/parsimmon/-/parsimmon-1.10.1.tgz#d46015ad91128fce06a1a688ab39a2516507f740" integrity sha512-MoF2IC9oGSgArJwlxdst4XsvWuoYfNUWtBw0kpnCi6K05kV+Ecl7siEeJ40tgCbI9uqEMGQL/NlPMRv6KVkY5Q== "@types/prettier@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" 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" 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" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== "@types/yargs@^13.0.0": version "13.0.8" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== dependencies: "@types/yargs-parser" "*" "@types/yargs@^15.0.0": version "15.0.4" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== dependencies: "@types/yargs-parser" "*" "@typescript-eslint/experimental-utils@^4.0.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.1.tgz#52ff4e37c93113eb96385a4e6d075abece1ea72d" integrity sha512-jzYsNciHoa4Z3c1URtmeT/bamYm8Dwfw6vuN3WHIE/BXb1iC4KveAnXDErTAZtPVxTYBaYn3n2gbt6F6D2rm1A== dependencies: "@types/json-schema" "^7.0.3" "@typescript-eslint/scope-manager" "4.1.1" "@typescript-eslint/types" "4.1.1" "@typescript-eslint/typescript-estree" "4.1.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" "@typescript-eslint/scope-manager@4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.1.tgz#bdb8526e82435f32b4ccd9dd4cec01af97b48850" integrity sha512-0W8TTobCvIIQ2FsrYTffyZGAAFUyIbEHq5EYJb1m7Rpd005jrnOvKOo8ywCLhs/Bm17C+KsrUboBvBAARQVvyA== dependencies: "@typescript-eslint/types" "4.1.1" "@typescript-eslint/visitor-keys" "4.1.1" "@typescript-eslint/types@4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.1.tgz#57500c4a86b28cb47094c1a62f1177ea279a09cb" integrity sha512-zrBiqOKYerMTllKcn+BP+i1b7LW/EbMMYytroXMxUTvFPn1smkCu0D7lSAx29fTUO4jnwV0ljSvYQtn2vNrNxA== "@typescript-eslint/typescript-estree@4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.1.tgz#2015a84d71303ecdb6f46efd807ac19a51aab490" integrity sha512-2AUg5v0liVBsqbGxBphbJ0QbGqSRVaF5qPoTPWcxop+66vMdU1h4CCvHxTC47+Qb+Pr4l2RhXDd41JNpwcQEKw== dependencies: "@typescript-eslint/types" "4.1.1" "@typescript-eslint/visitor-keys" "4.1.1" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" "@typescript-eslint/visitor-keys@4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.1.tgz#bb05664bf4bea28dc120d1da94f3027d42ab0f6f" integrity sha512-/EOOXbA2ferGLG6RmCHEQ0lTTLkOlXYDgblCmQk3tIU7mTPLm4gKhFMeeUSe+bcchTUsKeCk8xcpbop5Zr/8Rw== dependencies: "@typescript-eslint/types" "4.1.1" eslint-visitor-keys "^2.0.0" abab@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== acorn-globals@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== dependencies: acorn "^7.1.1" acorn-walk "^7.1.1" acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== acorn-walk@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== acorn@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== acorn@^7.4.0: version "7.4.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.5.5: version "6.12.4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" 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" 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.0.0, ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 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" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 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" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== dependencies: "@types/color-name" "^1.1.1" color-convert "^2.0.1" anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" anymatch@^3.0.3: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 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" integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" 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" 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" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-includes@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== dependencies: define-properties "^1.1.3" es-abstract "^1.17.0" is-string "^1.0.5" array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= array.prototype.flat@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== dependencies: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 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" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== async-array-reduce@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/async-array-reduce/-/async-array-reduce-0.2.1.tgz#c8be010a2b5cd00dea96c81116034693dfdd82d1" integrity sha1-yL4BCitc0A3qlsgRFgNGk9/dgtE= async-to-gen@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/async-to-gen/-/async-to-gen-1.4.0.tgz#f8157f9013e0c487e1e940150a4d1a1b78b2dd6b" integrity sha1-+BV/kBPgxIfh6UAVCk0aG3iy3Ws= dependencies: babylon "^6.14.0" magic-string "^0.22.0" pirates "^3.0.2" asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" 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" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.9.1" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= dependencies: chalk "^1.1.3" esutils "^2.0.2" js-tokens "^3.0.2" babel-eslint@^10.0.2: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.7.0" "@babel/traverse" "^7.7.0" "@babel/types" "^7.7.0" eslint-visitor-keys "^1.0.0" resolve "^1.12.0" babel-jest@^26.0.1, babel-jest@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: "@jest/transform" "^26.6.2" "@jest/types" "^26.6.2" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" babel-preset-jest "^26.6.2" chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== dependencies: object.assign "^4.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" integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" babel-plugin-jest-hoist@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz#cf5feef29551253471cfa82fc8e0f5063df07a77" integrity sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-syntax-numeric-separator" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" babel-preset-jest@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== dependencies: babel-plugin-jest-hoist "^26.6.2" babel-preset-current-node-syntax "^1.0.0" babylon@^6.14.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" component-emitter "^1.2.1" define-property "^1.0.0" isobject "^3.0.1" mixin-deep "^1.2.0" pascalcase "^0.1.1" bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" bl@^1.0.0: version "1.2.3" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: readable-stream "^2.3.5" safe-buffer "^5.1.1" block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.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" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" extend-shallow "^2.0.1" fill-range "^4.0.0" isobject "^3.0.1" repeat-element "^1.1.2" snapdragon "^0.8.1" snapdragon-node "^2.0.1" split-string "^3.0.2" to-regex "^3.0.1" braces@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.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" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.14.5: version "4.14.7" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.7.tgz#c071c1b3622c1c2e790799a37bb09473a4351cb6" integrity sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ== dependencies: caniuse-lite "^1.0.30001157" colorette "^1.2.1" electron-to-chromium "^1.3.591" escalade "^3.1.1" node-releases "^1.1.66" browserslist@^4.15.0: version "4.15.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.15.0.tgz#3d48bbca6a3f378e86102ffd017d9a03f122bdb0" integrity sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ== dependencies: caniuse-lite "^1.0.30001164" colorette "^1.2.1" electron-to-chromium "^1.3.612" escalade "^3.1.1" node-releases "^1.1.67" bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 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" integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" get-value "^2.0.6" has-value "^1.0.0" isobject "^3.0.1" set-value "^2.0.0" to-object-path "^0.3.0" union-value "^1.0.0" unset-value "^1.0.0" callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== caniuse-lite@^1.0.30001157: version "1.0.30001159" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001159.tgz#bebde28f893fa9594dadcaa7d6b8e2aa0299df20" integrity sha512-w9Ph56jOsS8RL20K9cLND3u/+5WASWdhC/PPrf+V3/HsM3uHOavWOR1Xzakbv4Puo/srmPHudkmCRWM7Aq+/UA== caniuse-lite@^1.0.30001164: version "1.0.30001165" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz#32955490d2f60290bb186bb754f2981917fa744f" integrity sha512-8cEsSMwXfx7lWSUMA2s08z9dIgsnR5NAqjXP23stdsU3AUWkCr/rr4s4OFtHXn5XXr6+7kam3QFVoYyXNPdJPA== capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" 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" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" has-ansi "^2.0.0" strip-ansi "^3.0.0" supports-color "^2.0.0" chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" chalk@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== charm@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" integrity sha1-it02cVOm2aWBMxBSxAkJkdqZXjU= dependencies: inherits "^2.0.1" ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== cjs-module-lexer@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" isobject "^3.0.0" static-extend "^0.1.1" cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" wrap-ansi "^2.0.0" cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^6.2.0" co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 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" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 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" 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" integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-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" 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" 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" 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" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colorette@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== 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" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" command-exists@^1.2.8: version "1.2.9" resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== commander@^2.12.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 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" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" inherits "^2.0.3" readable-stream "^2.2.2" typedarray "^0.0.6" 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" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= 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" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js-compat@^3.8.0: version "3.8.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e" integrity sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ== dependencies: browserslist "^4.15.0" semver "7.0.0" core-js@^3: version "3.8.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.1.tgz#f51523668ac8a294d1285c3b9db44025fda66d47" integrity sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg== 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" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" path-key "^2.0.1" semver "^5.5.0" shebang-command "^1.2.0" which "^1.2.9" cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" 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" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: cssom "~0.3.6" dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 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" integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: abab "^2.0.3" whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 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" 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" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 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" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== 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" 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" 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" integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== diff-sequences@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== diff-sequences@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= dependencies: esutils "^2.0.2" isarray "^1.0.0" doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== dependencies: webidl-conversions "^5.0.0" dts-critic@latest: version "3.2.4" resolved "https://registry.yarnpkg.com/dts-critic/-/dts-critic-3.2.4.tgz#88e0473d3db7eb07e14c08b9e84e7dc23ea3e2df" integrity sha512-KdW/qVKydHF8HkFBe3hNqXRIDUwSqioTOxVAUS7tbo0++vlRNq7wluCfTgi5J26bS1L4ybJvN22BBVRR5Cp2wQ== dependencies: "@definitelytyped/header-parser" "0.0.34" command-exists "^1.2.8" rimraf "^3.0.2" semver "^6.2.0" tmp "^0.2.1" yargs "^12.0.5" dtslint@^4.0.2: version "4.0.6" resolved "https://registry.yarnpkg.com/dtslint/-/dtslint-4.0.6.tgz#47a939365ff1fbbff2345b3858fb81c42e10fddd" integrity sha512-bj5EaTeAqVXDHo/ut8oTRN/hZNTVKTAsNkavyH/T7XeDU/bqrctlYJmQo2HWJzPDoNCjq6NdVgvOnmQBGmSHsg== dependencies: "@definitelytyped/header-parser" latest "@definitelytyped/typescript-versions" latest "@definitelytyped/utils" latest dts-critic latest fs-extra "^6.0.1" json-stable-stringify "^1.0.1" strip-json-comments "^2.0.1" tslint "5.14.0" yargs "^15.1.0" ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" electron-to-chromium@^1.3.591: version "1.3.603" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.603.tgz#1b71bec27fb940eccd79245f6824c63d5f7e8abf" integrity sha512-J8OHxOeJkoSLgBXfV9BHgKccgfLMHh+CoeRo6wJsi6m0k3otaxS/5vrHpMNSEYY4MISwewqanPOuhAtuE8riQQ== electron-to-chromium@^1.3.612: version "1.3.621" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.621.tgz#0bbe2100ef0b28f88d0b1101fbdf433312f69be0" integrity sha512-FeIuBzArONbAmKmZIsZIFGu/Gc9AVGlVeVbhCq+G2YIl6QkT0TDn2HKN/FMf1btXEB9kEmIuQf3/lBTVAbmFOg== emittery@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451" integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ== emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 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" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enquirer@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== dependencies: ansi-colors "^4.1.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.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" is-callable "^1.1.5" is-regex "^1.0.5" object-inspect "^1.7.0" object-keys "^1.1.1" object.assign "^4.1.0" string.prototype.trimleft "^2.1.1" string.prototype.trimright "^2.1.1" es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" is-date-object "^1.0.1" is-symbol "^1.0.2" escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.2, 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" 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" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escodegen@^1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== dependencies: esprima "^4.0.1" estraverse "^4.2.0" esutils "^2.0.2" optionator "^0.8.1" optionalDependencies: source-map "~0.6.1" eslint-config-prettier@^6.3.0: version "6.15.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== dependencies: get-stdin "^6.0.0" eslint-import-resolver-alias@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97" integrity sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w== eslint-import-resolver-node@^0.3.2, eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== dependencies: debug "^2.6.9" resolve "^1.13.1" eslint-module-utils@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== dependencies: debug "^2.6.9" pkg-dir "^2.0.0" eslint-plugin-es@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b" integrity sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng== dependencies: eslint-utils "^2.0.0" regexpp "^3.0.0" eslint-plugin-import@^2.18.2: version "2.22.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== dependencies: array-includes "^3.1.1" array.prototype.flat "^1.2.3" contains-path "^0.1.0" debug "^2.6.9" doctrine "1.5.0" eslint-import-resolver-node "^0.3.4" eslint-module-utils "^2.6.0" has "^1.0.3" minimatch "^3.0.4" object.values "^1.1.1" read-pkg-up "^2.0.0" resolve "^1.17.0" tsconfig-paths "^3.9.0" eslint-plugin-jest@^24.0.2: version "24.1.3" resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz#fa3db864f06c5623ff43485ca6c0e8fc5fe8ba0c" integrity sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" eslint-plugin-node@^11.0.0: version "11.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== dependencies: eslint-plugin-es "^3.0.0" eslint-utils "^2.0.0" ignore "^5.1.1" minimatch "^3.0.4" resolve "^1.10.1" semver "^6.1.0" eslint-plugin-prettier@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz#61e295349a65688ffac0b7808ef0a8244bdd8d40" integrity sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ== dependencies: prettier-linter-helpers "^1.0.0" eslint-scope@^5.0.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" estraverse "^4.1.1" eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== eslint@^7.4.0: version "7.15.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.15.0.tgz#eb155fb8ed0865fcf5d903f76be2e5b6cd7e0bc7" integrity sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA== dependencies: "@babel/code-frame" "^7.0.0" "@eslint/eslintrc" "^0.2.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" enquirer "^2.3.5" eslint-scope "^5.1.1" eslint-utils "^2.1.0" eslint-visitor-keys "^2.0.0" espree "^7.3.1" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^6.0.0" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" globals "^12.1.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash "^4.17.19" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" progress "^2.0.0" regexpp "^3.1.0" semver "^7.2.1" strip-ansi "^6.0.0" strip-json-comments "^3.1.0" table "^5.2.3" text-table "^0.2.0" v8-compile-cache "^2.0.3" espree@^7.3.0, espree@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.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" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== estraverse@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== estree-walker@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e" integrity sha1-va/oCVOD2EFNXcLs9MkXO225QS4= estree-walker@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== exec-sh@^0.3.2: version "0.3.4" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" 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" integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" get-stream "^4.0.0" is-stream "^1.1.0" npm-run-path "^2.0.0" p-finally "^1.0.0" signal-exit "^3.0.0" strip-eof "^1.0.0" execa@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.1.tgz#988488781f1f0238cd156f7aaede11c3e853b4c1" integrity sha512-SCjM/zlBdOK8Q5TIjOn6iEHZaPHFsMoTxXQ2nvUvtPnuohz3H2dIozSg+etNR98dGoYUp2ENSKLL/XaMmbxVgw== dependencies: cross-spawn "^7.0.0" get-stream "^5.0.0" human-signals "^1.1.1" is-stream "^2.0.0" merge-stream "^2.0.0" npm-run-path "^4.0.0" onetime "^5.1.0" signal-exit "^3.0.2" strip-final-newline "^2.0.0" exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" 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" integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" extend-shallow "^2.0.1" posix-character-classes "^0.1.0" regex-not "^1.0.0" snapdragon "^0.8.1" to-regex "^3.0.1" expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= dependencies: homedir-polyfill "^1.0.1" expect@^24.1.0: version "24.9.0" resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== dependencies: "@jest/types" "^24.9.0" ansi-styles "^3.2.0" jest-get-type "^24.9.0" jest-matcher-utils "^24.9.0" jest-message-util "^24.9.0" jest-regex-util "^24.9.0" expect@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: "@jest/types" "^26.6.2" ansi-styles "^4.0.0" jest-get-type "^26.3.0" jest-matcher-utils "^26.6.2" jest-message-util "^26.6.2" jest-regex-util "^26.0.0" extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 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" integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" expand-brackets "^2.1.4" extend-shallow "^2.0.1" fragment-cache "^0.2.1" regex-not "^1.0.0" snapdragon "^0.8.1" to-regex "^3.0.1" extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fake-xml-http-request@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.1.2.tgz#f1786720cae50bbb46273035a0173414f3e85e74" integrity sha512-HaFMBi7r+oEC9iJNpc3bvcW7Z7iLmM26hPDmlb0mFwyANSsOQAtJxbdWsXITKOzZUyMYK0zYCv3h5yDj9TsiXg== fast-deep-equal@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== fast-diff@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-glob@^3.1.1: version "3.2.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.0" merge2 "^1.3.0" micromatch "^4.0.2" picomatch "^2.2.1" 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" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fastq@^1.6.0: version "1.8.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" 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" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== dependencies: bser "2.1.1" file-entry-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== dependencies: flat-cache "^3.0.4" fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" repeat-string "^1.6.1" to-regex-range "^2.1.0" fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" find-up@^2.0.0, find-up@^2.1.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" 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" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" path-exists "^4.0.0" flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: flatted "^3.1.0" rimraf "^3.0.2" flatted@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA== for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 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" integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" mime-types "^2.1.12" fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" integrity sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" universalify "^0.1.0" fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: graceful-fs "^4.2.0" jsonfile "^4.0.0" universalify "^0.1.0" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^2.1.2, fsevents@~2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" mkdirp ">=0.5 0" rimraf "2" 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== functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" has-unicode "^2.0.0" object-assign "^4.1.0" signal-exit "^3.0.0" string-width "^1.0.1" strip-ansi "^3.0.1" wide-align "^1.1.0" 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" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" get-stream@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== dependencies: pump "^3.0.0" 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" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" glob-parent@^5.0.0, glob-parent@^5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== dependencies: is-glob "^4.0.1" glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" resolve-dir "^1.0.0" global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" ini "^1.3.4" is-windows "^1.0.1" which "^1.2.14" globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^12.1.0: version "12.4.0" resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== dependencies: type-fest "^0.8.1" globby@^11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" fast-glob "^3.1.1" ignore "^5.1.4" merge2 "^1.3.0" slash "^3.0.0" graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 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" integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== dependencies: ajv "^6.5.5" har-schema "^2.0.0" has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 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" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" integrity sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc= dependencies: is-glob "^3.0.0" has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 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" integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" isobject "^2.0.0" has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" isobject "^3.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" 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" integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" 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" homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== 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" 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" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ignore@^4.0.6: 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.1, ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== dependencies: parent-module "^1.0.0" resolve-from "^4.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" integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= inflected@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.1.0.tgz#2816ac17a570bbbc8303ca05bca8bf9b3f959687" integrity sha512-hAEKNxvHf2Iq3H60oMBHkB4wl5jn3TPF3+fXek/sRwAB5gP9xWs4r7aweSF95f99HFoz69pnZTcu8f0SIHV18w== inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@^1.3.4: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= 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" 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" 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" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-callable@^1.1.4, is-callable@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== dependencies: ci-info "^2.0.0" is-core-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.0.0.tgz#58531b70aed1db7c0e8d4eb1a0a2d1ddd64bd12d" integrity sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw== 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" 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" integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" kind-of "^5.0.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" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" kind-of "^6.0.2" is-docker@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== 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" 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" 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" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 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" 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" 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" 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" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-glob@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== dependencies: is-extglob "^2.1.1" is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" 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" 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" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" 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" 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" integrity sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw== dependencies: "@types/estree" "0.0.39" is-regex@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== dependencies: has "^1.0.3" is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 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" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== dependencies: has-symbols "^1.0.1" 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" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-valid-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" 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" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 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" 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" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 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" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== istanbul-lib-instrument@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== dependencies: "@babel/core" "^7.7.5" "@babel/parser" "^7.7.5" "@babel/template" "^7.7.4" "@babel/traverse" "^7.7.4" "@istanbuljs/schema" "^0.1.2" istanbul-lib-coverage "^3.0.0" semver "^6.3.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" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" "@istanbuljs/schema" "^0.1.2" istanbul-lib-coverage "^3.0.0" semver "^6.3.0" 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" integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: istanbul-lib-coverage "^3.0.0" make-dir "^3.0.0" supports-color "^7.1.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" integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== dependencies: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" istanbul-reports@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" jest-changed-files@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: "@jest/types" "^26.6.2" execa "^4.0.0" throat "^5.0.0" jest-cli@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: "@jest/core" "^26.6.3" "@jest/test-result" "^26.6.2" "@jest/types" "^26.6.2" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" jest-config "^26.6.3" jest-util "^26.6.2" jest-validate "^26.6.2" prompts "^2.0.1" yargs "^15.4.1" jest-config@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" "@jest/test-sequencer" "^26.6.3" "@jest/types" "^26.6.2" babel-jest "^26.6.3" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" jest-environment-jsdom "^26.6.2" jest-environment-node "^26.6.2" jest-get-type "^26.3.0" jest-jasmine2 "^26.6.3" jest-regex-util "^26.0.0" jest-resolve "^26.6.2" jest-util "^26.6.2" jest-validate "^26.6.2" micromatch "^4.0.2" pretty-format "^26.6.2" jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== dependencies: chalk "^2.0.1" diff-sequences "^24.9.0" jest-get-type "^24.9.0" pretty-format "^24.9.0" jest-diff@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: chalk "^4.0.0" diff-sequences "^26.6.2" jest-get-type "^26.3.0" pretty-format "^26.6.2" jest-docblock@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" jest-each@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: "@jest/types" "^26.6.2" chalk "^4.0.0" jest-get-type "^26.3.0" jest-util "^26.6.2" pretty-format "^26.6.2" jest-environment-jsdom@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== dependencies: "@jest/environment" "^26.6.2" "@jest/fake-timers" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" jest-mock "^26.6.2" jest-util "^26.6.2" jsdom "^16.4.0" jest-environment-node@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== dependencies: "@jest/environment" "^26.6.2" "@jest/fake-timers" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" jest-mock "^26.6.2" jest-util "^26.6.2" jest-extended@^0.11.2: version "0.11.5" resolved "https://registry.yarnpkg.com/jest-extended/-/jest-extended-0.11.5.tgz#f063b3f1eaadad8d7c13a01f0dfe0f538d498ccf" integrity sha512-3RsdFpLWKScpsLD6hJuyr/tV5iFOrw7v6YjA3tPdda9sJwoHwcMROws5gwiIZfcwhHlJRwFJB2OUvGmF3evV/Q== dependencies: expect "^24.1.0" jest-get-type "^22.4.3" jest-matcher-utils "^22.0.0" jest-get-type@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" integrity sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== jest-get-type@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== jest-haste-map@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: "@jest/types" "^26.6.2" "@types/graceful-fs" "^4.1.2" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.4" jest-regex-util "^26.0.0" jest-serializer "^26.6.2" jest-util "^26.6.2" jest-worker "^26.6.2" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" optionalDependencies: fsevents "^2.1.2" jest-jasmine2@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" "@jest/environment" "^26.6.2" "@jest/source-map" "^26.6.2" "@jest/test-result" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" expect "^26.6.2" is-generator-fn "^2.0.0" jest-each "^26.6.2" jest-matcher-utils "^26.6.2" jest-message-util "^26.6.2" jest-runtime "^26.6.3" jest-snapshot "^26.6.2" jest-util "^26.6.2" pretty-format "^26.6.2" throat "^5.0.0" jest-leak-detector@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: jest-get-type "^26.3.0" pretty-format "^26.6.2" jest-matcher-utils@^22.0.0: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff" integrity sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA== dependencies: chalk "^2.0.1" jest-get-type "^22.4.3" pretty-format "^22.4.3" jest-matcher-utils@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== dependencies: chalk "^2.0.1" jest-diff "^24.9.0" jest-get-type "^24.9.0" pretty-format "^24.9.0" jest-matcher-utils@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: chalk "^4.0.0" jest-diff "^26.6.2" jest-get-type "^26.3.0" pretty-format "^26.6.2" jest-message-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== dependencies: "@babel/code-frame" "^7.0.0" "@jest/test-result" "^24.9.0" "@jest/types" "^24.9.0" "@types/stack-utils" "^1.0.1" chalk "^2.0.1" micromatch "^3.1.10" slash "^2.0.0" stack-utils "^1.0.1" jest-message-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" "@jest/types" "^26.6.2" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.4" micromatch "^4.0.2" pretty-format "^26.6.2" slash "^3.0.0" stack-utils "^2.0.2" jest-mock@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: "@jest/types" "^26.6.2" "@types/node" "*" jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== 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" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== jest-resolve-dependencies@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: "@jest/types" "^26.6.2" jest-regex-util "^26.0.0" jest-snapshot "^26.6.2" jest-resolve@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: "@jest/types" "^26.6.2" chalk "^4.0.0" graceful-fs "^4.2.4" jest-pnp-resolver "^1.2.2" jest-util "^26.6.2" read-pkg-up "^7.0.1" resolve "^1.18.1" slash "^3.0.0" jest-runner@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: "@jest/console" "^26.6.2" "@jest/environment" "^26.6.2" "@jest/test-result" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" chalk "^4.0.0" emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" jest-config "^26.6.3" jest-docblock "^26.0.0" jest-haste-map "^26.6.2" jest-leak-detector "^26.6.2" jest-message-util "^26.6.2" jest-resolve "^26.6.2" jest-runtime "^26.6.3" jest-util "^26.6.2" jest-worker "^26.6.2" source-map-support "^0.5.6" throat "^5.0.0" jest-runtime@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== dependencies: "@jest/console" "^26.6.2" "@jest/environment" "^26.6.2" "@jest/fake-timers" "^26.6.2" "@jest/globals" "^26.6.2" "@jest/source-map" "^26.6.2" "@jest/test-result" "^26.6.2" "@jest/transform" "^26.6.2" "@jest/types" "^26.6.2" "@types/yargs" "^15.0.0" chalk "^4.0.0" cjs-module-lexer "^0.6.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" jest-config "^26.6.3" jest-haste-map "^26.6.2" jest-message-util "^26.6.2" jest-mock "^26.6.2" jest-regex-util "^26.0.0" jest-resolve "^26.6.2" jest-snapshot "^26.6.2" jest-util "^26.6.2" jest-validate "^26.6.2" slash "^3.0.0" strip-bom "^4.0.0" yargs "^15.4.1" jest-serializer@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== dependencies: "@types/node" "*" graceful-fs "^4.2.4" jest-snapshot@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" "@jest/types" "^26.6.2" "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.0.0" chalk "^4.0.0" expect "^26.6.2" graceful-fs "^4.2.4" jest-diff "^26.6.2" jest-get-type "^26.3.0" jest-haste-map "^26.6.2" jest-matcher-utils "^26.6.2" jest-message-util "^26.6.2" jest-resolve "^26.6.2" natural-compare "^1.4.0" pretty-format "^26.6.2" semver "^7.3.2" jest-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: "@jest/types" "^26.6.2" "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^2.0.0" micromatch "^4.0.2" jest-validate@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: "@jest/types" "^26.6.2" camelcase "^6.0.0" chalk "^4.0.0" jest-get-type "^26.3.0" leven "^3.1.0" pretty-format "^26.6.2" jest-watcher@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: "@jest/test-result" "^26.6.2" "@jest/types" "^26.6.2" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" jest-util "^26.6.2" string-length "^4.0.1" jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" jest@^26.0.1: version "26.6.3" resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== dependencies: "@jest/core" "^26.6.3" import-local "^3.0.2" jest-cli "^26.6.3" js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1, js-yaml@^3.7.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== dependencies: argparse "^1.0.7" esprima "^4.0.0" jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsdom@^16.4.0: version "16.4.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== dependencies: abab "^2.0.3" acorn "^7.1.1" acorn-globals "^6.0.0" cssom "^0.4.4" cssstyle "^2.2.0" data-urls "^2.0.0" decimal.js "^10.2.0" domexception "^2.0.1" escodegen "^1.14.1" html-encoding-sniffer "^2.0.1" is-potential-custom-element-name "^1.0.0" nwsapi "^2.2.0" parse5 "5.1.1" request "^2.88.2" request-promise-native "^1.0.8" saxes "^5.0.0" symbol-tree "^3.2.4" tough-cookie "^3.0.1" w3c-hr-time "^1.0.2" w3c-xmlserializer "^2.0.0" webidl-conversions "^6.1.0" whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" ws "^7.2.3" xml-name-validator "^3.0.0" jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" 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" 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" 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" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= dependencies: jsonify "~0.0.0" 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" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== dependencies: minimist "^1.2.0" json5@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== dependencies: minimist "^1.2.5" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" json-schema "0.2.3" verror "1.10.0" 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" 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" 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" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== 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" 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" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== dependencies: invert-kv "^2.0.0" leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" type-check "~0.4.0" levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" 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" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" pify "^2.0.0" strip-bom "^3.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" 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" integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" path-exists "^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" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= 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.compact@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5" integrity sha1-VAzjg3dFl1gHRx4WtKK6IeclbKU= lodash.find@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= lodash.forin@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.forin/-/lodash.forin-4.4.0.tgz#5d3f20ae564011fbe88381f7d98949c9c9519731" integrity sha1-XT8grlZAEfvog4H32YlJyclRlzE= 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.has@^4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= lodash.invokemap@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62" integrity sha1-F0jNpdiw74NpxOs+xUwh/rofLWI= lodash.isempty@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4= lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= lodash.isfunction@^3.0.9: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== lodash.isinteger@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= lodash.lowerfirst@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/lodash.lowerfirst/-/lodash.lowerfirst-4.3.1.tgz#de3c7b12e02c6524a0059c2f6cb7c5c52655a13d" integrity sha1-3jx7EuAsZSSgBZwvbLfFxSZVoT0= lodash.map@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= lodash.mapvalues@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw= lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= lodash.snakecase@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= 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.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= lodash.values@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c= lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== magic-string@^0.22.0: version "0.22.5" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e" integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w== dependencies: vlq "^0.2.2" magic-string@^0.25.2: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: sourcemap-codec "^1.4.4" 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" makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-age-cleaner@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== dependencies: p-defer "^1.0.0" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" matched@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/matched/-/matched-1.0.2.tgz#1d95d77dd5f1b5075a9e94acde5462ffd85f317a" integrity sha512-7ivM1jFZVTOOS77QsR+TtYHH0ecdLclMkqbf5qiJdX2RorqfhsL65QHySPZgDE0ZjHoh+mQUNHTanNXIlzXd0Q== dependencies: arr-union "^3.1.0" async-array-reduce "^0.2.1" glob "^7.1.2" has-glob "^1.0.0" is-valid-glob "^1.0.0" resolve-dir "^1.0.0" mem@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== dependencies: map-age-cleaner "^0.1.1" mimic-fn "^2.0.0" p-is-promise "^2.0.0" memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" braces "^2.3.1" define-property "^2.0.2" extend-shallow "^3.0.2" extglob "^2.0.4" fragment-cache "^0.2.1" kind-of "^6.0.2" nanomatch "^1.2.9" object.pick "^1.3.0" regex-not "^1.0.0" snapdragon "^0.8.1" to-regex "^3.0.2" micromatch@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== dependencies: braces "^3.0.1" picomatch "^2.0.5" mime-db@1.44.0: version "1.44.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" 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" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== dependencies: mime-db "1.44.0" mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.3: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== dependencies: minimist "^1.2.5" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" define-property "^2.0.2" extend-shallow "^3.0.2" fragment-cache "^0.2.1" is-windows "^1.0.2" kind-of "^6.0.2" object.pick "^1.3.0" regex-not "^1.0.0" snapdragon "^0.8.1" to-regex "^3.0.1" natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= 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" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== dependencies: growly "^1.3.0" is-wsl "^2.2.0" semver "^7.3.2" shellwords "^0.1.1" uuid "^8.3.0" which "^2.0.2" node-releases@^1.1.66, node-releases@^1.1.67: version "1.1.67" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg== normalize-package-data@^2.3.2, normalize-package-data@^2.5.0, "normalize-package-data@~1.0.1 || ^2.0.0": version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" resolve "^1.10.0" semver "2 || 3 || 4 || 5" 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" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== "npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.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-registry-client@^8.6.0: version "8.6.0" resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" integrity sha512-Qs6P6nnopig+Y8gbzpeN/dkt+n7IyVd8f45NTMotGk6Qo7GfBmzwYx6jRLoOOgKiMnaQfYxsuyQlD8Mc3guBhg== dependencies: concat-stream "^1.5.2" graceful-fs "^4.1.6" normalize-package-data "~1.0.1 || ^2.0.0" npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" once "^1.3.3" request "^2.74.0" retry "^0.10.0" safe-buffer "^5.1.1" semver "2 >=2.2.1 || 3.x || 4 || 5" slide "^1.1.3" ssri "^5.2.4" optionalDependencies: npmlog "2 || ^3.1.0 || ^4.0.0" npm-run-all@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== dependencies: ansi-styles "^3.2.1" chalk "^2.4.1" cross-spawn "^6.0.5" memorystream "^0.3.1" minimatch "^3.0.4" pidtree "^0.3.0" read-pkg "^3.0.0" shell-quote "^1.6.1" string.prototype.padend "^3.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" integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" "npmlog@2 || ^3.1.0 || ^4.0.0": version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" gauge "~2.7.3" set-blocking "~2.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" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" 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" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 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" integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== object-keys@^1.0.11, 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" integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== dependencies: define-properties "^1.1.2" function-bind "^1.1.1" has-symbols "^1.0.0" object-keys "^1.0.11" object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" object.values@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== dependencies: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" function-bind "^1.1.1" has "^1.0.3" once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== dependencies: mimic-fn "^2.1.0" optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.6" levn "~0.3.0" prelude-ls "~1.1.2" type-check "~0.3.2" word-wrap "~1.2.3" optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" word-wrap "^1.2.3" os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-locale@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== dependencies: execa "^1.0.0" lcid "^2.0.0" mem "^4.0.0" os-tmpdir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= 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" 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" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-is-promise@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== 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" 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" 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" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.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" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" 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.1.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ== dependencies: "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= parse5@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== parsimmon@^1.13.0: version "1.13.0" resolved "https://registry.yarnpkg.com/parsimmon/-/parsimmon-1.13.0.tgz#6e4ef3dbd45ed6ea6808be600ac4b9c8a44228cf" integrity sha512-5UIrOCW+gjbILkjKPgTgmq8LKf8TT3Iy7kN2VD7OtQ81facKn8B4gG1X94jWqXYZsxG2KbJhrv/Yq/5H6BQn7A== pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 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" 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" 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" 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" 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" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^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" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== pidtree@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== pify@^2.0.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= pirates@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/pirates/-/pirates-3.0.2.tgz#7e6f85413fd9161ab4e12b539b06010d85954bb9" integrity sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q== dependencies: node-modules-regexp "^1.0.0" pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: node-modules-regexp "^1.0.0" pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= dependencies: find-up "^2.1.0" pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" 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" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= pretender@^3.4.7: version "3.4.7" resolved "https://registry.yarnpkg.com/pretender/-/pretender-3.4.7.tgz#34a2ae2d1fc9db440a990d50e6c0f5481d8755fc" integrity sha512-jkPAvt1BfRi0RKamweJdEcnjkeu7Es8yix3bJ+KgBC5VpG/Ln4JE3hYN6vJym4qprm8Xo5adhWpm3HCoft1dOw== dependencies: fake-xml-http-request "^2.1.2" route-recognizer "^0.3.3" prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prettier@^2.0.2: version "2.2.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== pretty-format@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" integrity sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ== dependencies: ansi-regex "^3.0.0" ansi-styles "^3.2.0" pretty-format@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== dependencies: "@jest/types" "^24.9.0" ansi-regex "^4.0.0" ansi-styles "^3.2.0" react-is "^16.8.4" pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== dependencies: "@jest/types" "^26.6.2" ansi-regex "^5.0.0" ansi-styles "^4.0.0" react-is "^17.0.1" private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== 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" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== prompts@^2.0.1: version "2.3.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== dependencies: kleur "^3.0.3" sisteransi "^1.0.4" psl@^1.1.28: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" once "^1.3.1" punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== react-is@^17.0.1: version "17.0.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= dependencies: find-up "^2.0.0" read-pkg "^2.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" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" read-pkg "^5.2.0" type-fest "^0.8.1" read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" path-type "^2.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" 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" readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~2.0.0" safe-buffer "~5.1.1" string_decoder "~1.1.1" util-deprecate "~1.0.1" regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== dependencies: regenerate "^1.4.0" regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.13.4: version "0.13.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== regenerator-transform@^0.14.2: version "0.14.4" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== dependencies: "@babel/runtime" "^7.8.4" private "^0.1.8" 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" integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== regexpu-core@^4.7.1: version "4.7.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== dependencies: regenerate "^1.4.0" regenerate-unicode-properties "^8.2.0" regjsgen "^0.5.1" regjsparser "^0.6.4" unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.2.0" regjsgen@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== regjsparser@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== dependencies: jsesc "~0.5.0" 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" 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" 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" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= 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" 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" 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.74.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" caseless "~0.12.0" combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" form-data "~2.3.2" har-validator "~5.1.3" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" oauth-sign "~0.9.0" performance-now "^2.1.0" qs "~6.5.2" safe-buffer "^5.1.2" tough-cookie "~2.5.0" tunnel-agent "^0.6.0" uuid "^3.3.2" require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 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" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-dir@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 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" 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" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.3.2: version "1.18.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== dependencies: is-core-module "^2.0.0" path-parse "^1.0.6" ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 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= reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@2: 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.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" rollup-plugin-alias@^2.0.1: version "2.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-alias/-/rollup-plugin-alias-2.2.0.tgz#5004a2bc542a2eebb45b5a0fff8c6f540439decc" integrity sha512-9ZK410qeFed4gGrHoojBpxLsHF74vPgsheGg9JRW5RbALAxqdvJbd357mSqWBqUrBfRVnZnNUXTZdYLxxQEA5A== dependencies: slash "^3.0.0" rollup-plugin-async@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-async/-/rollup-plugin-async-1.2.0.tgz#f95fdd29f8b6f2332b5a89a9d64ee8087b12b249" integrity sha1-+V/dKfi28jMrWomp1k7oCHsSskk= dependencies: async-to-gen "^1.2.0" rollup-pluginutils "^1.5.1" rollup-plugin-babel@^4.3.3: version "4.4.0" resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz#d15bd259466a9d1accbdb2fe2fff17c52d030acb" integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw== dependencies: "@babel/helper-module-imports" "^7.0.0" rollup-pluginutils "^2.8.1" rollup-plugin-commonjs@^10.0.1: version "10.1.0" resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb" integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q== dependencies: estree-walker "^0.6.1" is-reference "^1.1.2" magic-string "^0.25.2" resolve "^1.11.0" rollup-pluginutils "^2.8.1" rollup-plugin-multi-entry@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/rollup-plugin-multi-entry/-/rollup-plugin-multi-entry-2.1.0.tgz#64a7287adfd437cab33bf6364a8d8ab1e7a7725d" integrity sha512-YVVsI15uvbxMKdeYS5NXQa5zbVr/DYdDBBwseC80+KAc7mqDUjM6Qe4wl+jFucVw1yvBDZFk0PPSBZqoLq8xUA== dependencies: matched "^1.0.2" rollup-plugin-node-resolve@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523" integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw== dependencies: "@types/resolve" "0.0.8" builtin-modules "^3.1.0" is-module "^1.0.0" resolve "^1.11.1" rollup-pluginutils "^2.8.1" rollup-pluginutils@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" integrity sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg= dependencies: estree-walker "^0.2.1" minimatch "^3.0.2" rollup-pluginutils@^2.8.1: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== dependencies: estree-walker "^0.6.1" rollup@^2.3.2: version "2.35.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c" integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA== optionalDependencies: fsevents "~2.1.2" route-recognizer@^0.3.3: version "0.3.4" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3" integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g== rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== run-parallel@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: 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: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", 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" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: "@cnakazawa/watch" "^1.0.3" anymatch "^2.0.0" capture-exit "^2.0.0" exec-sh "^0.3.2" execa "^1.0.0" fb-watchman "^2.0.0" micromatch "^3.1.4" minimist "^1.1.1" walker "~1.0.5" saxes@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" "semver@2 >=2.2.1 || 3.x || 4 || 5", "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" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== 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" 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" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" is-plain-object "^2.0.3" split-string "^3.0.1" shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 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" 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" 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" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.6.1: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== sisteransi@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== 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" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== dependencies: ansi-styles "^3.2.0" astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" slide@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" snapdragon-util "^3.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" 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" integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" define-property "^0.2.5" extend-shallow "^2.0.1" map-cache "^0.2.2" source-map "^0.5.6" source-map-resolve "^0.5.0" use "^3.1.0" 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" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" 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" 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" 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" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== sourcemap-codec@^1.4.4: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== spdx-correct@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^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" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^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" integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== 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" integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" bcrypt-pbkdf "^1.0.0" dashdash "^1.12.0" ecc-jsbn "~0.1.1" getpass "^0.1.1" jsbn "~0.1.0" safer-buffer "^2.0.2" tweetnacl "~0.14.0" ssri@^5.2.4: version "5.3.0" resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== dependencies: safe-buffer "^5.1.1" stack-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== stack-utils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" 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" integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= string-length@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== dependencies: char-regex "^1.0.2" strip-ansi "^6.0.0" string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 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.0.0, string-width@^2.1.1: 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: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== dependencies: emoji-regex "^7.0.1" is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" string.prototype.padend@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3" integrity sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA== dependencies: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" string.prototype.trimend@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== dependencies: define-properties "^1.1.3" es-abstract "^1.17.5" string.prototype.trimleft@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== dependencies: define-properties "^1.1.3" es-abstract "^1.17.5" string.prototype.trimstart "^1.0.0" string.prototype.trimright@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== dependencies: define-properties "^1.1.3" es-abstract "^1.17.5" string.prototype.trimend "^1.0.0" string.prototype.trimstart@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== dependencies: define-properties "^1.1.3" es-abstract "^1.17.5" string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.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" 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.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 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" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== dependencies: ansi-regex "^5.0.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" 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" 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" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== 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" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 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" 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" integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== dependencies: ajv "^6.10.2" lodash "^4.17.14" slice-ansi "^2.1.0" string-width "^3.0.0" tar-stream@1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: bl "^1.0.0" buffer-alloc "^1.2.0" end-of-stream "^1.0.0" fs-constants "^1.0.0" readable-stream "^2.3.0" to-buffer "^1.1.1" xtend "^4.0.0" tar@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== dependencies: block-stream "*" fstream "^1.0.12" inherits "2" terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== dependencies: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" glob "^7.1.4" minimatch "^3.0.4" text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== tmp@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== dependencies: rimraf "^3.0.0" tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= to-buffer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== 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" 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" 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" integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" 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" 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" integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" regex-not "^1.0.2" safe-regex "^1.1.0" 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" integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: psl "^1.1.28" punycode "^2.1.1" tough-cookie@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== dependencies: ip-regex "^2.1.0" psl "^1.1.28" punycode "^2.1.1" tr46@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== dependencies: punycode "^2.1.1" tsconfig-paths@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" minimist "^1.2.0" strip-bom "^3.0.0" tslib@^1.13.0, tslib@^1.8.0, tslib@^1.8.1: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== 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" integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== tslint@5.14.0: version "5.14.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.14.0.tgz#be62637135ac244fc9b37ed6ea5252c9eba1616e" integrity sha512-IUla/ieHVnB8Le7LdQFRGlVJid2T/gaJe5VkjzRVSRR6pA2ODYrnfR1hmxi+5+au9l50jBwpbBL34txgv4NnTQ== dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" chalk "^2.3.0" commander "^2.12.1" diff "^3.2.0" glob "^7.1.1" js-yaml "^3.7.0" minimatch "^3.0.4" mkdirp "^0.5.1" resolve "^1.3.2" semver "^5.3.0" tslib "^1.8.0" tsutils "^2.29.0" tslint@^6.1.1: version "6.1.3" resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== dependencies: "@babel/code-frame" "^7.0.0" builtin-modules "^1.1.1" chalk "^2.3.0" commander "^2.12.1" diff "^4.0.1" glob "^7.1.1" js-yaml "^3.13.1" minimatch "^3.0.4" mkdirp "^0.5.3" resolve "^1.3.2" semver "^5.3.0" tslib "^1.13.0" tsutils "^2.29.0" tsutils@^2.29.0: version "2.29.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== dependencies: tslib "^1.8.1" tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== dependencies: tslib "^1.8.1" tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 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" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 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" 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" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" 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" 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" 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" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^4.0.3: version "4.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== unicode-match-property-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== dependencies: unicode-canonical-property-names-ecmascript "^1.0.4" unicode-property-aliases-ecmascript "^1.0.4" unicode-match-property-value-ecmascript@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== unicode-property-aliases-ecmascript@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" get-value "^2.0.6" is-extendable "^0.1.1" set-value "^2.0.1" universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 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" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== v8-compile-cache@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== v8-to-istanbul@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz#b4fe00e35649ef7785a9b7fcebcea05f37c332fc" integrity sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA== 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: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" 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" integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" extsprintf "^1.2.0" vlq@^0.2.2: version "0.2.3" resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== 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" 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" 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" integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== webidl-conversions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" 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" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== whatwg-url@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.1.0.tgz#c628acdcf45b82274ce7281ee31dd3c839791771" integrity sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw== dependencies: lodash.sortby "^4.7.0" tr46 "^2.0.2" webidl-conversions "^5.0.0" which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= which@^1.2.14, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 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" 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" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 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" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: imurmurhash "^0.1.4" is-typedarray "^1.0.0" signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" ws@^7.2.3: version "7.3.0" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== 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" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" yargs@^12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== dependencies: cliui "^4.0.0" decamelize "^1.2.0" find-up "^3.0.0" get-caller-file "^1.0.1" os-locale "^3.0.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" string-width "^2.0.0" which-module "^2.0.0" y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" yargs@^15.1.0, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" decamelize "^1.2.0" find-up "^4.1.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 "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^18.1.2"