From 07fb9158eed685c85977c5a929c79b08caba5991 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Wed, 20 Feb 2019 18:49:47 +0000 Subject: [PATCH 1/9] Installed jest and added one test file --- .eslintrc | 6 +- package.json | 10 +- src/inputs/MidiInput.js | 2 +- .../_test/processMidiMessage.test.js | 117 +++ src/utils/midiMessage/index.js | 43 + src/utils/processMidiMessage/index.js | 35 - yarn.lock | 920 +++++++++++++++++- 7 files changed, 1070 insertions(+), 63 deletions(-) create mode 100644 src/utils/midiMessage/_test/processMidiMessage.test.js create mode 100644 src/utils/midiMessage/index.js delete mode 100644 src/utils/processMidiMessage/index.js diff --git a/.eslintrc b/.eslintrc index 34d1b2f0..82787e16 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,8 +5,12 @@ "standard-react" ], "env": { - "browser" : true + "browser" : true, + "jest/globals": true }, + "plugins": [ + "jest" + ], "rules": { "key-spacing" : 0, "jsx-quotes" : [2, "prefer-single"], diff --git a/package.json b/package.json index f6f74d63..5497b97a 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,9 @@ "lint": "eslint src config example-projects mockTests", "lint:css": "stylelint \"src/components/**/*.js\"", "lint:fix": "yarn lint -- --fix", - "test": "yarn lint && cross-env NODE_ENV=test tape-watch --once -r @babel/register src/**/*.spec.js mockTests/**/*.spec.js -p tap-diff", + "test": "yarn lint && yarn jest && cross-env NODE_ENV=test tape-watch --once -r @babel/register src/**/*.spec.js mockTests/**/*.spec.js -p tap-diff", "test:dev": "cross-env NODE_ENV=test tape-watch -r @babel/register src/**/*.spec.js mockTests/**/*.spec.js -p tap-diff", + "test-jest": "yarn jest --watch", "compile": "electron-webpack", "dist": "yarn compile && electron-builder", "dist:dev": "yarn dist -- --dir -c.compression=store -c.mac.identity=null && open dist/mac/hedron.app/ --args --distDev", @@ -35,6 +36,11 @@ "glslify-import" ] }, + "jest": { + "testMatch": [ + "**/?(*.)+(test).[jt]s?(x)" + ] + }, "dependencies": { "@babel/core": "^7.2.2", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", @@ -110,9 +116,11 @@ "eslint-config-standard": "^6.2.1", "eslint-config-standard-react": "^4.2.0", "eslint-plugin-babel": "^4.0.1", + "eslint-plugin-jest": "^22.3.0", "eslint-plugin-promise": "^3.4.1", "eslint-plugin-react": "^6.10.0", "eslint-plugin-standard": "^2.0.1", + "jest": "^24.1.0", "jsdom": "^11.5.1", "jsdom-global": "^3.0.2", "minimist": "^1.2.0", diff --git a/src/inputs/MidiInput.js b/src/inputs/MidiInput.js index 1ff8abf1..61901d0b 100644 --- a/src/inputs/MidiInput.js +++ b/src/inputs/MidiInput.js @@ -3,7 +3,7 @@ import { midiStopLearning, midiUpdateDevices, midiMessage } from '../store/midi/ import { uInputLinkCreate } from '../store/inputLinks/actions' import { clockPulse } from '../store/clock/actions' import { newData as teachMidi } from '../utils/getMidiMode' -import processMidiMessage from '../utils/processMidiMessage' +import { processMidiMessage } from '../utils/midiMessage' export default (store) => { const onMessage = (rawMessage) => { diff --git a/src/utils/midiMessage/_test/processMidiMessage.test.js b/src/utils/midiMessage/_test/processMidiMessage.test.js new file mode 100644 index 00000000..3bf62ddd --- /dev/null +++ b/src/utils/midiMessage/_test/processMidiMessage.test.js @@ -0,0 +1,117 @@ +const { processMidiMessage } = require('../') + +test('Returns correct value as a number between 0 and 1', () => { + let message, expected, actual + + message = { + data: [0, 0, 127], + } + + expected = 1 + actual = processMidiMessage(message).value + + expect(actual).toBe(expected) + + message = { + data: [0, 0, 0], + } + + expected = 0 + actual = processMidiMessage(message).value + + expect(actual).toBe(expected) +}) + +test('Returns correct type', () => { + let message, expected, actual + + message = { + data: [176, 0, 0], + } + + expected = 'controlChange' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) + + message = { + data: [180, 0, 0], + } + + expected = 'controlChange' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) + + message = { + data: [144, 0, 1], + } + + expected = 'noteOn' + actual = processMidiMessage(message).type + + message = { + data: [147, 0, 1], + } + + expected = 'noteOn' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) + + message = { + data: [144, 0, 0], // If last value is 0, it becomes a noteOff + } + + expected = 'noteOff' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) + + message = { + data: [128, 0, 1], + } + + expected = 'noteOff' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) + + message = { + data: [248, 0, 1], + } + + expected = 'timingClock' + actual = processMidiMessage(message).type + + expect(actual).toBe(expected) +}) + +test('Returns id as a concatination of the first two vals', () => { + let message, expected, actual + + message = { + data: [176, 100, 0], + } + + expected = 'midi_176_100' + actual = processMidiMessage(message).id + + expect(actual).toBe(expected) + + message = { + data: [88, 0, 0], + } + + expected = 'midi_88_0' + actual = processMidiMessage(message).id + + message = { + data: [8, 80, 0], + } + + expected = 'midi_8_80' + actual = processMidiMessage(message).id + + expect(actual).toBe(expected) +}) diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js new file mode 100644 index 00000000..927bd3ad --- /dev/null +++ b/src/utils/midiMessage/index.js @@ -0,0 +1,43 @@ +export const processMidiMessage = message => { + let value, type, id + + const d0 = message.data[0] + const d1 = message.data[1] + const d2 = message.data[2] + + // Erase the first bit as this relates to channel + const code = d0 & 0xf0 + + switch (code) { + case 0x80: + type = 'noteOff' + break + case 0x90: + type = d2 === 0 ? 'noteOff' : 'noteOn' + break + case 0xA0: + type = 'polyPressure' + break + case 0xB0: + type = 'controlChange' + break + case 0xC0: + type = 'programChange' + break + default: + if (d0 === 248) type = 'timingClock' + break + } + + if (d2 !== undefined) { + value = d2 / 127 + } + + if (d0 !== undefined && d1 !== undefined) { + id = `midi_${d0}_${d1}` + } + + return { + value, id, type, + } +} diff --git a/src/utils/processMidiMessage/index.js b/src/utils/processMidiMessage/index.js deleted file mode 100644 index d2aa3d16..00000000 --- a/src/utils/processMidiMessage/index.js +++ /dev/null @@ -1,35 +0,0 @@ -export default message => { - let value, type, id - - const d0 = message.data[0] - const d1 = message.data[1] - const d2 = message.data[2] - - if (d0 >= 128 && d0 < 144 || - d0 >= 144 && d0 < 160 && d2 === 0 - ) { - type = 'noteOff' - } else if (d0 >= 144 && d0 < 160) { - type = 'noteOn' - } else if (d0 >= 160 && d0 < 176) { - type = 'polyPressure' - } else if (d0 >= 176 && d0 < 192) { - type = 'controlChange' - } else if (d0 >= 192 && d0 < 208) { - type = 'programChange' - } else if (d0 === 248) { - type = 'timingClock' - } - - if (d2 !== undefined) { - value = d2 / 127 - } - - if (d0 !== undefined && d1 !== undefined) { - id = 'midi_' + d0.toString() + d1.toString() - } - - return { - value, id, type, - } -} diff --git a/yarn.lock b/yarn.lock index 76b73e37..f94cd375 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,6 +25,26 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/core@^7.1.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" + integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.3.3" + "@babel/helpers" "^7.2.0" + "@babel/parser" "^7.3.3" + "@babel/template" "^7.2.2" + "@babel/traverse" "^7.2.2" + "@babel/types" "^7.3.3" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" @@ -56,6 +76,17 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.0.0", "@babel/generator@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" + integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A== + dependencies: + "@babel/types" "^7.3.3" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/generator@^7.2.2": version "7.3.2" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.2.tgz#fff31a7b2f2f3dad23ef8e01be45b0d5c2fc0132" @@ -299,6 +330,11 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.0.0", "@babel/parser@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" + integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg== + "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": version "7.3.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.2.tgz#95cdeddfc3992a6ca2a1315191c1679ca32c55cd" @@ -443,7 +479,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.2.0": +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== @@ -809,7 +845,7 @@ babylon "7.0.0-beta.44" lodash "^4.2.0" -"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== @@ -834,7 +870,7 @@ invariant "^2.2.0" lodash "^4.2.0" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== @@ -885,6 +921,15 @@ lodash "^4.17.10" to-fast-properties "^2.0.0" +"@babel/types@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" + integrity sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@emotion/is-prop-valid@^0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc" @@ -1234,6 +1279,11 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -1251,6 +1301,11 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -1259,7 +1314,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0, ansi-styles@^3.2.1: +ansi-styles@^3.1.0, 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== @@ -1316,6 +1371,13 @@ app-builder-lib@20.38.5, app-builder-lib@~20.38.5: semver "^5.6.0" temp-file "^3.3.2" +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== + dependencies: + default-require-extensions "^2.0.0" + aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -1420,7 +1482,7 @@ array.prototype.find@^2.0.1: define-properties "^1.1.2" es-abstract "^1.7.0" -arrify@^1.0.0: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -1463,6 +1525,11 @@ assign-symbols@^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-each@^1.0.0, async-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -1476,6 +1543,13 @@ async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" +async@^2.5.0, async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1543,6 +1617,16 @@ babel-eslint@8.2.6: eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" +babel-jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.1.0.tgz#441e23ef75ded3bd547e300ac3194cef87b55190" + integrity sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw== + dependencies: + babel-plugin-istanbul "^5.1.0" + babel-preset-jest "^24.1.0" + chalk "^2.4.2" + slash "^2.0.0" + babel-loader@^8.0.5: version "8.0.5" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.5.tgz#225322d7509c2157655840bba52e46b6c2f2fe33" @@ -1566,6 +1650,20 @@ babel-plugin-component@^1.1.1: dependencies: "@babel/helper-module-imports" "7.0.0-beta.35" +babel-plugin-istanbul@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz#7981590f1956d75d67630ba46f0c22493588c893" + integrity sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ== + dependencies: + find-up "^3.0.0" + istanbul-lib-instrument "^3.0.0" + test-exclude "^5.0.0" + +babel-plugin-jest-hoist@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz#dfecc491fb15e2668abbd690a697a8fd1411a7f8" + integrity sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw== + "babel-plugin-styled-components@>= 1", babel-plugin-styled-components@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.0.tgz#ff1f42ad2cc78c21f26b62266b8f564dbc862939" @@ -1580,6 +1678,14 @@ babel-plugin-syntax-jsx@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" +babel-preset-jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz#83bc564fdcd4903641af65ec63f2f5de6b04132e" + integrity sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw== + dependencies: + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + babel-plugin-jest-hoist "^24.1.0" + babel-runtime@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611" @@ -1825,6 +1931,13 @@ browser-process-hrtime@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" @@ -1892,6 +2005,13 @@ browserslist@^4.3.4: electron-to-chromium "^1.3.103" node-releases "^1.1.3" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= + 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" @@ -2027,6 +2147,11 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +callsites@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" + integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== + camel-case@3.0.x: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -2079,6 +2204,13 @@ caniuse-lite@^1.0.30000929: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000935.tgz#d1b59df00b46f4921bb84a8a34c1d172b346df59" integrity sha512-1Y2uJ5y56qDt3jsDTdBHL1OqiImzjoQcBG6Yl3Qizq8mcc2SgCFpi+ZwLLqkztYnk9l87IYqRlNBnPSOTbFkXQ== +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= + dependencies: + rsvp "^3.3.3" + capture-stack-trace@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" @@ -2436,6 +2568,11 @@ compare-version@^0.1.2: resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" integrity sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA= +compare-versions@^3.2.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" + integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== + component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -2538,7 +2675,7 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.1.0: +convert-source-map@^1.1.0, convert-source-map@^1.4.0: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== @@ -3057,6 +3194,13 @@ default-gateway@^2.6.0: execa "^0.10.0" ip-regex "^2.1.0" +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= + dependencies: + strip-bom "^3.0.0" + 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" @@ -3149,11 +3293,21 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== +diff-sequences@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.0.0.tgz#cdf8e27ed20d8b8d3caccb4e0c0d8fe31a173013" + integrity sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw== + diff@^2.2.1: version "2.2.3" resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99" @@ -3604,7 +3758,7 @@ errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.2.0: +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== @@ -3767,6 +3921,11 @@ eslint-plugin-babel@^4.0.1: version "4.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz#79202a0e35757dd92780919b2336f1fa2fe53c1e" +eslint-plugin-jest@^22.3.0: + version "22.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.3.0.tgz#a10f10dedfc92def774ec9bb5bfbd2fb8e1c96d2" + integrity sha512-P1mYVRNlOEoO5T9yTqOfucjOYf1ktmJ26NjwjH8sxpCFQa6IhBGr5TpKl3hcAAT29hOsRJVuMWmTsHoUVo9FoA== + eslint-plugin-promise@^3.4.1: version "3.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz#54b7658c8f454813dc2a870aff8152ec4969ba75" @@ -3932,6 +4091,13 @@ evp_bytestokey@^1.0.0: dependencies: create-hash "^1.1.1" +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== + dependencies: + merge "^1.2.0" + execa@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" @@ -3981,6 +4147,11 @@ exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" +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@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -4013,6 +4184,17 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" +expect@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.1.0.tgz#88e73301c4c785cde5f16da130ab407bdaf8c0f2" + integrity sha512-lVcAPhaYkQcIyMS+F8RVwzbm1jro20IG8OkvxQ6f1JfqhVZyyudCwYogQ7wnktlf14iF3ii7ArIUO/mqvrW9Gw== + dependencies: + ansi-styles "^3.2.0" + jest-get-type "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" + express@^4.16.2: version "4.16.4" resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" @@ -4147,6 +4329,13 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= + dependencies: + bser "^2.0.0" + fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" @@ -4196,6 +4385,14 @@ filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" +fileset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + fill-keys@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" @@ -4441,7 +4638,7 @@ fsevents@^1.0.0: nan "^2.3.0" node-pre-gyp "^0.6.29" -fsevents@^1.2.7: +fsevents@^1.2.3, fsevents@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== @@ -4595,7 +4792,7 @@ glob@^7.0.3, glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3: +glob@^7.1.1, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -4722,11 +4919,27 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +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= + handle-thing@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== +handlebars@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" + integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== + dependencies: + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" @@ -5217,7 +5430,7 @@ invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2: dependencies: loose-envify "^1.0.0" -invariant@^2.2.0: +invariant@^2.2.0, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -5418,6 +5631,11 @@ is-function@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" +is-generator-fn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.0.0.tgz#038c31b774709641bda678b1f06a4e3227c10b3e" + integrity sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g== + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -5595,10 +5813,6 @@ is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-windows@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" @@ -5653,6 +5867,406 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= +istanbul-api@^2.0.8: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.1.tgz#194b773f6d9cbc99a9258446848b0f988951c4d0" + integrity sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw== + dependencies: + async "^2.6.1" + compare-versions "^3.2.1" + fileset "^2.0.3" + istanbul-lib-coverage "^2.0.3" + istanbul-lib-hook "^2.0.3" + istanbul-lib-instrument "^3.1.0" + istanbul-lib-report "^2.0.4" + istanbul-lib-source-maps "^3.0.2" + istanbul-reports "^2.1.1" + js-yaml "^3.12.0" + make-dir "^1.3.0" + minimatch "^3.0.4" + once "^1.4.0" + +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba" + integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw== + +istanbul-lib-hook@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz#e0e581e461c611be5d0e5ef31c5f0109759916fb" + integrity sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA== + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz#a2b5484a7d445f1f311e93190813fa56dfb62971" + integrity sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA== + dependencies: + "@babel/generator" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + istanbul-lib-coverage "^2.0.3" + semver "^5.5.0" + +istanbul-lib-report@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4" + integrity sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA== + dependencies: + istanbul-lib-coverage "^2.0.3" + make-dir "^1.3.0" + supports-color "^6.0.0" + +istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz#f1e817229a9146e8424a28e5d69ba220fda34156" + integrity sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.3" + make-dir "^1.3.0" + rimraf "^2.6.2" + source-map "^0.6.1" + +istanbul-reports@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.1.1.tgz#72ef16b4ecb9a4a7bd0e2001e00f95d1eec8afa9" + integrity sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw== + dependencies: + handlebars "^4.1.0" + +jest-changed-files@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.0.0.tgz#c02c09a8cc9ca93f513166bc773741bd39898ff7" + integrity sha512-nnuU510R9U+UX0WNb5XFEcsrMqriSiRLeO9KWDFgPrpToaQm60prfQYpxsXigdClpvNot5bekDY440x9dNGnsQ== + dependencies: + execa "^1.0.0" + throat "^4.0.0" + +jest-cli@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.1.0.tgz#f7cc98995f36e7210cce3cbb12974cbf60940843" + integrity sha512-U/iyWPwOI0T1CIxVLtk/2uviOTJ/OiSWJSe8qt6X1VkbbgP+nrtLJlmT9lPBe4lK78VNFJtrJ7pttcNv/s7yCw== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.15" + import-local "^2.0.0" + is-ci "^2.0.0" + istanbul-api "^2.0.8" + istanbul-lib-coverage "^2.0.2" + istanbul-lib-instrument "^3.0.1" + istanbul-lib-source-maps "^3.0.1" + jest-changed-files "^24.0.0" + jest-config "^24.1.0" + jest-environment-jsdom "^24.0.0" + jest-get-type "^24.0.0" + jest-haste-map "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" + jest-resolve-dependencies "^24.1.0" + jest-runner "^24.1.0" + jest-runtime "^24.1.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + jest-watcher "^24.0.0" + jest-worker "^24.0.0" + micromatch "^3.1.10" + node-notifier "^5.2.1" + p-each-series "^1.0.0" + pirates "^4.0.0" + prompts "^2.0.1" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^2.0.0" + string-length "^2.0.0" + strip-ansi "^5.0.0" + which "^1.2.12" + yargs "^12.0.2" + +jest-config@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.1.0.tgz#6ea6881cfdd299bc86cc144ee36d937c97c3850c" + integrity sha512-FbbRzRqtFC6eGjG5VwsbW4E5dW3zqJKLWYiZWhB0/4E5fgsMw8GODLbGSrY5t17kKOtCWb/Z7nsIThRoDpuVyg== + dependencies: + "@babel/core" "^7.1.0" + babel-jest "^24.1.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^24.0.0" + jest-environment-node "^24.0.0" + jest-get-type "^24.0.0" + jest-jasmine2 "^24.1.0" + jest-regex-util "^24.0.0" + jest-resolve "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + micromatch "^3.1.10" + pretty-format "^24.0.0" + realpath-native "^1.0.2" + +jest-diff@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.0.0.tgz#a3e5f573dbac482f7d9513ac9cfa21644d3d6b34" + integrity sha512-XY5wMpRaTsuMoU+1/B2zQSKQ9RdE9gsLkGydx3nvApeyPijLA8GtEvIcPwISRCer+VDf9W1mStTYYq6fPt8ryA== + dependencies: + chalk "^2.0.1" + diff-sequences "^24.0.0" + jest-get-type "^24.0.0" + pretty-format "^24.0.0" + +jest-docblock@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.0.0.tgz#54d77a188743e37f62181a91a01eb9222289f94e" + integrity sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA== + dependencies: + detect-newline "^2.1.0" + +jest-each@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.0.0.tgz#10987a06b21c7ffbfb7706c89d24c52ed864be55" + integrity sha512-gFcbY4Cu55yxExXMkjrnLXov3bWO3dbPAW7HXb31h/DNWdNc/6X8MtxGff8nh3/MjkF9DpVqnj0KsPKuPK0cpA== + dependencies: + chalk "^2.0.1" + jest-get-type "^24.0.0" + jest-util "^24.0.0" + pretty-format "^24.0.0" + +jest-environment-jsdom@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz#5affa0654d6e44cd798003daa1a8701dbd6e4d11" + integrity sha512-1YNp7xtxajTRaxbylDc2pWvFnfDTH5BJJGyVzyGAKNt/lEULohwEV9zFqTgG4bXRcq7xzdd+sGFws+LxThXXOw== + dependencies: + jest-mock "^24.0.0" + jest-util "^24.0.0" + jsdom "^11.5.1" + +jest-environment-node@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.0.0.tgz#330948980656ed8773ce2e04eb597ed91e3c7190" + integrity sha512-62fOFcaEdU0VLaq8JL90TqwI7hLn0cOKOl8vY2n477vRkCJRojiRRtJVRzzCcgFvs6gqU97DNqX5R0BrBP6Rxg== + dependencies: + jest-mock "^24.0.0" + jest-util "^24.0.0" + +jest-get-type@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.0.0.tgz#36e72930b78e33da59a4f63d44d332188278940b" + integrity sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w== + +jest-haste-map@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" + integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.15" + invariant "^2.2.4" + jest-serializer "^24.0.0" + jest-util "^24.0.0" + jest-worker "^24.0.0" + micromatch "^3.1.10" + sane "^3.0.0" + +jest-jasmine2@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.1.0.tgz#8377324b967037c440f0a549ee0bbd9912055db6" + integrity sha512-H+o76SdSNyCh9fM5K8upK45YTo/DiFx5w2YAzblQebSQmukDcoVBVeXynyr7DDnxh+0NTHYRCLwJVf3tC518wg== + dependencies: + "@babel/traverse" "^7.1.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^24.1.0" + is-generator-fn "^2.0.0" + jest-each "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + pretty-format "^24.0.0" + throat "^4.0.0" + +jest-leak-detector@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.0.0.tgz#78280119fd05ee98317daee62cddb3aa537a31c6" + integrity sha512-ZYHJYFeibxfsDSKowjDP332pStuiFT2xfc5R67Rjm/l+HFJWJgNIOCOlQGeXLCtyUn3A23+VVDdiCcnB6dTTrg== + dependencies: + pretty-format "^24.0.0" + +jest-matcher-utils@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.0.0.tgz#fc9c41cfc49b2c3ec14e576f53d519c37729d579" + integrity sha512-LQTDmO+aWRz1Tf9HJg+HlPHhDh1E1c65kVwRFo5mwCVp5aQDzlkz4+vCvXhOKFjitV2f0kMdHxnODrXVoi+rlA== + dependencies: + chalk "^2.0.1" + jest-diff "^24.0.0" + jest-get-type "^24.0.0" + pretty-format "^24.0.0" + +jest-message-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.0.0.tgz#a07a141433b2c992dbaec68d4cbfe470ba289619" + integrity sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q== + dependencies: + "@babel/code-frame" "^7.0.0" + chalk "^2.0.1" + micromatch "^3.1.10" + slash "^2.0.0" + stack-utils "^1.0.1" + +jest-mock@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.0.0.tgz#9a4b53e01d66a0e780f7d857462d063e024c617d" + integrity sha512-sQp0Hu5fcf5NZEh1U9eIW2qD0BwJZjb63Yqd98PQJFvf/zzUTBoUAwv/Dc/HFeNHIw1f3hl/48vNn+j3STaI7A== + +jest-regex-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.0.0.tgz#4feee8ec4a358f5bee0a654e94eb26163cb9089a" + integrity sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q== + +jest-resolve-dependencies@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.1.0.tgz#78f738a2ec59ff4d00751d9da56f176e3f589f6c" + integrity sha512-2VwPsjd3kRPu7qe2cpytAgowCObk5AKeizfXuuiwgm1a9sijJDZe8Kh1sFj6FKvSaNEfCPlBVkZEJa2482m/Uw== + dependencies: + jest-regex-util "^24.0.0" + jest-snapshot "^24.1.0" + +jest-resolve@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.1.0.tgz#42ff0169b0ea47bfdbd0c52a0067ca7d022c7688" + integrity sha512-TPiAIVp3TG6zAxH28u/6eogbwrvZjBMWroSLBDkwkHKrqxB/RIdwkWDye4uqPlZIXWIaHtifY3L0/eO5Z0f2wg== + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.1.0.tgz#3686a2bb89ce62800da23d7fdc3da2c32792943b" + integrity sha512-CDGOkT3AIFl16BLL/OdbtYgYvbAprwJ+ExKuLZmGSCSldwsuU2dEGauqkpvd9nphVdAnJUcP12e/EIlnTX0QXg== + dependencies: + chalk "^2.4.2" + exit "^0.1.2" + graceful-fs "^4.1.15" + jest-config "^24.1.0" + jest-docblock "^24.0.0" + jest-haste-map "^24.0.0" + jest-jasmine2 "^24.1.0" + jest-leak-detector "^24.0.0" + jest-message-util "^24.0.0" + jest-runtime "^24.1.0" + jest-util "^24.0.0" + jest-worker "^24.0.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.1.0.tgz#7c157a2e776609e8cf552f956a5a19ec9c985214" + integrity sha512-59/BY6OCuTXxGeDhEMU7+N33dpMQyXq7MLK07cNSIY/QYt2QZgJ7Tjx+rykBI0skAoigFl0A5tmT8UdwX92YuQ== + dependencies: + "@babel/core" "^7.1.0" + babel-plugin-istanbul "^5.1.0" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + glob "^7.1.3" + graceful-fs "^4.1.15" + jest-config "^24.1.0" + jest-haste-map "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" + jest-resolve "^24.1.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + micromatch "^3.1.10" + realpath-native "^1.0.0" + slash "^2.0.0" + strip-bom "^3.0.0" + write-file-atomic "2.4.1" + yargs "^12.0.2" + +jest-serializer@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" + integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== + +jest-snapshot@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.1.0.tgz#85e22f810357aa5994ab61f236617dc2205f2f5b" + integrity sha512-th6TDfFqEmXvuViacU1ikD7xFb7lQsPn2rJl7OEmnfIVpnrx3QNY2t3PE88meeg0u/mQ0nkyvmC05PBqO4USFA== + dependencies: + "@babel/types" "^7.0.0" + chalk "^2.0.1" + jest-diff "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-resolve "^24.1.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^24.0.0" + semver "^5.5.0" + +jest-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.0.0.tgz#fd38fcafd6dedbd0af2944d7a227c0d91b68f7d6" + integrity sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ== + dependencies: + callsites "^3.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.15" + is-ci "^2.0.0" + jest-message-util "^24.0.0" + mkdirp "^0.5.1" + slash "^2.0.0" + source-map "^0.6.0" + +jest-validate@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.0.0.tgz#aa8571a46983a6538328fef20406b4a496b6c020" + integrity sha512-vMrKrTOP4BBFIeOWsjpsDgVXATxCspC9S1gqvbJ3Tnn/b9ACsJmteYeVx9830UMV28Cob1RX55x96Qq3Tfad4g== + dependencies: + camelcase "^5.0.0" + chalk "^2.0.1" + jest-get-type "^24.0.0" + leven "^2.1.0" + pretty-format "^24.0.0" + +jest-watcher@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.0.0.tgz#20d44244d10b0b7312410aefd256c1c1eef68890" + integrity sha512-GxkW2QrZ4YxmW1GUWER05McjVDunBlKMFfExu+VsGmXJmpej1saTEKvONdx5RJBlVdpPI5x6E3+EDQSIGgl53g== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + jest-util "^24.0.0" + string-length "^2.0.0" + +jest-worker@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" + integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== + dependencies: + merge-stream "^1.0.1" + supports-color "^6.1.0" + +jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-24.1.0.tgz#b1e1135caefcf2397950ecf7f90e395fde866fd2" + integrity sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A== + dependencies: + import-local "^2.0.0" + jest-cli "^24.1.0" + js-base64@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" @@ -5740,7 +6354,7 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" -json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -5884,6 +6498,11 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +kleur@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.2.tgz#83c7ec858a41098b613d5998a7b653962b504f68" + integrity sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q== + known-css-properties@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.2.0.tgz#899c94be368e55b42d7db8d5be7d73a4a4a41454" @@ -5925,6 +6544,11 @@ left-pad@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -5943,6 +6567,16 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" @@ -6117,13 +6751,20 @@ macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" -make-dir@^1.0.0: +make-dir@^1.0.0, make-dir@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" +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" @@ -6206,6 +6847,18 @@ merge-descriptors@1.0.1, merge-descriptors@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= + dependencies: + readable-stream "^2.0.1" + +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -6310,7 +6963,7 @@ minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" -"minimatch@2 || 3", minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.3, 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== @@ -6328,10 +6981,15 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + minimist@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.0.tgz#4dffe525dae2b864c66c2e23c6271d7afdecefce" @@ -6533,6 +7191,11 @@ node-forge@0.6.33: version "0.6.33" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" +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-libs-browser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" @@ -6570,6 +7233,17 @@ node-modules-regexp@^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@^5.2.1: + version "5.4.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.0.tgz#7b455fdce9f7de0c63538297354f3db468426e6a" + integrity sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ== + dependencies: + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" @@ -6866,6 +7540,14 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -6930,6 +7612,13 @@ p-defer@^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@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= + dependencies: + p-reduce "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -6972,6 +7661,11 @@ p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -7044,6 +7738,14 @@ parse-json@^2.2.0: 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-ms@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" @@ -7136,6 +7838,13 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + pbkdf2@^3.0.3: version "3.0.9" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693" @@ -7626,6 +8335,14 @@ pretty-error@^2.0.2: renderkid "^2.0.1" utila "~0.4" +pretty-format@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" + integrity sha512-LszZaKG665djUcqg5ZQq+XzezHLKrxsA86ZABTozp+oNhkdqa+tG2dX4qa6ERl5c/sRDrAa3lHmwnvKoP+OG/g== + dependencies: + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + pretty-ms@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc" @@ -7679,6 +8396,14 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +prompts@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.3.tgz#c5ccb324010b2e8f74752aadceeb57134c1d2522" + integrity sha512-H8oWEoRZpybm6NV4to9/1limhttEo13xK62pNvn2JzY0MA03p7s0OjtmhXyon3uJmxiJJVSuUwEJFFssI3eBiQ== + dependencies: + kleur "^3.0.2" + sisteransi "^1.0.0" + prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" @@ -8009,6 +8734,14 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" +read-pkg-up@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" + integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== + dependencies: + find-up "^3.0.0" + read-pkg "^3.0.0" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -8018,6 +8751,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" @@ -8132,6 +8874,13 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" +realpath-native@^1.0.0, realpath-native@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== + dependencies: + util.promisify "^1.0.0" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -8536,6 +9285,10 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= +resolve@1.1.7, resolve@~1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + resolve@^0.6.1: version "0.6.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46" @@ -8553,10 +9306,6 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.6" -resolve@~1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - resolve@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" @@ -8604,6 +9353,11 @@ ripemd160@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e" +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -8646,6 +9400,23 @@ samsam@1.x, samsam@^1.1.3: version "1.3.0" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" +sane@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" + integrity sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q== + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + sanitize-filename@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a" @@ -8835,6 +9606,11 @@ shelljs@^0.7.5: interpret "^1.0.0" rechoir "^0.6.2" +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.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -8868,6 +9644,16 @@ sinon@^2.1.0: text-encoding "0.6.4" type-detect "^4.0.0" +sisteransi@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" + integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" @@ -8962,7 +9748,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.10, source-map-support@^0.5.9, source-map-support@~0.5.9: +source-map-support@^0.5.10, source-map-support@^0.5.6, source-map-support@^0.5.9, source-map-support@~0.5.9: version "0.5.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== @@ -9112,6 +9898,11 @@ stable@~0.1.6: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +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== + stackframe@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4" @@ -9192,6 +9983,14 @@ strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.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" @@ -9271,6 +10070,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -9461,6 +10267,13 @@ supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-co dependencies: has-flag "^3.0.0" +supports-color@^6.0.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + svg-inline-loader@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/svg-inline-loader/-/svg-inline-loader-0.7.1.tgz#6d0e2728b7ec3414c2180b3f780bc3f7154ef226" @@ -9692,6 +10505,16 @@ terser@^3.16.1, terser@^3.8.1: source-map "~0.6.1" source-map-support "~0.5.9" +test-exclude@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.1.0.tgz#6ba6b25179d2d38724824661323b73e03c0c1de1" + integrity sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA== + dependencies: + arrify "^1.0.1" + minimatch "^3.0.4" + read-pkg-up "^4.0.0" + require-main-filename "^1.0.1" + text-encoding@0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" @@ -9704,6 +10527,11 @@ three@^0.100.0: version "0.100.0" resolved "https://registry.yarnpkg.com/three/-/three-0.100.0.tgz#262841c0b7d88ebd62af73f28d9f578963b3aa00" +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + throttleit@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" @@ -9761,6 +10589,11 @@ tinycolor2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -9929,6 +10762,14 @@ uglify-js@3.1.x: commander "~2.11.0" source-map "~0.6.1" +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + uid-number@~0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -10202,12 +11043,27 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +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" + warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" dependencies: loose-envify "^1.0.0" +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + watchpack@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" @@ -10387,7 +11243,7 @@ which-module@^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: +which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -10412,6 +11268,11 @@ window-size@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -10436,6 +11297,15 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" + integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write-file-atomic@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" @@ -10563,7 +11433,7 @@ yargs@^1.2.6: version "1.3.3" resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.3.3.tgz#054de8b61f22eefdb7207059eaef9d6b83fb931a" -yargs@^12.0.4, yargs@^12.0.5: +yargs@^12.0.2, yargs@^12.0.4, 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== From 4195813c09025faf88d7daf1d0d93a74660804aa Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Wed, 20 Feb 2019 19:44:15 +0000 Subject: [PATCH 2/9] messageType list and constructMidiId function --- .../midiMessage/_test/constructMidiId.test.js | 33 +++++++++++++++ src/utils/midiMessage/index.js | 41 ++++++++++--------- 2 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 src/utils/midiMessage/_test/constructMidiId.test.js diff --git a/src/utils/midiMessage/_test/constructMidiId.test.js b/src/utils/midiMessage/_test/constructMidiId.test.js new file mode 100644 index 00000000..d1166d52 --- /dev/null +++ b/src/utils/midiMessage/_test/constructMidiId.test.js @@ -0,0 +1,33 @@ +const { constructMidiId } = require('../') + +test('Returns concatinated id based on input paramaters', () => { + let type, note, channel, expected, actual + + type = 'b0' + note = 100 + channel = 0 + actual = constructMidiId(type, note, channel) + expected = 'midi_176_100' + + expect(actual).toBe(expected) + + type = 'b0' + note = 100 + channel = 1 + actual = constructMidiId(type, note, channel) + expected = 'midi_177_100' + + type = 'c0' + note = 127 + channel = 0 + actual = constructMidiId(type, note, channel) + expected = 'midi_192_127' + + type = 'c0' + note = 127 + channel = 10 + actual = constructMidiId(type, note, channel) + expected = 'midi_202_127' + + expect(actual).toBe(expected) +}) diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js index 927bd3ad..a4843a2e 100644 --- a/src/utils/midiMessage/index.js +++ b/src/utils/midiMessage/index.js @@ -1,3 +1,11 @@ +export const messageTypes = { + // These represent ranges of 16 + '80': 'noteOff', + '90': 'noteOn', + 'b0': 'controlChange', + 'c0': 'programChange', +} + export const processMidiMessage = message => { let value, type, id @@ -5,28 +13,18 @@ export const processMidiMessage = message => { const d1 = message.data[1] const d2 = message.data[2] - // Erase the first bit as this relates to channel - const code = d0 & 0xf0 + // If the midi message is less than 240, it involves channels + if (d0 < 0xf0) { + // Erase the first bit as this relates to channel + const code = d0 & 0xf0 + type = messageTypes[code.toString(16)] - switch (code) { - case 0x80: + // If it's a noteOn but value is 0, make it a noteOff + if (type === 'noteOn' && d2 === 0) { type = 'noteOff' - break - case 0x90: - type = d2 === 0 ? 'noteOff' : 'noteOn' - break - case 0xA0: - type = 'polyPressure' - break - case 0xB0: - type = 'controlChange' - break - case 0xC0: - type = 'programChange' - break - default: - if (d0 === 248) type = 'timingClock' - break + } + } else if (d0 === 248) { + type = 'timingClock' } if (d2 !== undefined) { @@ -41,3 +39,6 @@ export const processMidiMessage = message => { value, id, type, } } + +export const constructMidiId = (type, note, channel) => + `midi_${parseInt(type, 16) + channel}_${note}` From 76f085d168ce4b486c5aa826bd3897a9910ad407 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Wed, 20 Feb 2019 22:08:07 +0000 Subject: [PATCH 3/9] Created more midi related utils --- src/inputs/MidiInput.js | 4 +- src/utils/midiMessage/_test/midiNotes.test.js | 20 +++ .../midiMessage/_test/processMidiData.test.js | 109 ++++++++++++++++ .../midiMessage/_test/processMidiId.test.js | 23 ++++ .../_test/processMidiMessage.test.js | 117 ------------------ src/utils/midiMessage/index.js | 31 ++++- 6 files changed, 180 insertions(+), 124 deletions(-) create mode 100644 src/utils/midiMessage/_test/midiNotes.test.js create mode 100644 src/utils/midiMessage/_test/processMidiData.test.js create mode 100644 src/utils/midiMessage/_test/processMidiId.test.js delete mode 100644 src/utils/midiMessage/_test/processMidiMessage.test.js diff --git a/src/inputs/MidiInput.js b/src/inputs/MidiInput.js index 61901d0b..d22f1a28 100644 --- a/src/inputs/MidiInput.js +++ b/src/inputs/MidiInput.js @@ -3,12 +3,12 @@ import { midiStopLearning, midiUpdateDevices, midiMessage } from '../store/midi/ import { uInputLinkCreate } from '../store/inputLinks/actions' import { clockPulse } from '../store/clock/actions' import { newData as teachMidi } from '../utils/getMidiMode' -import { processMidiMessage } from '../utils/midiMessage' +import { processMidiData } from '../utils/midiMessage' export default (store) => { const onMessage = (rawMessage) => { const state = store.getState() - const m = processMidiMessage(rawMessage) + const m = processMidiData(rawMessage.data) if (m.type !== 'timingClock' && m.type !== 'noteOff') { store.dispatch(midiMessage(rawMessage.target.name, { diff --git a/src/utils/midiMessage/_test/midiNotes.test.js b/src/utils/midiMessage/_test/midiNotes.test.js new file mode 100644 index 00000000..e664f093 --- /dev/null +++ b/src/utils/midiMessage/_test/midiNotes.test.js @@ -0,0 +1,20 @@ +const { midiNotes } = require('../') + +test('Returns text for midi note', () => { + let expected, actual + + expected = '0 - C (-1)' + actual = midiNotes[0] + + expect(actual).toBe(expected) + + expected = '27 - D# / Eb (1)' + actual = midiNotes[27] + + expect(actual).toBe(expected) + + expected = '60 - C (4)' + actual = midiNotes[60] + + expect(actual).toBe(expected) +}) diff --git a/src/utils/midiMessage/_test/processMidiData.test.js b/src/utils/midiMessage/_test/processMidiData.test.js new file mode 100644 index 00000000..e7a3bce9 --- /dev/null +++ b/src/utils/midiMessage/_test/processMidiData.test.js @@ -0,0 +1,109 @@ +const { processMidiData } = require('../') + +test('Returns correct value as a number between 0 and 1', () => { + let data, expected, actual + + data = [0, 0, 127] + + expected = 1 + actual = processMidiData(data).value + + expect(actual).toBe(expected) + + data = [0, 0, 0] + + expected = 0 + actual = processMidiData(data).value + + expect(actual).toBe(expected) +}) + +test('Returns correct type', () => { + let data, expected, actual + + data = [176, 0, 0] + + expected = 'controlChange' + actual = processMidiData(data).type + + expect(actual).toBe(expected) + + data = [180, 0, 0] + + expected = 'controlChange' + actual = processMidiData(data).type + + expect(actual).toBe(expected) + + data = [144, 0, 1] + + expected = 'noteOn' + actual = processMidiData(data).type + + data = [147, 0, 1] + + expected = 'noteOn' + actual = processMidiData(data).type + + expect(actual).toBe(expected) + + data = [144, 0, 0] // If last value is 0, it becomes a noteOf + + expected = 'noteOff' + actual = processMidiData(data).type + + expect(actual).toBe(expected) + + data = [128, 0, 1] + + expected = 'noteOff' + actual = processMidiData(data).type + + expect(actual).toBe(expected) + + data = [248, 0, 1] + + expected = 'timingClock' + actual = processMidiData(data).type + + expect(actual).toBe(expected) +}) + +test('Returns id as a concatination of the first two vals', () => { + let data, expected, actual + + data = [176, 100, 0] + + expected = 'midi_176_100' + actual = processMidiData(data).id + + expect(actual).toBe(expected) + + data = [88, 0, 0] + + expected = 'midi_88_0' + actual = processMidiData(data).id + + data = [8, 80, 0] + + expected = 'midi_8_80' + actual = processMidiData(data).id + + expect(actual).toBe(expected) +}) + +test('Returns channel', () => { + let data, expected, actual + + data = [176, 100, 0] + + expected = 0 + actual = processMidiData(data).channel + + data = [186, 100, 0] + + expected = 10 + actual = processMidiData(data).channel + + expect(actual).toBe(expected) +}) diff --git a/src/utils/midiMessage/_test/processMidiId.test.js b/src/utils/midiMessage/_test/processMidiId.test.js new file mode 100644 index 00000000..d55aa9c5 --- /dev/null +++ b/src/utils/midiMessage/_test/processMidiId.test.js @@ -0,0 +1,23 @@ +const { processMidiId, processMidiData } = require('../') + +test('Returns same as processMidiData, split by _, last val always being 1', () => { + let id, expected, actual + + id = 'midi_1_0' + + expected = processMidiData([1, 0, 1]) + actual = processMidiId(id) + expect(actual).toEqual(expected) + + id = 'midi_0_1' + + expected = processMidiData([0, 1, 1]) + actual = processMidiId(id) + expect(actual).toEqual(expected) + + id = 'midi_127_0' + + expected = processMidiData([127, 0, 1]) + actual = processMidiId(id) + expect(actual).toEqual(expected) +}) diff --git a/src/utils/midiMessage/_test/processMidiMessage.test.js b/src/utils/midiMessage/_test/processMidiMessage.test.js deleted file mode 100644 index 3bf62ddd..00000000 --- a/src/utils/midiMessage/_test/processMidiMessage.test.js +++ /dev/null @@ -1,117 +0,0 @@ -const { processMidiMessage } = require('../') - -test('Returns correct value as a number between 0 and 1', () => { - let message, expected, actual - - message = { - data: [0, 0, 127], - } - - expected = 1 - actual = processMidiMessage(message).value - - expect(actual).toBe(expected) - - message = { - data: [0, 0, 0], - } - - expected = 0 - actual = processMidiMessage(message).value - - expect(actual).toBe(expected) -}) - -test('Returns correct type', () => { - let message, expected, actual - - message = { - data: [176, 0, 0], - } - - expected = 'controlChange' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) - - message = { - data: [180, 0, 0], - } - - expected = 'controlChange' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) - - message = { - data: [144, 0, 1], - } - - expected = 'noteOn' - actual = processMidiMessage(message).type - - message = { - data: [147, 0, 1], - } - - expected = 'noteOn' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) - - message = { - data: [144, 0, 0], // If last value is 0, it becomes a noteOff - } - - expected = 'noteOff' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) - - message = { - data: [128, 0, 1], - } - - expected = 'noteOff' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) - - message = { - data: [248, 0, 1], - } - - expected = 'timingClock' - actual = processMidiMessage(message).type - - expect(actual).toBe(expected) -}) - -test('Returns id as a concatination of the first two vals', () => { - let message, expected, actual - - message = { - data: [176, 100, 0], - } - - expected = 'midi_176_100' - actual = processMidiMessage(message).id - - expect(actual).toBe(expected) - - message = { - data: [88, 0, 0], - } - - expected = 'midi_88_0' - actual = processMidiMessage(message).id - - message = { - data: [8, 80, 0], - } - - expected = 'midi_8_80' - actual = processMidiMessage(message).id - - expect(actual).toBe(expected) -}) diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js index a4843a2e..ec7b5196 100644 --- a/src/utils/midiMessage/index.js +++ b/src/utils/midiMessage/index.js @@ -1,3 +1,15 @@ +const noteLetters = [ + 'C', 'C# / Db', 'D', 'D# / Eb', 'E', 'F', 'F# / Gb', 'G', 'G# / Ab', 'A', 'A# / Bb', 'B', +] + +export const midiNotes = new Array(128) + +for (let i = 0; i < 128; i++) { + const letter = noteLetters[i % noteLetters.length] + const octave = Math.floor(i / noteLetters.length) - 1 + midiNotes[i] = `${i} - ${letter} (${octave})` +} + export const messageTypes = { // These represent ranges of 16 '80': 'noteOff', @@ -6,12 +18,14 @@ export const messageTypes = { 'c0': 'programChange', } -export const processMidiMessage = message => { +export const processMidiData = data => { let value, type, id - const d0 = message.data[0] - const d1 = message.data[1] - const d2 = message.data[2] + const d0 = data[0] + const d1 = data[1] + const d2 = data[2] + + const channel = d0 & 0x0f // If the midi message is less than 240, it involves channels if (d0 < 0xf0) { @@ -36,9 +50,16 @@ export const processMidiMessage = message => { } return { - value, id, type, + value, id, type, channel, } } export const constructMidiId = (type, note, channel) => `midi_${parseInt(type, 16) + channel}_${note}` + +export const processMidiId = id => { + const parts = id.split('_') + const data = [parts[1], parts[2], 1] + + return processMidiData(data) +} From 1854705ca4f34f26b6d1f4b55e14a9ec88b3cc94 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 12:27:52 +0000 Subject: [PATCH 4/9] Midi Learn correctly populating dropdowns for channel, control type, note num --- src/inputs/MidiInput.js | 19 +++++++--- .../_test/getInputLinkLfoOptionIds.spec.js | 3 +- src/selectors/getInputLinkLfoOptionIds.js | 4 +- src/store/inputLinks/actions.js | 5 +-- src/store/inputLinks/sagas.js | 14 ++++--- src/utils/midiGenerateOptions/index.js | 38 +++++++++++++++++++ src/utils/midiMessage/index.js | 18 ++++----- 7 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/inputs/MidiInput.js b/src/inputs/MidiInput.js index d22f1a28..a80658b4 100644 --- a/src/inputs/MidiInput.js +++ b/src/inputs/MidiInput.js @@ -10,7 +10,7 @@ export default (store) => { const state = store.getState() const m = processMidiData(rawMessage.data) - if (m.type !== 'timingClock' && m.type !== 'noteOff') { + if (m.messageType !== 'timingClock' && m.messageType !== 'noteOff') { store.dispatch(midiMessage(rawMessage.target.name, { data: rawMessage.data, timeStamp: rawMessage.timeStamp, @@ -20,7 +20,7 @@ export default (store) => { if (learning) { let controlType - const mode = teachMidi(rawMessage.data, m.type) + const mode = teachMidi(rawMessage.data, m.messageType) if (mode !== 'learning') { if (mode === 'ignore') { @@ -30,18 +30,27 @@ export default (store) => { controlType = mode } store.dispatch(uInputLinkCreate( - learning.id, m.id, learning.type, rawMessage.target.name, controlType + learning.id, + m.id, + learning.type, + { + deviceId: rawMessage.target.name, + controlType, + channel: m.channel, + messageType: m.messageType, + noteNum: m.noteNum, + } )) store.dispatch(midiStopLearning()) } } else { store.dispatch(inputFired(m.id, m.value, { - noteOn: m.type === 'noteOn', + noteOn: m.messageType === 'noteOn', type: 'midi', })) } // If no note data, treat as clock - } else if (m.type === 'timingClock') { + } else if (m.messageType === 'timingClock') { // Only dispatch clock pulse if no generated clock if (!state.clock.isGenerated) { store.dispatch(clockPulse()) diff --git a/src/selectors/_test/getInputLinkLfoOptionIds.spec.js b/src/selectors/_test/getInputLinkLfoOptionIds.spec.js index cbc27f7e..0f4f676b 100644 --- a/src/selectors/_test/getInputLinkLfoOptionIds.spec.js +++ b/src/selectors/_test/getInputLinkLfoOptionIds.spec.js @@ -8,13 +8,14 @@ test('(Selector) getInputLinkLfoOptionIds (input is not "lfo")', (t) => { input: { id: 'BAR', }, + lfoOptionIds: [], }, }, } const actual = getInputLinkLfoOptionIds(state, 'aaa') - t.equal(actual, undefined, 'Returns undefined') + t.deepEqual(actual, [], 'Returns empty array') t.end() }) diff --git a/src/selectors/getInputLinkLfoOptionIds.js b/src/selectors/getInputLinkLfoOptionIds.js index e5639716..848586b2 100644 --- a/src/selectors/getInputLinkLfoOptionIds.js +++ b/src/selectors/getInputLinkLfoOptionIds.js @@ -2,9 +2,9 @@ import getNodes from './getNodes' export default (state, linkId) => { const link = state.inputLinks[linkId] + const optionIds = link.lfoOptionIds if (link.input && link.input.id === 'lfo') { - const optionIds = link.lfoOptionIds const optionNodes = getNodes(state, optionIds) const shapeOpt = optionNodes.find(node => node.key === 'shape') const isNoise = shapeOpt.value === 'noise' @@ -32,5 +32,5 @@ export default (state, linkId) => { } } - return undefined + return optionIds } diff --git a/src/store/inputLinks/actions.js b/src/store/inputLinks/actions.js index e4044019..22cfb97f 100644 --- a/src/store/inputLinks/actions.js +++ b/src/store/inputLinks/actions.js @@ -1,12 +1,11 @@ -export function uInputLinkCreate (nodeId, inputId, inputType, deviceId, controlType) { +export function uInputLinkCreate (nodeId, inputId, inputType, meta) { return { type: 'U_INPUT_LINK_CREATE', payload: { nodeId, inputId, inputType, - deviceId, - controlType, + meta, }, } } diff --git a/src/store/inputLinks/sagas.js b/src/store/inputLinks/sagas.js index aa86b150..4f876283 100644 --- a/src/store/inputLinks/sagas.js +++ b/src/store/inputLinks/sagas.js @@ -27,6 +27,7 @@ import uid from 'uid' */ export function* inputLinkCreate (action) { const p = action.payload + const m = p.meta const modifierIds = [] const lfoOptionIds = [] const midiOptionIds = [] @@ -104,7 +105,7 @@ export function* inputLinkCreate (action) { } if (p.inputType === 'midi' || linkType === 'linkableAction') { - bankIndex = yield select(getCurrentBankIndex, p.deviceId) + bankIndex = yield select(getCurrentBankIndex, m.deviceId) if (linkType === 'node') { const midiOpts = yield call(midiGenerateOptions) @@ -113,9 +114,10 @@ export function* inputLinkCreate (action) { const item = midiOpts[key] midiOptionIds.push(item.id) - if (item.key === 'controlType' && p.controlType) { - item.value = p.controlType - } + if (item.key === 'controlType' && m.controlType) item.value = m.controlType + if (item.key === 'channel' && m.channel) item.value = m.channel + if (item.key === 'noteNum' && m.noteNum) item.value = m.noteNum + if (item.key === 'messageType' && m.messageType) item.value = m.messageType yield put(uNodeCreate(item.id, item)) } @@ -152,7 +154,7 @@ export function* inputLinkCreate (action) { id: linkId, nodeId: p.nodeId, nodeType, - deviceId: p.deviceId, + deviceId: m.deviceId, bankIndex, modifierIds, lfoOptionIds, @@ -170,7 +172,7 @@ export function* inputLinkCreate (action) { } else if (linkType === 'linkableAction') { yield put(linkableActionInputLinkAdd(p.nodeId, linkId)) } - yield put(inputAssignedLinkCreate(p.inputId, linkId, p.deviceId)) + yield put(inputAssignedLinkCreate(p.inputId, linkId, m.deviceId)) } } diff --git a/src/utils/midiGenerateOptions/index.js b/src/utils/midiGenerateOptions/index.js index ae0d03d1..e1a8c4de 100644 --- a/src/utils/midiGenerateOptions/index.js +++ b/src/utils/midiGenerateOptions/index.js @@ -1,4 +1,5 @@ import uid from 'uid' +import { midiNotes, messageTypes } from '../midiMessage' export default () => { return [ @@ -37,5 +38,42 @@ export default () => { }, ], }, + { + title: 'Note', + key: 'noteNum', + type: 'select', + id: uid(), + inputLinkIds: [], + subNode: true, + options: midiNotes.map((label, value) => ({ value, label })), + }, + { + title: 'Type', + key: 'messageType', + type: 'select', + id: uid(), + inputLinkIds: [], + subNode: true, + options: Object.keys(messageTypes).map(key => ( + { + value: messageTypes[key], + label: messageTypes[key], + } + )), + }, + { + title: 'Channel', + key: 'channel', + type: 'select', + id: uid(), + inputLinkIds: [], + subNode: true, + options: Array(16).fill(0).map((value, index) => ( + { + value: index + 1, + label: index + 1, + } + )), + }, ] } diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js index ec7b5196..348b432e 100644 --- a/src/utils/midiMessage/index.js +++ b/src/utils/midiMessage/index.js @@ -19,11 +19,11 @@ export const messageTypes = { } export const processMidiData = data => { - let value, type, id + let value, messageType, id - const d0 = data[0] - const d1 = data[1] - const d2 = data[2] + const d0 = data[0] // messageType + channel + const d1 = data[1] // Note number + const d2 = data[2] // Velocity const channel = d0 & 0x0f @@ -31,14 +31,14 @@ export const processMidiData = data => { if (d0 < 0xf0) { // Erase the first bit as this relates to channel const code = d0 & 0xf0 - type = messageTypes[code.toString(16)] + messageType = messageTypes[code.toString(16)] // If it's a noteOn but value is 0, make it a noteOff - if (type === 'noteOn' && d2 === 0) { - type = 'noteOff' + if (messageType === 'noteOn' && d2 === 0) { + messageType = 'noteOff' } } else if (d0 === 248) { - type = 'timingClock' + messageType = 'timingClock' } if (d2 !== undefined) { @@ -50,7 +50,7 @@ export const processMidiData = data => { } return { - value, id, type, channel, + value, id, messageType, channel, noteNum: d1, } } From 06bf5e3d501ea915e892ac83677b9a7e56ea1766 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 12:32:03 +0000 Subject: [PATCH 5/9] Nicer dropdown text for message type --- src/utils/midiGenerateOptions/index.js | 6 +++--- src/utils/midiMessage/index.js | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/utils/midiGenerateOptions/index.js b/src/utils/midiGenerateOptions/index.js index e1a8c4de..99101275 100644 --- a/src/utils/midiGenerateOptions/index.js +++ b/src/utils/midiGenerateOptions/index.js @@ -48,7 +48,7 @@ export default () => { options: midiNotes.map((label, value) => ({ value, label })), }, { - title: 'Type', + title: 'Message Type', key: 'messageType', type: 'select', id: uid(), @@ -56,8 +56,8 @@ export default () => { subNode: true, options: Object.keys(messageTypes).map(key => ( { - value: messageTypes[key], - label: messageTypes[key], + value: messageTypes[key].key, + label: messageTypes[key].title, } )), }, diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js index 348b432e..a963dd83 100644 --- a/src/utils/midiMessage/index.js +++ b/src/utils/midiMessage/index.js @@ -12,10 +12,10 @@ for (let i = 0; i < 128; i++) { export const messageTypes = { // These represent ranges of 16 - '80': 'noteOff', - '90': 'noteOn', - 'b0': 'controlChange', - 'c0': 'programChange', + '80': { key: 'noteOff', title: 'Note Off' }, + '90': { key: 'noteOn', title: 'Note On' }, + 'b0': { key: 'controlChange', title: 'Control Change' }, + 'c0': { key: 'programChange', title: 'Program Change' }, } export const processMidiData = data => { @@ -31,7 +31,7 @@ export const processMidiData = data => { if (d0 < 0xf0) { // Erase the first bit as this relates to channel const code = d0 & 0xf0 - messageType = messageTypes[code.toString(16)] + messageType = messageTypes[code.toString(16)].key // If it's a noteOn but value is 0, make it a noteOff if (messageType === 'noteOn' && d2 === 0) { From 3904b65060691479507c2397be9440b673e56725 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 13:06:50 +0000 Subject: [PATCH 6/9] Performance fix for redux-devtools --- src/renderer/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/index.js b/src/renderer/index.js index 333d9ffc..9b959148 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -48,6 +48,7 @@ if (process.env.NODE_ENV !== 'development') { 'NODE_VALUE_UPDATE', 'NODE_RANGE_UPDATE', 'NODE_SHOT_ARM', 'NODE_SHOT_DISARM', 'NODE_SHOT_FIRED', 'NODE_VALUES_BATCH_UPDATE', ], + maxAge: 10, }) } From 0ffcb4c8a083c4111f805e0bef3d4b2acfbe3e72 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 13:26:59 +0000 Subject: [PATCH 7/9] Firing action when midi dropdown changes --- src/components/Control/index.js | 8 ++++++-- src/containers/Control/index.js | 1 + src/containers/Select/index.js | 4 ++++ src/store/inputLinks/actions.js | 9 +++++++++ src/store/inputLinks/sagas.js | 2 +- src/utils/midiGenerateOptions/index.js | 6 +++++- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/Control/index.js b/src/components/Control/index.js index 2dcc7197..acc0cbb5 100644 --- a/src/components/Control/index.js +++ b/src/components/Control/index.js @@ -3,10 +3,10 @@ import PropTypes from 'prop-types' import Modifier from '../../containers/Modifier' import Select from '../../containers/Select' -const Control = ({ nodeId, type }) => { +const Control = ({ nodeId, type, onChangeAction }) => { switch (type) { case 'select': - return case 'slider': return default: @@ -17,6 +17,10 @@ const Control = ({ nodeId, type }) => { Control.propTypes = { nodeId: PropTypes.string.isRequired, type: PropTypes.string.isRequired, + onChangeAction: PropTypes.shape({ + type: PropTypes.string.isRequired, + payload: PropTypes.object, + }), } export default Control diff --git a/src/containers/Control/index.js b/src/containers/Control/index.js index 4f504596..19f0939e 100644 --- a/src/containers/Control/index.js +++ b/src/containers/Control/index.js @@ -6,6 +6,7 @@ const mapStateToProps = (state, ownProps) => { const node = getNode(state, ownProps.nodeId) return { type: node.type || 'slider', + onChangeAction: node.onChangeAction, } } diff --git a/src/containers/Select/index.js b/src/containers/Select/index.js index 0a554d98..b52067ce 100644 --- a/src/containers/Select/index.js +++ b/src/containers/Select/index.js @@ -18,6 +18,10 @@ const mapDispatchToProps = (dispatch, ownProps) => { dispatch(nodeValueUpdate(ownProps.nodeId, value.value, { dontMutate: true, })) + + if (ownProps.onChangeAction) { + dispatch(ownProps.onChangeAction) + } }, onAssignClick: () => { dispatch(uInputLinkCreate(ownProps.nodeId, 'midi', 'midi')) diff --git a/src/store/inputLinks/actions.js b/src/store/inputLinks/actions.js index 22cfb97f..c143196a 100644 --- a/src/store/inputLinks/actions.js +++ b/src/store/inputLinks/actions.js @@ -49,6 +49,15 @@ export function uInputLinkUpdate (linkId, inputId, inputType) { } } +export function uInputLinkUpdateMidiInput (linkId) { + return { + type: 'U_INPUT_LINK_UPDATE_MIDI_INPUT', + payload: { + linkId, + }, + } +} + export function inputLinksReplaceAll (links) { return { type: 'INPUT_LINKS_REPLACE_ALL', diff --git a/src/store/inputLinks/sagas.js b/src/store/inputLinks/sagas.js index 4f876283..3f963969 100644 --- a/src/store/inputLinks/sagas.js +++ b/src/store/inputLinks/sagas.js @@ -108,7 +108,7 @@ export function* inputLinkCreate (action) { bankIndex = yield select(getCurrentBankIndex, m.deviceId) if (linkType === 'node') { - const midiOpts = yield call(midiGenerateOptions) + const midiOpts = yield call(midiGenerateOptions, linkId) for (let key in midiOpts) { const item = midiOpts[key] diff --git a/src/utils/midiGenerateOptions/index.js b/src/utils/midiGenerateOptions/index.js index 99101275..613c2d82 100644 --- a/src/utils/midiGenerateOptions/index.js +++ b/src/utils/midiGenerateOptions/index.js @@ -1,7 +1,8 @@ import uid from 'uid' import { midiNotes, messageTypes } from '../midiMessage' +import { uInputLinkUpdateMidiInput } from '../../store/inputLinks/actions' -export default () => { +export default linkId => { return [ { title: 'MIDI Sensitivity', @@ -46,6 +47,7 @@ export default () => { inputLinkIds: [], subNode: true, options: midiNotes.map((label, value) => ({ value, label })), + onChangeAction: uInputLinkUpdateMidiInput(linkId), }, { title: 'Message Type', @@ -60,6 +62,7 @@ export default () => { label: messageTypes[key].title, } )), + onChangeAction: uInputLinkUpdateMidiInput(linkId), }, { title: 'Channel', @@ -74,6 +77,7 @@ export default () => { label: index + 1, } )), + onChangeAction: uInputLinkUpdateMidiInput(linkId), }, ] } From 8b1da78a36176ecd3f3c65eefc5ee70c8992d4e5 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 14:54:29 +0000 Subject: [PATCH 8/9] Input link dropdowns changing midi input link state (might be broken for shots) --- mockTests/inputLinks.test.js | 111 ++++++++++++++++++ src/store/inputLinks/actions.js | 19 +-- src/store/inputLinks/listener.js | 34 ++++++ src/store/inputLinks/reducer.js | 9 ++ src/store/rootListener.js | 2 + .../midiMessage/_test/constructMidiId.test.js | 8 +- .../midiMessage/_test/processMidiData.test.js | 14 +-- .../midiMessage/_test/processMidiId.test.js | 2 +- src/utils/midiMessage/index.js | 19 +-- 9 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 mockTests/inputLinks.test.js create mode 100644 src/store/inputLinks/listener.js diff --git a/mockTests/inputLinks.test.js b/mockTests/inputLinks.test.js new file mode 100644 index 00000000..e2dc7df1 --- /dev/null +++ b/mockTests/inputLinks.test.js @@ -0,0 +1,111 @@ +/** * SETUP ***/ + +import proxyquire from 'proxyquire' +import listen from 'redux-action-listeners' +import { createStore, applyMiddleware, combineReducers } from 'redux' + +import inputsReducer from '../src/store/inputs/reducer' +import nodesReducer from '../src/store/nodes/reducer' +import inputLinksReducer from '../src/store/inputLinks/reducer' + +import { constructMidiId } from '../src/utils/midiMessage' + +import { uInputLinkUpdateMidiInput } from '../src/store/inputLinks/actions' + +const rootReducer = combineReducers( + { + nodes: nodesReducer, + inputs: inputsReducer, + inputLinks: inputLinksReducer, + } +) + +let uniqueId +const uid = () => { + uniqueId++ + return 'id_' + uniqueId +} + +const inputLinksListener = proxyquire('../src/store/inputLinks/listener', { + 'uid': uid, +}).default + +const rootListener = { + types: 'all', + + handleAction (action, dispatched, store) { + inputLinksListener(action, store) + }, +} + +/** * TEST ***/ + +test('(mock) Input Links - Update link midi input', () => { + uniqueId = 0 + const messageType = 'controlChange' + const noteNum = 100 + const channel = 13 + const deviceId = 'Akai Foo' + + // State starts assuming some dropdown value have changed + const startState = { + nodes: { + option_a: { + key: 'channel', + value: channel, + }, + option_b: { + key: 'messageType', + value: messageType, + }, + option_c: { + key: 'noteNum', + value: noteNum, + }, + option_x: { + key: 'foo', + value: 1, + }, + }, + inputs: { + midi_0_0: { + deviceId: deviceId, + assignedLinkIds: [ + 'link_a', + ], + }, + }, + inputLinks: { + link_a: { + id: 'link_a', + deviceId: deviceId, + midiOptionIds: [ + 'option_a', 'option_b', 'option_c', + ], + input: { + id: 'midi_0_0', + type: 'midi', + }, + }, + }, + } + + const store = createStore(rootReducer, startState, applyMiddleware(listen(rootListener))) + + let state + + // The dropdown value has changed and so this action would be dispatched + store.dispatch(uInputLinkUpdateMidiInput('link_a')) + state = store.getState() + + const oldInput = state.inputs.midi_0_0 + expect(oldInput.assignedLinkIds.length).toBe(0) + + const newInputId = constructMidiId(messageType, noteNum, channel) + const newInput = state.inputs[newInputId] + expect(newInput.assignedLinkIds[0]).toBe('link_a') + expect(newInput.deviceId).toBe(deviceId) + + const link = state.inputLinks.link_a + expect(link.input.id).toBe(newInputId) +}) diff --git a/src/store/inputLinks/actions.js b/src/store/inputLinks/actions.js index c143196a..85a69375 100644 --- a/src/store/inputLinks/actions.js +++ b/src/store/inputLinks/actions.js @@ -38,13 +38,12 @@ export function rInputLinkDelete (id) { } } -export function uInputLinkUpdate (linkId, inputId, inputType) { +export function rInputLinkUpdate (id, newProperties) { return { - type: 'U_INPUT_LINK_UPDATE', + type: 'R_INPUT_LINK_UPDATE', payload: { - linkId, - inputId, - inputType, + id, + newProperties, }, } } @@ -67,16 +66,6 @@ export function inputLinksReplaceAll (links) { } } -export function rInputLinkUpdate (linkId, input) { - return { - type: 'R_INPUT_LINK_UPDATE', - payload: { - linkId, - input, - }, - } -} - export function inputLinkShotArm (id) { return { type: 'INPUT_LINK_SHOT_ARM', diff --git a/src/store/inputLinks/listener.js b/src/store/inputLinks/listener.js new file mode 100644 index 00000000..4d999642 --- /dev/null +++ b/src/store/inputLinks/listener.js @@ -0,0 +1,34 @@ +import getInputLink from '../../selectors/getInputLink' +import getNodes from '../../selectors/getNodes' +import { constructMidiId } from '../../utils/midiMessage' +import { inputAssignedLinkCreate, inputAssignedLinkDelete } from '../inputs/actions' +import { rInputLinkUpdate } from '../inputLinks/actions' + +const handleUpdateMidiInput = (action, store) => { + const state = store.getState() + const link = getInputLink(state, action.payload.linkId) + const opts = getNodes(state, link.midiOptionIds) + + let messageType, noteNum, channel + + opts.forEach(opt => { + if (opt.key === 'messageType') messageType = opt.value + if (opt.key === 'noteNum') noteNum = opt.value + if (opt.key === 'channel') channel = opt.value + }) + + const newInputId = constructMidiId(messageType, noteNum, channel) + + store.dispatch(inputAssignedLinkDelete(link.input.id, link.id)) + store.dispatch(inputAssignedLinkCreate(newInputId, link.id, link.deviceId)) + store.dispatch(rInputLinkUpdate(link.id, { input: { id: newInputId, type: 'midi' } })) +} + +export default (action, store) => { + switch (action.type) { + case 'U_INPUT_LINK_UPDATE_MIDI_INPUT': + handleUpdateMidiInput(action, store) + break + } +} + diff --git a/src/store/inputLinks/reducer.js b/src/store/inputLinks/reducer.js index 887dabd3..293d4f37 100644 --- a/src/store/inputLinks/reducer.js +++ b/src/store/inputLinks/reducer.js @@ -35,6 +35,15 @@ const inputLinkReducer = (state = defaultState, action) => { }, } } + case 'R_INPUT_LINK_UPDATE': { + return { + ...state, + [p.id] : { + ...state[p.id], + ...p.newProperties, + }, + } + } default: return state } diff --git a/src/store/rootListener.js b/src/store/rootListener.js index 9e2d17be..6b9b2dd7 100644 --- a/src/store/rootListener.js +++ b/src/store/rootListener.js @@ -1,5 +1,6 @@ import scenesListener from './scenes/listener' import sketchesListener from './sketches/listener' +import inputLinkListener from './inputLinks/listener' import linkableActionsListener from './linkableActions/listener' import animListener from './anims/listener' import engineListener from '../engine/listener' @@ -11,6 +12,7 @@ export default { handleAction (action, dispatched, store) { scenesListener(action, store) sketchesListener(action, store) + inputLinkListener(action, store) linkableActionsListener(action, store) engineListener(action, store) animListener(action, store) diff --git a/src/utils/midiMessage/_test/constructMidiId.test.js b/src/utils/midiMessage/_test/constructMidiId.test.js index d1166d52..006d95d6 100644 --- a/src/utils/midiMessage/_test/constructMidiId.test.js +++ b/src/utils/midiMessage/_test/constructMidiId.test.js @@ -3,7 +3,7 @@ const { constructMidiId } = require('../') test('Returns concatinated id based on input paramaters', () => { let type, note, channel, expected, actual - type = 'b0' + type = 'controlChange' note = 100 channel = 0 actual = constructMidiId(type, note, channel) @@ -11,19 +11,19 @@ test('Returns concatinated id based on input paramaters', () => { expect(actual).toBe(expected) - type = 'b0' + type = 'controlChange' note = 100 channel = 1 actual = constructMidiId(type, note, channel) expected = 'midi_177_100' - type = 'c0' + type = 'programChange' note = 127 channel = 0 actual = constructMidiId(type, note, channel) expected = 'midi_192_127' - type = 'c0' + type = 'programChange' note = 127 channel = 10 actual = constructMidiId(type, note, channel) diff --git a/src/utils/midiMessage/_test/processMidiData.test.js b/src/utils/midiMessage/_test/processMidiData.test.js index e7a3bce9..afa0d7ba 100644 --- a/src/utils/midiMessage/_test/processMidiData.test.js +++ b/src/utils/midiMessage/_test/processMidiData.test.js @@ -24,47 +24,47 @@ test('Returns correct type', () => { data = [176, 0, 0] expected = 'controlChange' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) data = [180, 0, 0] expected = 'controlChange' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) data = [144, 0, 1] expected = 'noteOn' - actual = processMidiData(data).type + actual = processMidiData(data).messageType data = [147, 0, 1] expected = 'noteOn' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) data = [144, 0, 0] // If last value is 0, it becomes a noteOf expected = 'noteOff' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) data = [128, 0, 1] expected = 'noteOff' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) data = [248, 0, 1] expected = 'timingClock' - actual = processMidiData(data).type + actual = processMidiData(data).messageType expect(actual).toBe(expected) }) diff --git a/src/utils/midiMessage/_test/processMidiId.test.js b/src/utils/midiMessage/_test/processMidiId.test.js index d55aa9c5..c46d1f5b 100644 --- a/src/utils/midiMessage/_test/processMidiId.test.js +++ b/src/utils/midiMessage/_test/processMidiId.test.js @@ -1,6 +1,6 @@ const { processMidiId, processMidiData } = require('../') -test('Returns same as processMidiData, split by _, last val always being 1', () => { +test('Returns same as processMidiData. Params entered are split by _, last val always being 1', () => { let id, expected, actual id = 'midi_1_0' diff --git a/src/utils/midiMessage/index.js b/src/utils/midiMessage/index.js index a963dd83..7ae81dd3 100644 --- a/src/utils/midiMessage/index.js +++ b/src/utils/midiMessage/index.js @@ -31,11 +31,14 @@ export const processMidiData = data => { if (d0 < 0xf0) { // Erase the first bit as this relates to channel const code = d0 & 0xf0 - messageType = messageTypes[code.toString(16)].key + const messageTypeObj = messageTypes[code.toString(16)] + if (messageTypeObj !== undefined) { + messageType = messageTypeObj.key - // If it's a noteOn but value is 0, make it a noteOff - if (messageType === 'noteOn' && d2 === 0) { - messageType = 'noteOff' + // If it's a noteOn but value is 0, make it a noteOff + if (messageType === 'noteOn' && d2 === 0) { + messageType = 'noteOff' + } } } else if (d0 === 248) { messageType = 'timingClock' @@ -54,12 +57,14 @@ export const processMidiData = data => { } } -export const constructMidiId = (type, note, channel) => - `midi_${parseInt(type, 16) + channel}_${note}` +export const constructMidiId = (messageType, noteNum, channel) => { + const typeHex = Object.keys(messageTypes).find(hex => messageTypes[hex].key === messageType) + return `midi_${parseInt(typeHex, 16) + channel}_${noteNum}` +} export const processMidiId = id => { const parts = id.split('_') - const data = [parts[1], parts[2], 1] + const data = [parseInt(parts[1]), parseInt(parts[2]), 1] return processMidiData(data) } From b655ae35b9741992552dd9239b59dfe50254d24d Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Thu, 21 Feb 2019 14:59:37 +0000 Subject: [PATCH 9/9] Channel dropdown values fix --- src/utils/midiGenerateOptions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/midiGenerateOptions/index.js b/src/utils/midiGenerateOptions/index.js index 613c2d82..b2200f80 100644 --- a/src/utils/midiGenerateOptions/index.js +++ b/src/utils/midiGenerateOptions/index.js @@ -73,7 +73,7 @@ export default linkId => { subNode: true, options: Array(16).fill(0).map((value, index) => ( { - value: index + 1, + value: index, label: index + 1, } )),