diff options
42 files changed, 1702 insertions, 1484 deletions
diff --git a/karma.conf.js b/karma.conf.js index 5e69f9e..32da469 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -29,6 +29,7 @@ module.exports = function (config) {      singleRun: true,      webpack: { +      mode: 'development',        devtool: 'inline-source-map',        resolve: webpackConfig.resolve,        module: webpackConfig.module diff --git a/package-lock.json b/package-lock.json index 1e9353e..cbc8dae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3,6 +3,32 @@    "requires": true,    "lockfileVersion": 1,    "dependencies": { +    "@babel/cli": { +      "version": "7.4.4", +      "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.4.4.tgz", +      "integrity": "sha512-XGr5YjQSjgTa6OzQZY57FAJsdeVSAKR/u/KA5exWIz66IKtv/zXtHy+fIZcMry/EgYegwuHE7vzGnrFhjdIAsQ==", +      "dev": true, +      "requires": { +        "chokidar": "^2.0.4", +        "commander": "^2.8.1", +        "convert-source-map": "^1.1.0", +        "fs-readdir-recursive": "^1.1.0", +        "glob": "^7.0.0", +        "lodash": "^4.17.11", +        "mkdirp": "^0.5.1", +        "output-file-sync": "^2.0.0", +        "slash": "^2.0.0", +        "source-map": "^0.5.0" +      }, +      "dependencies": { +        "lodash": { +          "version": "4.17.11", +          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", +          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", +          "dev": true +        } +      } +    },      "@babel/code-frame": {        "version": "7.0.0",        "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -12,6 +38,133 @@          "@babel/highlight": "^7.0.0"        }      }, +    "@babel/core": { +      "version": "7.4.4", +      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.4.tgz", +      "integrity": "sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==", +      "dev": true, +      "requires": { +        "@babel/code-frame": "^7.0.0", +        "@babel/generator": "^7.4.4", +        "@babel/helpers": "^7.4.4", +        "@babel/parser": "^7.4.4", +        "@babel/template": "^7.4.4", +        "@babel/traverse": "^7.4.4", +        "@babel/types": "^7.4.4", +        "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" +      }, +      "dependencies": { +        "@babel/generator": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", +          "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", +          "dev": true, +          "requires": { +            "@babel/types": "^7.4.4", +            "jsesc": "^2.5.1", +            "lodash": "^4.17.11", +            "source-map": "^0.5.0", +            "trim-right": "^1.0.1" +          } +        }, +        "@babel/helper-split-export-declaration": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", +          "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", +          "dev": true, +          "requires": { +            "@babel/types": "^7.4.4" +          } +        }, +        "@babel/parser": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", +          "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", +          "dev": true +        }, +        "@babel/template": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", +          "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", +          "dev": true, +          "requires": { +            "@babel/code-frame": "^7.0.0", +            "@babel/parser": "^7.4.4", +            "@babel/types": "^7.4.4" +          } +        }, +        "@babel/traverse": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", +          "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", +          "dev": true, +          "requires": { +            "@babel/code-frame": "^7.0.0", +            "@babel/generator": "^7.4.4", +            "@babel/helper-function-name": "^7.1.0", +            "@babel/helper-split-export-declaration": "^7.4.4", +            "@babel/parser": "^7.4.4", +            "@babel/types": "^7.4.4", +            "debug": "^4.1.0", +            "globals": "^11.1.0", +            "lodash": "^4.17.11" +          } +        }, +        "@babel/types": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", +          "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", +          "dev": true, +          "requires": { +            "esutils": "^2.0.2", +            "lodash": "^4.17.11", +            "to-fast-properties": "^2.0.0" +          } +        }, +        "debug": { +          "version": "4.1.1", +          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", +          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", +          "dev": true, +          "requires": { +            "ms": "^2.1.1" +          } +        }, +        "json5": { +          "version": "2.1.0", +          "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", +          "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", +          "dev": true, +          "requires": { +            "minimist": "^1.2.0" +          } +        }, +        "lodash": { +          "version": "4.17.11", +          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", +          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", +          "dev": true +        }, +        "minimist": { +          "version": "1.2.0", +          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", +          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", +          "dev": true +        }, +        "ms": { +          "version": "2.1.1", +          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", +          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", +          "dev": true +        } +      } +    },      "@babel/generator": {        "version": "7.3.0",        "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", @@ -33,6 +186,16 @@          }        }      }, +    "@babel/helper-builder-react-jsx": { +      "version": "7.3.0", +      "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", +      "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", +      "dev": true, +      "requires": { +        "@babel/types": "^7.3.0", +        "esutils": "^2.0.0" +      } +    },      "@babel/helper-function-name": {        "version": "7.1.0",        "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", @@ -53,6 +216,12 @@          "@babel/types": "^7.0.0"        }      }, +    "@babel/helper-plugin-utils": { +      "version": "7.0.0", +      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", +      "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", +      "dev": true +    },      "@babel/helper-split-export-declaration": {        "version": "7.0.0",        "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", @@ -62,6 +231,107 @@          "@babel/types": "^7.0.0"        }      }, +    "@babel/helpers": { +      "version": "7.4.4", +      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", +      "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", +      "dev": true, +      "requires": { +        "@babel/template": "^7.4.4", +        "@babel/traverse": "^7.4.4", +        "@babel/types": "^7.4.4" +      }, +      "dependencies": { +        "@babel/generator": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", +          "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", +          "dev": true, +          "requires": { +            "@babel/types": "^7.4.4", +            "jsesc": "^2.5.1", +            "lodash": "^4.17.11", +            "source-map": "^0.5.0", +            "trim-right": "^1.0.1" +          } +        }, +        "@babel/helper-split-export-declaration": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", +          "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", +          "dev": true, +          "requires": { +            "@babel/types": "^7.4.4" +          } +        }, +        "@babel/parser": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", +          "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", +          "dev": true +        }, +        "@babel/template": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", +          "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", +          "dev": true, +          "requires": { +            "@babel/code-frame": "^7.0.0", +            "@babel/parser": "^7.4.4", +            "@babel/types": "^7.4.4" +          } +        }, +        "@babel/traverse": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", +          "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", +          "dev": true, +          "requires": { +            "@babel/code-frame": "^7.0.0", +            "@babel/generator": "^7.4.4", +            "@babel/helper-function-name": "^7.1.0", +            "@babel/helper-split-export-declaration": "^7.4.4", +            "@babel/parser": "^7.4.4", +            "@babel/types": "^7.4.4", +            "debug": "^4.1.0", +            "globals": "^11.1.0", +            "lodash": "^4.17.11" +          } +        }, +        "@babel/types": { +          "version": "7.4.4", +          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", +          "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", +          "dev": true, +          "requires": { +            "esutils": "^2.0.2", +            "lodash": "^4.17.11", +            "to-fast-properties": "^2.0.0" +          } +        }, +        "debug": { +          "version": "4.1.1", +          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", +          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", +          "dev": true, +          "requires": { +            "ms": "^2.1.1" +          } +        }, +        "lodash": { +          "version": "4.17.11", +          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", +          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", +          "dev": true +        }, +        "ms": { +          "version": "2.1.1", +          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", +          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", +          "dev": true +        } +      } +    },      "@babel/highlight": {        "version": "7.0.0",        "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -116,6 +386,85 @@        "integrity": "sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA==",        "dev": true      }, +    "@babel/plugin-syntax-jsx": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", +      "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", +      "dev": true, +      "requires": { +        "@babel/helper-plugin-utils": "^7.0.0" +      } +    }, +    "@babel/plugin-transform-react-display-name": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", +      "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", +      "dev": true, +      "requires": { +        "@babel/helper-plugin-utils": "^7.0.0" +      } +    }, +    "@babel/plugin-transform-react-jsx": { +      "version": "7.3.0", +      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", +      "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", +      "dev": true, +      "requires": { +        "@babel/helper-builder-react-jsx": "^7.3.0", +        "@babel/helper-plugin-utils": "^7.0.0", +        "@babel/plugin-syntax-jsx": "^7.2.0" +      } +    }, +    "@babel/plugin-transform-react-jsx-self": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", +      "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", +      "dev": true, +      "requires": { +        "@babel/helper-plugin-utils": "^7.0.0", +        "@babel/plugin-syntax-jsx": "^7.2.0" +      } +    }, +    "@babel/plugin-transform-react-jsx-source": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz", +      "integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==", +      "dev": true, +      "requires": { +        "@babel/helper-plugin-utils": "^7.0.0", +        "@babel/plugin-syntax-jsx": "^7.2.0" +      } +    }, +    "@babel/preset-react": { +      "version": "7.0.0", +      "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", +      "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", +      "dev": true, +      "requires": { +        "@babel/helper-plugin-utils": "^7.0.0", +        "@babel/plugin-transform-react-display-name": "^7.0.0", +        "@babel/plugin-transform-react-jsx": "^7.0.0", +        "@babel/plugin-transform-react-jsx-self": "^7.0.0", +        "@babel/plugin-transform-react-jsx-source": "^7.0.0" +      } +    }, +    "@babel/runtime": { +      "version": "7.4.4", +      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.4.tgz", +      "integrity": "sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==", +      "dev": true, +      "requires": { +        "regenerator-runtime": "^0.13.2" +      }, +      "dependencies": { +        "regenerator-runtime": { +          "version": "0.13.2", +          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", +          "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==", +          "dev": true +        } +      } +    },      "@babel/template": {        "version": "7.2.2",        "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", @@ -513,14 +862,26 @@        "dev": true      },      "anymatch": { -      "version": "1.3.2", -      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", -      "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", +      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",        "dev": true,        "optional": true,        "requires": { -        "micromatch": "^2.1.5", -        "normalize-path": "^2.0.0" +        "micromatch": "^3.1.4", +        "normalize-path": "^2.1.1" +      }, +      "dependencies": { +        "normalize-path": { +          "version": "2.1.1", +          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", +          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", +          "dev": true, +          "optional": true, +          "requires": { +            "remove-trailing-separator": "^1.0.1" +          } +        }        }      },      "aproba": { @@ -549,14 +910,10 @@        }      },      "arr-diff": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", -      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", -      "dev": true, -      "optional": true, -      "requires": { -        "arr-flatten": "^1.0.1" -      } +      "version": "4.0.0", +      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", +      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", +      "dev": true      },      "arr-flatten": {        "version": "1.1.0", @@ -599,11 +956,10 @@        }      },      "array-unique": { -      "version": "0.2.1", -      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", -      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", -      "dev": true, -      "optional": true +      "version": "0.3.2", +      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", +      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", +      "dev": true      },      "arraybuffer.slice": {        "version": "0.0.7", @@ -732,67 +1088,6 @@        "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",        "dev": true      }, -    "babel-cli": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", -      "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", -      "dev": true, -      "requires": { -        "babel-core": "^6.26.0", -        "babel-polyfill": "^6.26.0", -        "babel-register": "^6.26.0", -        "babel-runtime": "^6.26.0", -        "chokidar": "^1.6.1", -        "commander": "^2.11.0", -        "convert-source-map": "^1.5.0", -        "fs-readdir-recursive": "^1.0.0", -        "glob": "^7.1.2", -        "lodash": "^4.17.4", -        "output-file-sync": "^1.1.2", -        "path-is-absolute": "^1.0.1", -        "slash": "^1.0.0", -        "source-map": "^0.5.6", -        "v8flags": "^2.1.1" -      } -    }, -    "babel-code-frame": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", -      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", -      "dev": true, -      "requires": { -        "chalk": "^1.1.3", -        "esutils": "^2.0.2", -        "js-tokens": "^3.0.2" -      } -    }, -    "babel-core": { -      "version": "6.26.3", -      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", -      "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", -      "dev": true, -      "requires": { -        "babel-code-frame": "^6.26.0", -        "babel-generator": "^6.26.0", -        "babel-helpers": "^6.24.1", -        "babel-messages": "^6.23.0", -        "babel-register": "^6.26.0", -        "babel-runtime": "^6.26.0", -        "babel-template": "^6.26.0", -        "babel-traverse": "^6.26.0", -        "babel-types": "^6.26.0", -        "babylon": "^6.18.0", -        "convert-source-map": "^1.5.1", -        "debug": "^2.6.9", -        "json5": "^0.5.1", -        "lodash": "^4.17.4", -        "minimatch": "^3.0.4", -        "path-is-absolute": "^1.0.1", -        "private": "^0.1.8", -        "slash": "^1.0.0", -        "source-map": "^0.5.7" -      } -    },      "babel-eslint": {        "version": "10.0.1",        "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", @@ -807,344 +1102,16 @@          "eslint-visitor-keys": "^1.0.0"        }      }, -    "babel-generator": { -      "version": "6.26.1", -      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", -      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", -      "dev": true, -      "requires": { -        "babel-messages": "^6.23.0", -        "babel-runtime": "^6.26.0", -        "babel-types": "^6.26.0", -        "detect-indent": "^4.0.0", -        "jsesc": "^1.3.0", -        "lodash": "^4.17.4", -        "source-map": "^0.5.7", -        "trim-right": "^1.0.1" -      } -    }, -    "babel-helper-bindify-decorators": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", -      "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.22.0", -        "babel-traverse": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-builder-binary-assignment-operator-visitor": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", -      "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", -      "dev": true, -      "requires": { -        "babel-helper-explode-assignable-expression": "^6.24.1", -        "babel-runtime": "^6.22.0", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-builder-react-jsx": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", -      "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.26.0", -        "babel-types": "^6.26.0", -        "esutils": "^2.0.2" -      } -    }, -    "babel-helper-explode-assignable-expression": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", -      "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.22.0", -        "babel-traverse": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-explode-class": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", -      "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", -      "dev": true, -      "requires": { -        "babel-helper-bindify-decorators": "^6.24.1", -        "babel-runtime": "^6.22.0", -        "babel-traverse": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-function-name": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", -      "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", -      "dev": true, -      "requires": { -        "babel-helper-get-function-arity": "^6.24.1", -        "babel-runtime": "^6.22.0", -        "babel-template": "^6.24.1", -        "babel-traverse": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-get-function-arity": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", -      "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.22.0", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helper-remap-async-to-generator": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", -      "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", -      "dev": true, -      "requires": { -        "babel-helper-function-name": "^6.24.1", -        "babel-runtime": "^6.22.0", -        "babel-template": "^6.24.1", -        "babel-traverse": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-helpers": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", -      "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.22.0", -        "babel-template": "^6.24.1" -      } -    },      "babel-loader": { -      "version": "7.1.5", -      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", -      "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", +      "version": "8.0.5", +      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", +      "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==",        "dev": true,        "requires": { -        "find-cache-dir": "^1.0.0", +        "find-cache-dir": "^2.0.0",          "loader-utils": "^1.0.2", -        "mkdirp": "^0.5.1" -      } -    }, -    "babel-messages": { -      "version": "6.23.0", -      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", -      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.22.0" -      } -    }, -    "babel-plugin-syntax-async-functions": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", -      "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", -      "dev": true -    }, -    "babel-plugin-syntax-async-generators": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", -      "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", -      "dev": true -    }, -    "babel-plugin-syntax-class-properties": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", -      "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", -      "dev": true -    }, -    "babel-plugin-syntax-decorators": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", -      "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", -      "dev": true -    }, -    "babel-plugin-syntax-dynamic-import": { -      "version": "6.18.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", -      "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", -      "dev": true -    }, -    "babel-plugin-syntax-exponentiation-operator": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", -      "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", -      "dev": true -    }, -    "babel-plugin-syntax-jsx": { -      "version": "6.18.0", -      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", -      "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", -      "dev": true -    }, -    "babel-plugin-syntax-object-rest-spread": { -      "version": "6.13.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", -      "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", -      "dev": true -    }, -    "babel-plugin-syntax-trailing-function-commas": { -      "version": "6.22.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", -      "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", -      "dev": true -    }, -    "babel-plugin-transform-async-generator-functions": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", -      "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", -      "dev": true, -      "requires": { -        "babel-helper-remap-async-to-generator": "^6.24.1", -        "babel-plugin-syntax-async-generators": "^6.5.0", -        "babel-runtime": "^6.22.0" -      } -    }, -    "babel-plugin-transform-async-to-generator": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", -      "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", -      "dev": true, -      "requires": { -        "babel-helper-remap-async-to-generator": "^6.24.1", -        "babel-plugin-syntax-async-functions": "^6.8.0", -        "babel-runtime": "^6.22.0" -      } -    }, -    "babel-plugin-transform-class-properties": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", -      "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", -      "dev": true, -      "requires": { -        "babel-helper-function-name": "^6.24.1", -        "babel-plugin-syntax-class-properties": "^6.8.0", -        "babel-runtime": "^6.22.0", -        "babel-template": "^6.24.1" -      } -    }, -    "babel-plugin-transform-decorators": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", -      "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", -      "dev": true, -      "requires": { -        "babel-helper-explode-class": "^6.24.1", -        "babel-plugin-syntax-decorators": "^6.13.0", -        "babel-runtime": "^6.22.0", -        "babel-template": "^6.24.1", -        "babel-types": "^6.24.1" -      } -    }, -    "babel-plugin-transform-exponentiation-operator": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", -      "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", -      "dev": true, -      "requires": { -        "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", -        "babel-plugin-syntax-exponentiation-operator": "^6.8.0", -        "babel-runtime": "^6.22.0" -      } -    }, -    "babel-plugin-transform-object-rest-spread": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", -      "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", -      "dev": true, -      "requires": { -        "babel-plugin-syntax-object-rest-spread": "^6.8.0", -        "babel-runtime": "^6.26.0" -      } -    }, -    "babel-plugin-transform-react-jsx": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", -      "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", -      "dev": true, -      "requires": { -        "babel-helper-builder-react-jsx": "^6.24.1", -        "babel-plugin-syntax-jsx": "^6.8.0", -        "babel-runtime": "^6.22.0" -      } -    }, -    "babel-polyfill": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", -      "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.26.0", -        "core-js": "^2.5.0", -        "regenerator-runtime": "^0.10.5" -      }, -      "dependencies": { -        "regenerator-runtime": { -          "version": "0.10.5", -          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", -          "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", -          "dev": true -        } -      } -    }, -    "babel-preset-preact": { -      "version": "1.1.0", -      "resolved": "https://registry.npmjs.org/babel-preset-preact/-/babel-preset-preact-1.1.0.tgz", -      "integrity": "sha1-NaxlWnOkm4Q4FjzgU4Fld+GYCGE=", -      "dev": true, -      "requires": { -        "babel-plugin-syntax-jsx": "^6.0.2", -        "babel-plugin-transform-react-jsx": "^6.0.2" -      } -    }, -    "babel-preset-stage-2": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", -      "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", -      "dev": true, -      "requires": { -        "babel-plugin-syntax-dynamic-import": "^6.18.0", -        "babel-plugin-transform-class-properties": "^6.24.1", -        "babel-plugin-transform-decorators": "^6.24.1", -        "babel-preset-stage-3": "^6.24.1" -      } -    }, -    "babel-preset-stage-3": { -      "version": "6.24.1", -      "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", -      "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", -      "dev": true, -      "requires": { -        "babel-plugin-syntax-trailing-function-commas": "^6.22.0", -        "babel-plugin-transform-async-generator-functions": "^6.24.1", -        "babel-plugin-transform-async-to-generator": "^6.24.1", -        "babel-plugin-transform-exponentiation-operator": "^6.24.1", -        "babel-plugin-transform-object-rest-spread": "^6.22.0" -      } -    }, -    "babel-register": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", -      "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", -      "dev": true, -      "requires": { -        "babel-core": "^6.26.0", -        "babel-runtime": "^6.26.0", -        "core-js": "^2.5.0", -        "home-or-tmp": "^2.0.0", -        "lodash": "^4.17.4",          "mkdirp": "^0.5.1", -        "source-map-support": "^0.4.15" +        "util.promisify": "^1.0.0"        }      },      "babel-runtime": { @@ -1157,54 +1124,6 @@          "regenerator-runtime": "^0.11.0"        }      }, -    "babel-template": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", -      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.26.0", -        "babel-traverse": "^6.26.0", -        "babel-types": "^6.26.0", -        "babylon": "^6.18.0", -        "lodash": "^4.17.4" -      } -    }, -    "babel-traverse": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", -      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", -      "dev": true, -      "requires": { -        "babel-code-frame": "^6.26.0", -        "babel-messages": "^6.23.0", -        "babel-runtime": "^6.26.0", -        "babel-types": "^6.26.0", -        "babylon": "^6.18.0", -        "debug": "^2.6.8", -        "globals": "^9.18.0", -        "invariant": "^2.2.2", -        "lodash": "^4.17.4" -      } -    }, -    "babel-types": { -      "version": "6.26.0", -      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", -      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", -      "dev": true, -      "requires": { -        "babel-runtime": "^6.26.0", -        "esutils": "^2.0.2", -        "lodash": "^4.17.4", -        "to-fast-properties": "^1.0.3" -      } -    }, -    "babylon": { -      "version": "6.18.0", -      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", -      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", -      "dev": true -    },      "backo2": {        "version": "1.0.2",        "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -1394,15 +1313,21 @@        }      },      "braces": { -      "version": "1.8.5", -      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", -      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", +      "version": "2.3.2", +      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", +      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",        "dev": true, -      "optional": true,        "requires": { -        "expand-range": "^1.8.1", -        "preserve": "^0.2.0", -        "repeat-element": "^1.1.2" +        "arr-flatten": "^1.1.0", +        "array-unique": "^0.3.2", +        "extend-shallow": "^2.0.1", +        "fill-range": "^4.0.0", +        "isobject": "^3.0.1", +        "repeat-element": "^1.1.2", +        "snapdragon": "^0.8.1", +        "snapdragon-node": "^2.0.1", +        "split-string": "^3.0.2", +        "to-regex": "^3.0.1"        }      },      "brorand": { @@ -1725,21 +1650,24 @@        "dev": true      },      "chokidar": { -      "version": "1.7.0", -      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", -      "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", +      "version": "2.1.5", +      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", +      "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",        "dev": true,        "optional": true,        "requires": { -        "anymatch": "^1.3.0", -        "async-each": "^1.0.0", -        "fsevents": "^1.0.0", -        "glob-parent": "^2.0.0", -        "inherits": "^2.0.1", +        "anymatch": "^2.0.0", +        "async-each": "^1.0.1", +        "braces": "^2.3.2", +        "fsevents": "^1.2.7", +        "glob-parent": "^3.1.0", +        "inherits": "^2.0.3",          "is-binary-path": "^1.0.0", -        "is-glob": "^2.0.0", +        "is-glob": "^4.0.0", +        "normalize-path": "^3.0.0",          "path-is-absolute": "^1.0.0", -        "readdirp": "^2.0.0" +        "readdirp": "^2.2.1", +        "upath": "^1.1.1"        }      },      "chownr": { @@ -2013,10 +1941,13 @@        "dev": true      },      "convert-source-map": { -      "version": "1.5.1", -      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", -      "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", -      "dev": true +      "version": "1.6.0", +      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", +      "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", +      "dev": true, +      "requires": { +        "safe-buffer": "~5.1.1" +      }      },      "cookie": {        "version": "0.3.1", @@ -2470,15 +2401,6 @@        "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",        "dev": true      }, -    "detect-indent": { -      "version": "4.0.0", -      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", -      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", -      "dev": true, -      "requires": { -        "repeating": "^2.0.0" -      } -    },      "di": {        "version": "0.0.1",        "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -3149,23 +3071,18 @@        }      },      "expand-brackets": { -      "version": "0.1.5", -      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", -      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", +      "version": "2.1.4", +      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", +      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",        "dev": true, -      "optional": true, -      "requires": { -        "is-posix-bracket": "^0.1.0" -      } -    }, -    "expand-range": { -      "version": "1.8.2", -      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", -      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", -      "dev": true, -      "optional": true,        "requires": { -        "fill-range": "^2.1.0" +        "debug": "^2.3.3", +        "define-property": "^0.2.5", +        "extend-shallow": "^2.0.1", +        "posix-character-classes": "^0.1.0", +        "regex-not": "^1.0.0", +        "snapdragon": "^0.8.1", +        "to-regex": "^3.0.1"        }      },      "expand-tilde": { @@ -3282,13 +3199,65 @@        }      },      "extglob": { -      "version": "0.3.2", -      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", -      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", +      "version": "2.0.4", +      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", +      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",        "dev": true, -      "optional": true,        "requires": { -        "is-extglob": "^1.0.0" +        "array-unique": "^0.3.2", +        "define-property": "^1.0.0", +        "expand-brackets": "^2.1.4", +        "extend-shallow": "^2.0.1", +        "fragment-cache": "^0.2.1", +        "regex-not": "^1.0.0", +        "snapdragon": "^0.8.1", +        "to-regex": "^3.0.1" +      }, +      "dependencies": { +        "define-property": { +          "version": "1.0.0", +          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", +          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", +          "dev": true, +          "requires": { +            "is-descriptor": "^1.0.0" +          } +        }, +        "is-accessor-descriptor": { +          "version": "1.0.0", +          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", +          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", +          "dev": true, +          "requires": { +            "kind-of": "^6.0.0" +          } +        }, +        "is-data-descriptor": { +          "version": "1.0.0", +          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", +          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", +          "dev": true, +          "requires": { +            "kind-of": "^6.0.0" +          } +        }, +        "is-descriptor": { +          "version": "1.0.2", +          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", +          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", +          "dev": true, +          "requires": { +            "is-accessor-descriptor": "^1.0.0", +            "is-data-descriptor": "^1.0.0", +            "kind-of": "^6.0.2" +          } +        }, +        "kind-of": { +          "version": "6.0.2", +          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", +          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", +          "dev": true +        }        }      },      "extsprintf": { @@ -3339,25 +3308,16 @@          "flat-cache": "^2.0.1"        }      }, -    "filename-regex": { -      "version": "2.0.1", -      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", -      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", -      "dev": true, -      "optional": true -    },      "fill-range": { -      "version": "2.2.4", -      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", -      "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", +      "version": "4.0.0", +      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", +      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",        "dev": true, -      "optional": true,        "requires": { -        "is-number": "^2.1.0", -        "isobject": "^2.0.0", -        "randomatic": "^3.0.0", -        "repeat-element": "^1.1.2", -        "repeat-string": "^1.5.2" +        "extend-shallow": "^2.0.1", +        "is-number": "^3.0.0", +        "repeat-string": "^1.6.1", +        "to-regex-range": "^2.1.0"        }      },      "finalhandler": { @@ -3384,23 +3344,23 @@        }      },      "find-cache-dir": { -      "version": "1.0.0", -      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", -      "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", +      "version": "2.1.0", +      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", +      "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",        "dev": true,        "requires": {          "commondir": "^1.0.1", -        "make-dir": "^1.0.0", -        "pkg-dir": "^2.0.0" +        "make-dir": "^2.0.0", +        "pkg-dir": "^3.0.0"        }      },      "find-up": { -      "version": "2.1.0", -      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", -      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", +      "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",        "dev": true,        "requires": { -        "locate-path": "^2.0.0" +        "locate-path": "^3.0.0"        }      },      "findup-sync": { @@ -3847,16 +3807,6 @@        "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",        "dev": true      }, -    "for-own": { -      "version": "0.1.5", -      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", -      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", -      "dev": true, -      "optional": true, -      "requires": { -        "for-in": "^1.0.1" -      } -    },      "foreach": {        "version": "2.0.5",        "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -3998,12 +3948,14 @@          "balanced-match": {            "version": "1.0.0",            "bundled": true, -          "dev": true +          "dev": true, +          "optional": true          },          "brace-expansion": {            "version": "1.1.11",            "bundled": true,            "dev": true, +          "optional": true,            "requires": {              "balanced-match": "^1.0.0",              "concat-map": "0.0.1" @@ -4023,7 +3975,8 @@          "concat-map": {            "version": "0.0.1",            "bundled": true, -          "dev": true +          "dev": true, +          "optional": true          },          "console-control-strings": {            "version": "1.1.0", @@ -4171,6 +4124,7 @@            "version": "3.0.4",            "bundled": true,            "dev": true, +          "optional": true,            "requires": {              "brace-expansion": "^1.1.7"            } @@ -4620,24 +4574,27 @@          "path-is-absolute": "^1.0.0"        }      }, -    "glob-base": { -      "version": "0.3.0", -      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", -      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", -      "dev": true, -      "optional": true, -      "requires": { -        "glob-parent": "^2.0.0", -        "is-glob": "^2.0.0" -      } -    },      "glob-parent": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", -      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", +      "version": "3.1.0", +      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", +      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",        "dev": true, +      "optional": true,        "requires": { -        "is-glob": "^2.0.0" +        "is-glob": "^3.1.0", +        "path-dirname": "^1.0.0" +      }, +      "dependencies": { +        "is-glob": { +          "version": "3.1.0", +          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", +          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", +          "dev": true, +          "optional": true, +          "requires": { +            "is-extglob": "^2.1.0" +          } +        }        }      },      "global-modules": { @@ -4665,9 +4622,9 @@        }      },      "globals": { -      "version": "9.18.0", -      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", -      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", +      "version": "11.11.0", +      "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", +      "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==",        "dev": true      },      "globule": { @@ -4865,14 +4822,13 @@          "minimalistic-crypto-utils": "^1.0.1"        }      }, -    "home-or-tmp": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", -      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", +    "hoist-non-react-statics": { +      "version": "3.3.0", +      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", +      "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",        "dev": true,        "requires": { -        "os-homedir": "^1.0.0", -        "os-tmpdir": "^1.0.1" +        "react-is": "^16.7.0"        }      },      "homedir-polyfill": { @@ -5435,23 +5391,6 @@          }        }      }, -    "is-dotfile": { -      "version": "1.0.3", -      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", -      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", -      "dev": true, -      "optional": true -    }, -    "is-equal-shallow": { -      "version": "0.1.3", -      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", -      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", -      "dev": true, -      "optional": true, -      "requires": { -        "is-primitive": "^2.0.0" -      } -    },      "is-extendable": {        "version": "0.1.1",        "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -5459,9 +5398,9 @@        "dev": true      },      "is-extglob": { -      "version": "1.0.0", -      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", -      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", +      "version": "2.1.1", +      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", +      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",        "dev": true      },      "is-finite": { @@ -5480,24 +5419,30 @@        "dev": true      },      "is-glob": { -      "version": "2.0.1", -      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", -      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", +      "version": "4.0.1", +      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", +      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",        "dev": true, +      "optional": true,        "requires": { -        "is-extglob": "^1.0.0" +        "is-extglob": "^2.1.1"        }      },      "is-number": { -      "version": "2.1.0", -      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", -      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", +      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",        "dev": true, -      "optional": true,        "requires": {          "kind-of": "^3.0.2"        }      }, +    "is-plain-obj": { +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", +      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", +      "dev": true +    },      "is-plain-object": {        "version": "2.0.4",        "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -5515,20 +5460,6 @@          }        }      }, -    "is-posix-bracket": { -      "version": "0.1.1", -      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", -      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", -      "dev": true, -      "optional": true -    }, -    "is-primitive": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", -      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", -      "dev": true, -      "optional": true -    },      "is-promise": {        "version": "2.1.0",        "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -5596,14 +5527,10 @@        "dev": true      },      "isobject": { -      "version": "2.1.0", -      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", -      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", -      "dev": true, -      "optional": true, -      "requires": { -        "isarray": "1.0.0" -      } +      "version": "3.0.1", +      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", +      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", +      "dev": true      },      "isstream": {        "version": "0.1.2", @@ -5640,9 +5567,9 @@        "dev": true      },      "jsesc": { -      "version": "1.3.0", -      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", -      "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", +      "version": "2.5.2", +      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", +      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",        "dev": true      },      "json-parse-better-errors": { @@ -6466,19 +6393,19 @@        }      },      "locate-path": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", -      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", +      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",        "dev": true,        "requires": { -        "p-locate": "^2.0.0", +        "p-locate": "^3.0.0",          "path-exists": "^3.0.0"        }      },      "lodash": { -      "version": "4.17.10", -      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", -      "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", +      "version": "4.17.11", +      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", +      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",        "dev": true      },      "lodash.tail": { @@ -6609,12 +6536,21 @@        }      },      "make-dir": { -      "version": "1.3.0", -      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", -      "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", +      "version": "2.1.0", +      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", +      "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",        "dev": true,        "requires": { -        "pify": "^3.0.0" +        "pify": "^4.0.1", +        "semver": "^5.6.0" +      }, +      "dependencies": { +        "pify": { +          "version": "4.0.1", +          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", +          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", +          "dev": true +        }        }      },      "mamacro": { @@ -6653,13 +6589,6 @@          "object-visit": "^1.0.0"        }      }, -    "math-random": { -      "version": "1.0.1", -      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", -      "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", -      "dev": true, -      "optional": true -    },      "md5.js": {        "version": "1.3.5",        "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -6745,25 +6674,90 @@        "dev": true      },      "micromatch": { -      "version": "2.3.11", -      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", -      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", +      "version": "3.1.10", +      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", +      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",        "dev": true, -      "optional": true,        "requires": { -        "arr-diff": "^2.0.0", -        "array-unique": "^0.2.1", -        "braces": "^1.8.2", -        "expand-brackets": "^0.1.4", -        "extglob": "^0.3.1", -        "filename-regex": "^2.0.0", -        "is-extglob": "^1.0.0", -        "is-glob": "^2.0.1", -        "kind-of": "^3.0.2", -        "normalize-path": "^2.0.1", -        "object.omit": "^2.0.0", -        "parse-glob": "^3.0.4", -        "regex-cache": "^0.4.2" +        "arr-diff": "^4.0.0", +        "array-unique": "^0.3.2", +        "braces": "^2.3.1", +        "define-property": "^2.0.2", +        "extend-shallow": "^3.0.2", +        "extglob": "^2.0.4", +        "fragment-cache": "^0.2.1", +        "kind-of": "^6.0.2", +        "nanomatch": "^1.2.9", +        "object.pick": "^1.3.0", +        "regex-not": "^1.0.0", +        "snapdragon": "^0.8.1", +        "to-regex": "^3.0.2" +      }, +      "dependencies": { +        "define-property": { +          "version": "2.0.2", +          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", +          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", +          "dev": true, +          "requires": { +            "is-descriptor": "^1.0.2", +            "isobject": "^3.0.1" +          } +        }, +        "extend-shallow": { +          "version": "3.0.2", +          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", +          "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", +          "dev": true, +          "requires": { +            "assign-symbols": "^1.0.0", +            "is-extendable": "^1.0.1" +          } +        }, +        "is-accessor-descriptor": { +          "version": "1.0.0", +          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", +          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", +          "dev": true, +          "requires": { +            "kind-of": "^6.0.0" +          } +        }, +        "is-data-descriptor": { +          "version": "1.0.0", +          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", +          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", +          "dev": true, +          "requires": { +            "kind-of": "^6.0.0" +          } +        }, +        "is-descriptor": { +          "version": "1.0.2", +          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", +          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", +          "dev": true, +          "requires": { +            "is-accessor-descriptor": "^1.0.0", +            "is-data-descriptor": "^1.0.0", +            "kind-of": "^6.0.2" +          } +        }, +        "is-extendable": { +          "version": "1.0.1", +          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", +          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", +          "dev": true, +          "requires": { +            "is-plain-object": "^2.0.4" +          } +        }, +        "kind-of": { +          "version": "6.0.2", +          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", +          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", +          "dev": true +        }        }      },      "miller-rabin": { @@ -7503,13 +7497,11 @@        }      },      "normalize-path": { -      "version": "2.1.1", -      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", -      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", +      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",        "dev": true, -      "requires": { -        "remove-trailing-separator": "^1.0.1" -      } +      "optional": true      },      "npm-run-path": {        "version": "2.0.2", @@ -7633,17 +7625,6 @@          "es-abstract": "^1.5.1"        }      }, -    "object.omit": { -      "version": "2.0.1", -      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", -      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", -      "dev": true, -      "optional": true, -      "requires": { -        "for-own": "^0.1.4", -        "is-extendable": "^0.1.1" -      } -    },      "object.pick": {        "version": "1.3.0",        "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -7758,14 +7739,14 @@        }      },      "output-file-sync": { -      "version": "1.1.2", -      "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", -      "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", +      "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==",        "dev": true,        "requires": { -        "graceful-fs": "^4.1.4", -        "mkdirp": "^0.5.1", -        "object-assign": "^4.1.0" +        "graceful-fs": "^4.1.11", +        "is-plain-obj": "^1.1.0", +        "mkdirp": "^0.5.1"        }      },      "p-defer": { @@ -7787,27 +7768,27 @@        "dev": true      },      "p-limit": { -      "version": "1.2.0", -      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", -      "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", +      "version": "2.2.0", +      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", +      "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",        "dev": true,        "requires": { -        "p-try": "^1.0.0" +        "p-try": "^2.0.0"        }      },      "p-locate": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", -      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", +      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",        "dev": true,        "requires": { -        "p-limit": "^1.1.0" +        "p-limit": "^2.0.0"        }      },      "p-try": { -      "version": "1.0.0", -      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", -      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", +      "version": "2.2.0", +      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", +      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",        "dev": true      },      "pako": { @@ -7859,19 +7840,6 @@          "safe-buffer": "^5.1.1"        }      }, -    "parse-glob": { -      "version": "3.0.4", -      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", -      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", -      "dev": true, -      "optional": true, -      "requires": { -        "glob-base": "^0.3.0", -        "is-dotfile": "^1.0.0", -        "is-extglob": "^1.0.0", -        "is-glob": "^2.0.0" -      } -    },      "parse-json": {        "version": "2.2.0",        "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -8042,12 +8010,12 @@        }      },      "pkg-dir": { -      "version": "2.0.0", -      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", -      "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", +      "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",        "dev": true,        "requires": { -        "find-up": "^2.1.0" +        "find-up": "^3.0.0"        }      },      "posix-character-classes": { @@ -8349,31 +8317,12 @@        "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",        "dev": true      }, -    "preact": { -      "version": "8.4.2", -      "resolved": "https://registry.npmjs.org/preact/-/preact-8.4.2.tgz", -      "integrity": "sha512-TsINETWiisfB6RTk0wh3/mvxbGRvx+ljeBccZ4Z6MPFKgu/KFGyf2Bmw3Z/jlXhL5JlNKY6QAbA9PVyzIy9//A==", -      "dev": true -    }, -    "preact-redux": { -      "version": "2.0.3", -      "resolved": "https://registry.npmjs.org/preact-redux/-/preact-redux-2.0.3.tgz", -      "integrity": "sha1-lgpTXDImQ801mY8z8MLme8Hn6qs=", -      "dev": true -    },      "prelude-ls": {        "version": "1.1.2",        "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",        "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",        "dev": true      }, -    "preserve": { -      "version": "0.2.0", -      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", -      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", -      "dev": true, -      "optional": true -    },      "pretty-error": {        "version": "2.1.1",        "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -8384,12 +8333,6 @@          "utila": "~0.4"        }      }, -    "private": { -      "version": "0.1.8", -      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", -      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", -      "dev": true -    },      "process": {        "version": "0.11.10",        "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -8529,34 +8472,6 @@        "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",        "dev": true      }, -    "randomatic": { -      "version": "3.0.0", -      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", -      "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", -      "dev": true, -      "optional": true, -      "requires": { -        "is-number": "^4.0.0", -        "kind-of": "^6.0.0", -        "math-random": "^1.0.1" -      }, -      "dependencies": { -        "is-number": { -          "version": "4.0.0", -          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", -          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", -          "dev": true, -          "optional": true -        }, -        "kind-of": { -          "version": "6.0.2", -          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", -          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", -          "dev": true, -          "optional": true -        } -      } -    },      "randombytes": {        "version": "2.1.0",        "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -8594,6 +8509,84 @@          "unpipe": "1.0.0"        }      }, +    "react": { +      "version": "16.8.6", +      "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", +      "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", +      "dev": true, +      "requires": { +        "loose-envify": "^1.1.0", +        "object-assign": "^4.1.1", +        "prop-types": "^15.6.2", +        "scheduler": "^0.13.6" +      } +    }, +    "react-dom": { +      "version": "16.8.6", +      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", +      "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", +      "dev": true, +      "requires": { +        "loose-envify": "^1.1.0", +        "object-assign": "^4.1.1", +        "prop-types": "^15.6.2", +        "scheduler": "^0.13.6" +      } +    }, +    "react-is": { +      "version": "16.8.6", +      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", +      "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", +      "dev": true +    }, +    "react-redux": { +      "version": "7.0.3", +      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.0.3.tgz", +      "integrity": "sha512-vYZA7ftOYlDk3NetitsI7fLjryt/widNl1SLXYvFenIpm7vjb4ryK0EeFrgn62usg5fYkyIAWNUPKnwWPevKLg==", +      "dev": true, +      "requires": { +        "@babel/runtime": "^7.4.3", +        "hoist-non-react-statics": "^3.3.0", +        "invariant": "^2.2.4", +        "loose-envify": "^1.4.0", +        "prop-types": "^15.7.2", +        "react-is": "^16.8.6" +      }, +      "dependencies": { +        "loose-envify": { +          "version": "1.4.0", +          "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", +          "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", +          "dev": true, +          "requires": { +            "js-tokens": "^3.0.0 || ^4.0.0" +          } +        }, +        "prop-types": { +          "version": "15.7.2", +          "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", +          "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", +          "dev": true, +          "requires": { +            "loose-envify": "^1.4.0", +            "object-assign": "^4.1.1", +            "react-is": "^16.8.1" +          } +        } +      } +    }, +    "react-test-renderer": { +      "version": "16.8.6", +      "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.6.tgz", +      "integrity": "sha512-H2srzU5IWYT6cZXof6AhUcx/wEyJddQ8l7cLM/F7gDXYyPr4oq+vCIxJYXVGhId1J706sqziAjuOEjyNkfgoEw==", +      "dev": true, +      "requires": { +        "object-assign": "^4.1.1", +        "prop-types": "^15.6.2", +        "react-is": "^16.8.6", +        "scheduler": "^0.13.6" +      } +    },      "read-pkg": {        "version": "1.1.0",        "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -8652,16 +8645,15 @@        }      },      "readdirp": { -      "version": "2.1.0", -      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", -      "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", +      "version": "2.2.1", +      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", +      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",        "dev": true,        "optional": true,        "requires": { -        "graceful-fs": "^4.1.2", -        "minimatch": "^3.0.2", -        "readable-stream": "^2.0.2", -        "set-immediate-shim": "^1.0.1" +        "graceful-fs": "^4.1.11", +        "micromatch": "^3.1.10", +        "readable-stream": "^2.0.2"        }      },      "redent": { @@ -8711,16 +8703,6 @@        "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",        "dev": true      }, -    "regex-cache": { -      "version": "0.4.4", -      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", -      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", -      "dev": true, -      "optional": true, -      "requires": { -        "is-equal-shallow": "^0.1.3" -      } -    },      "regex-not": {        "version": "1.0.2",        "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -9080,6 +9062,16 @@          "semver": "^5.5.0"        }      }, +    "scheduler": { +      "version": "0.13.6", +      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", +      "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", +      "dev": true, +      "requires": { +        "loose-envify": "^1.1.0", +        "object-assign": "^4.1.1" +      } +    },      "schema-utils": {        "version": "1.0.0",        "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -9321,9 +9313,9 @@        }      },      "slash": { -      "version": "1.0.0", -      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", -      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", +      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",        "dev": true      },      "slice-ansi": { @@ -9553,15 +9545,6 @@          "urix": "^0.1.0"        }      }, -    "source-map-support": { -      "version": "0.4.18", -      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", -      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", -      "dev": true, -      "requires": { -        "source-map": "^0.5.6" -      } -    },      "source-map-url": {        "version": "0.4.0",        "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -10182,9 +10165,9 @@        "dev": true      },      "to-fast-properties": { -      "version": "1.0.3", -      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", -      "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", +      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",        "dev": true      },      "to-object-path": { @@ -10598,12 +10581,6 @@        "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",        "dev": true      }, -    "user-home": { -      "version": "1.1.1", -      "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", -      "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", -      "dev": true -    },      "useragent": {        "version": "2.3.0",        "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", @@ -10663,15 +10640,6 @@        "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==",        "dev": true      }, -    "v8flags": { -      "version": "2.1.1", -      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", -      "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", -      "dev": true, -      "requires": { -        "user-home": "^1.1.1" -      } -    },      "validate-npm-package-license": {        "version": "3.0.4",        "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 7c758a2..98cdc60 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@    },    "homepage": "https://github.com/ueokande/vim-vixen",    "devDependencies": { -    "babel-cli": "^6.26.0", +    "@babel/cli": "^7.4.4", +    "@babel/core": "^7.4.4", +    "@babel/preset-react": "^7.0.0",      "babel-eslint": "^10.0.1", -    "babel-loader": "^7.1.5", -    "babel-preset-preact": "^1.1.0", -    "babel-preset-stage-2": "^6.24.1", +    "babel-loader": "^8.0.5",      "chai": "^4.2.0",      "css-loader": "^2.1.1",      "eslint": "^5.16.0", @@ -42,8 +42,10 @@      "lanthan": "git+https://github.com/ueokande/lanthan.git#master",      "mocha": "^6.1.4",      "node-sass": "^4.12.0", -    "preact": "^8.4.2", -    "preact-redux": "^2.0.3", +    "react": "^16.8.6", +    "react-dom": "^16.8.6", +    "react-redux": "^7.0.3", +    "react-test-renderer": "^16.8.6",      "redux": "^4.0.1",      "redux-promise": "^0.6.0",      "sass-loader": "^7.1.0", diff --git a/src/background/domains/Completions.js b/src/background/domains/Completions.js index 4e4219f..f399743 100644 --- a/src/background/domains/Completions.js +++ b/src/background/domains/Completions.js @@ -19,9 +19,9 @@ export default class Completions {      }));    } -  static EMPTY_COMPLETIONS = new Completions([]); -    static empty() { -    return Completions.EMPTY_COMPLETIONS; +    return EMPTY_COMPLETIONS;    }  } + +let EMPTY_COMPLETIONS = new Completions([]); diff --git a/src/console/components/console.jsx b/src/console/components/Console.jsx index 7994f78..5427e43 100644 --- a/src/console/components/console.jsx +++ b/src/console/components/Console.jsx @@ -1,17 +1,18 @@  import './console.scss'; -import { connect } from 'preact-redux'; -import { Component, h } from 'preact'; -import Input from './console/input'; -import Completion from './console/completion'; -import Message from './console/message'; +import { connect } from 'react-redux'; +import React from 'react'; +import PropTypes from 'prop-types'; +import Input from './console/Input'; +import Completion from './console/Completion'; +import Message from './console/Message';  import * as consoleActions from '../../console/actions/console';  const COMPLETION_MAX_ITEMS = 33; -class ConsoleComponent extends Component { +class Console extends React.Component {    onBlur() {      if (this.props.mode === 'command' || this.props.mode === 'find') { -      return this.context.store.dispatch(consoleActions.hideCommand()); +      return this.props.dispatch(consoleActions.hideCommand());      }    } @@ -21,45 +22,45 @@ class ConsoleComponent extends Component {      let value = e.target.value;      if (this.props.mode === 'command') { -      return this.context.store.dispatch(consoleActions.enterCommand(value)); +      return this.props.dispatch(consoleActions.enterCommand(value));      } else if (this.props.mode === 'find') { -      return this.context.store.dispatch(consoleActions.enterFind(value)); +      return this.props.dispatch(consoleActions.enterFind(value));      }    }    selectNext(e) { -    this.context.store.dispatch(consoleActions.completionNext()); +    this.props.dispatch(consoleActions.completionNext());      e.stopPropagation();      e.preventDefault();    }    selectPrev(e) { -    this.context.store.dispatch(consoleActions.completionPrev()); +    this.props.dispatch(consoleActions.completionPrev());      e.stopPropagation();      e.preventDefault();    }    onKeyDown(e) {      if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) { -      this.context.store.dispatch(consoleActions.hideCommand()); +      this.props.dispatch(consoleActions.hideCommand());      }      switch (e.keyCode) {      case KeyboardEvent.DOM_VK_ESCAPE: -      return this.context.store.dispatch(consoleActions.hideCommand()); +      return this.props.dispatch(consoleActions.hideCommand());      case KeyboardEvent.DOM_VK_RETURN:        return this.doEnter(e);      case KeyboardEvent.DOM_VK_TAB:        if (e.shiftKey) { -        this.context.store.dispatch(consoleActions.completionPrev()); +        this.props.dispatch(consoleActions.completionPrev());        } else { -        this.context.store.dispatch(consoleActions.completionNext()); +        this.props.dispatch(consoleActions.completionNext());        }        e.stopPropagation();        e.preventDefault();        break;      case KeyboardEvent.DOM_VK_OPEN_BRACKET:        if (e.ctrlKey) { -        return this.context.store.dispatch(consoleActions.hideCommand()); +        return this.props.dispatch(consoleActions.hideCommand());        }        break;      case KeyboardEvent.DOM_VK_M: @@ -80,11 +81,11 @@ class ConsoleComponent extends Component {      }    } -  onInput(e) { +  onChange(e) {      let text = e.target.value; -    this.context.store.dispatch(consoleActions.setConsoleText(text)); +    this.props.dispatch(consoleActions.setConsoleText(text));      if (this.props.mode === 'command') { -      this.context.store.dispatch(consoleActions.getCompletions(text)); +      this.props.dispatch(consoleActions.getCompletions(text));      }    } @@ -94,7 +95,7 @@ class ConsoleComponent extends Component {        return;      }      if (prevProps.mode !== 'command' && this.props.mode === 'command') { -      this.context.store.dispatch( +      this.props.dispatch(          consoleActions.getCompletions(this.props.consoleText));        this.focus();      } else if (prevProps.mode !== 'find' && this.props.mode === 'find') { @@ -117,7 +118,7 @@ class ConsoleComponent extends Component {            mode={this.props.mode}            onBlur={this.onBlur.bind(this)}            onKeyDown={this.onKeyDown.bind(this)} -          onInput={this.onInput.bind(this)} +          onChange={this.onChange.bind(this)}            value={this.props.consoleText}          />        </div>; @@ -126,6 +127,8 @@ class ConsoleComponent extends Component {        return <Message mode={ this.props.mode } >          { this.props.messageText }        </Message>; +    default: +      return null;      }    } @@ -135,5 +138,12 @@ class ConsoleComponent extends Component {    }  } +Console.propTypes = { +  mode: PropTypes.string, +  consoleText: PropTypes.string, +  messageText: PropTypes.string, +  children: PropTypes.string, +}; +  const mapStateToProps = state => state; -export default connect(mapStateToProps)(ConsoleComponent); +export default connect(mapStateToProps)(Console); diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/Completion.jsx index d836cec..5477cb6 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/Completion.jsx @@ -1,29 +1,9 @@ -import { Component, h } from 'preact'; +import React from 'react'; +import PropTypes from 'prop-types'; +import CompletionItem from './CompletionItem'; +import CompletionTitle from './CompletionTitle'; -const CompletionTitle = (props) => { -  return <li className='vimvixen-console-completion-title' >{props.title}</li>; -}; - -const CompletionItem = (props) => { -  let className = 'vimvixen-console-completion-item'; -  if (props.highlight) { -    className += ' vimvixen-completion-selected'; -  } -  return <li -    className={className} -    style={{ backgroundImage: 'url(' + props.icon + ')' }} -  > -    <span -      className='vimvixen-console-completion-item-caption' -    >{props.caption}</span> -    <span -      className='vimvixen-console-completion-item-url' -    >{props.url}</span> -  </li>; -}; - - -class CompletionComponent extends Component { +class Completion extends React.Component {    constructor() {      super();      this.state = { viewOffset: 0, select: -1 }; @@ -63,9 +43,13 @@ class CompletionComponent extends Component {      let index = 0;      for (let group of this.props.completions) { -      eles.push(<CompletionTitle title={ group.name }/>); +      eles.push(<CompletionTitle +        key={`group-${index}`} +        title={ group.name } +      />);        for (let item of group.items) {          eles.push(<CompletionItem +          key={`item-${index}`}            icon={item.icon}            caption={item.caption}            url={item.url} @@ -86,4 +70,17 @@ class CompletionComponent extends Component {    }  } -export default CompletionComponent; +Completion.propTypes = { +  select: PropTypes.number, +  size: PropTypes.number, +  completions: PropTypes.arrayOf(PropTypes.shape({ +    name: PropTypes.string, +    items: PropTypes.arrayOf(PropTypes.shape({ +      icon: PropTypes.string, +      caption: PropTypes.string, +      url: PropTypes.string, +    })), +  })), +}; + +export default Completion; diff --git a/src/console/components/console/CompletionItem.jsx b/src/console/components/console/CompletionItem.jsx new file mode 100644 index 0000000..3dc552b --- /dev/null +++ b/src/console/components/console/CompletionItem.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const CompletionItem = (props) => { +  let className = 'vimvixen-console-completion-item'; +  if (props.highlight) { +    className += ' vimvixen-completion-selected'; +  } +  return <li +    className={className} +    style={{ backgroundImage: 'url(' + props.icon + ')' }} +  > +    <span +      className='vimvixen-console-completion-item-caption' +    >{props.caption}</span> +    <span +      className='vimvixen-console-completion-item-url' +    >{props.url}</span> +  </li>; +}; + +CompletionItem.propTypes = { +  highlight: PropTypes.bool, +  caption: PropTypes.string, +  url: PropTypes.string, +}; + +export default CompletionItem; diff --git a/src/console/components/console/CompletionTitle.jsx b/src/console/components/console/CompletionTitle.jsx new file mode 100644 index 0000000..4fcba3f --- /dev/null +++ b/src/console/components/console/CompletionTitle.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const CompletionTitle = (props) => { +  return <li className='vimvixen-console-completion-title'> +    {props.title} +  </li>; +}; + +CompletionTitle.propTypes = { +  title: PropTypes.string, +}; + +export default CompletionTitle; diff --git a/src/console/components/console/input.jsx b/src/console/components/console/Input.jsx index d59e6e7..cbd3348 100644 --- a/src/console/components/console/input.jsx +++ b/src/console/components/console/Input.jsx @@ -1,6 +1,7 @@ -import { Component, h } from 'preact'; +import React from 'react'; +import PropTypes from 'prop-types'; -export default class InputComponent extends Component { +class Input extends React.Component {    focus() {      this.input.focus();    } @@ -23,10 +24,20 @@ export default class InputComponent extends Component {            ref={(c) => { this.input = c; }}            onBlur={this.props.onBlur}            onKeyDown={this.props.onKeyDown} -          onInput={this.props.onInput} +          onChange={this.props.onChange}            value={this.props.value}          />        </div>      );    }  } + +Input.propTypes = { +  mode: PropTypes.string, +  value: PropTypes.string, +  onBlur: PropTypes.func, +  onKeyDown: PropTypes.func, +  onChange: PropTypes.func, +}; + +export default Input; diff --git a/src/console/components/console/message.jsx b/src/console/components/console/Message.jsx index 5b60af4..dd96248 100644 --- a/src/console/components/console/message.jsx +++ b/src/console/components/console/Message.jsx @@ -1,6 +1,7 @@ -import { h } from 'preact'; +import React from 'react'; +import PropTypes from 'prop-types'; -export default function Message(props) { +const Message = (props) => {    switch (props.mode) {    case 'error':      return ( @@ -15,4 +16,10 @@ export default function Message(props) {        </p>      );    } -} +}; + +Message.propTypes = { +  children: PropTypes.string, +}; + +export default Message; diff --git a/src/console/index.html b/src/console/index.html index 5c1e99c..73e1e23 100644 --- a/src/console/index.html +++ b/src/console/index.html @@ -5,5 +5,7 @@      <title>VimVixen console</title>      <script src='console.js'></script>    </head> -  <body class='vimvixen-console'></body> +  <body> +    <div id='vimvixen-console' class='vimvixen-console'></div> +  </body>  </html> diff --git a/src/console/index.jsx b/src/console/index.jsx index dfd323e..3190a9a 100644 --- a/src/console/index.jsx +++ b/src/console/index.jsx @@ -3,11 +3,10 @@ import reducers from 'console/reducers';  import { createStore, applyMiddleware } from 'redux';  import promise from 'redux-promise';  import * as consoleActions from 'console/actions/console'; - -import { Provider } from 'preact-redux'; -import Console from './components/console'; - -import { render, h } from 'preact'; +import { Provider } from 'react-redux'; +import Console from './components/Console'; +import React from 'react'; +import ReactDOM from 'react-dom';  const store = createStore(    reducers, @@ -15,11 +14,12 @@ const store = createStore(  );  window.addEventListener('load', () => { -  render( +  let wrapper = document.getElementById('vimvixen-console'); +  ReactDOM.render(      <Provider store={store} >        <Console></Console>      </Provider>, -    document.body); +    wrapper);  });  const onMessage = (message) => { diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index 0277159..db63a45 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -1,8 +1,8 @@  import actions from 'settings/actions';  import * as validator from 'shared/settings/validator'; -import KeymapsForm from '../components/form/keymaps-form';  import * as settingsValues from 'shared/settings/values';  import * as settingsStorage from 'shared/settings/storage'; +import keymaps from '../keymaps';  const load = async() => {    let settings = await settingsStorage.loadRaw(); @@ -29,8 +29,7 @@ const save = async(settings) => {  const switchToForm = (json) => {    try {      validator.validate(JSON.parse(json)); -    // AllowdOps filters operations, this is dirty dependency -    let form = settingsValues.formFromJson(json, KeymapsForm.AllowdOps); +    let form = settingsValues.formFromJson(json, keymaps.allowedOps);      return {        type: actions.SETTING_SWITCH_TO_FORM,        form, @@ -61,4 +60,4 @@ const set = (settings) => {    };  }; -export { load, save, switchToForm, switchToJson }; +export { load, save, set, switchToForm, switchToJson }; diff --git a/src/settings/components/form/blacklist-form.jsx b/src/settings/components/form/BlacklistForm.jsx index 7ae9652..c470758 100644 --- a/src/settings/components/form/blacklist-form.jsx +++ b/src/settings/components/form/BlacklistForm.jsx @@ -1,38 +1,34 @@ -import './blacklist-form.scss'; -import AddButton from '../ui/add-button'; -import DeleteButton from '../ui/delete-button'; -import { h, Component } from 'preact'; +import './BlacklistForm.scss'; +import AddButton from '../ui/AddButton'; +import DeleteButton from '../ui/DeleteButton'; +import React from 'react'; +import PropTypes from 'prop-types'; -class BlacklistForm extends Component { +class BlacklistForm extends React.Component {    render() { -    let value = this.props.value; -    if (!value) { -      value = []; -    } -      return <div className='form-blacklist-form'>        { -        value.map((url, index) => { +        this.props.value.map((url, index) => {            return <div key={index} className='form-blacklist-form-row'>              <input data-index={index} type='text' name='url'                className='column-url' value={url} -              onChange={this.bindValue.bind(this)} /> +              onChange={this.bindValue.bind(this)} +              onBlur={this.props.onBlur} +            />              <DeleteButton data-index={index} name='delete' -              onClick={this.bindValue.bind(this)} /> +              onClick={this.bindValue.bind(this)} +              onBlur={this.props.onBlur} +            />            </div>;          })        } -      <AddButton name='add' style='float:right' +      <AddButton name='add' style={{ float: 'right' }}          onClick={this.bindValue.bind(this)} />      </div>;    }    bindValue(e) { -    if (!this.props.onChange) { -      return; -    } -      let name = e.target.name;      let index = e.target.getAttribute('data-index');      let next = this.props.value ? this.props.value.slice() : []; @@ -46,7 +42,22 @@ class BlacklistForm extends Component {      }      this.props.onChange(next); +    if (name === 'delete') { +      this.props.onBlur(); +    }    }  } +BlacklistForm.propTypes = { +  value: PropTypes.arrayOf(PropTypes.string), +  onChange: PropTypes.func, +  onBlur: PropTypes.func, +}; + +BlacklistForm.defaultProps = { +  value: [], +  onChange: () => {}, +  onBlur: () => {}, +}; +  export default BlacklistForm; diff --git a/src/settings/components/form/blacklist-form.scss b/src/settings/components/form/BlacklistForm.scss index a230d0d..a230d0d 100644 --- a/src/settings/components/form/blacklist-form.scss +++ b/src/settings/components/form/BlacklistForm.scss diff --git a/src/settings/components/form/KeymapsForm.jsx b/src/settings/components/form/KeymapsForm.jsx new file mode 100644 index 0000000..01acf61 --- /dev/null +++ b/src/settings/components/form/KeymapsForm.jsx @@ -0,0 +1,51 @@ +import './KeymapsForm.scss'; +import React from 'react'; +import PropTypes from 'prop-types'; +import Input from '../ui/Input'; +import keymaps from '../../keymaps'; + +class KeymapsForm extends React.Component { + +  render() { +    return <div className='form-keymaps-form'> +      { +        keymaps.fields.map((group, index) => { +          return <div key={index} className='form-keymaps-form-field-group'> +            { +              group.map((field) => { +                let name = field[0]; +                let label = field[1]; +                let value = this.props.value[name] || ''; +                return <Input +                  type='text' id={name} name={name} key={name} +                  label={label} value={value} +                  onChange={this.bindValue.bind(this)} +                  onBlur={this.props.onBlur} +                />; +              }) +            } +          </div>; +        }) +      } +    </div>; +  } + +  bindValue(e) { +    let next = { ...this.props.value }; +    next[e.target.name] = e.target.value; + +    this.props.onChange(next); +  } +} + +KeymapsForm.propTypes = { +  value: PropTypes.objectOf(PropTypes.string), +  onChange: PropTypes.func, +}; + +KeymapsForm.defaultProps = { +  value: {}, +  onChange: () => {}, +}; + +export default KeymapsForm; diff --git a/src/settings/components/form/keymaps-form.scss b/src/settings/components/form/KeymapsForm.scss index 1a4e5cd..1a4e5cd 100644 --- a/src/settings/components/form/keymaps-form.scss +++ b/src/settings/components/form/KeymapsForm.scss diff --git a/src/settings/components/form/properties-form.jsx b/src/settings/components/form/PropertiesForm.jsx index ceb79d7..979fdd8 100644 --- a/src/settings/components/form/properties-form.jsx +++ b/src/settings/components/form/PropertiesForm.jsx @@ -1,14 +1,12 @@ -import './properties-form.scss'; -import { h, Component } from 'preact'; +import './PropertiesForm.scss'; +import React from 'react'; +import PropTypes from 'prop-types'; -class PropertiesForm extends Component { +class PropertiesForm extends React.Component {    render() {      let types = this.props.types;      let value = this.props.value; -    if (!value) { -      value = {}; -    }      return <div className='form-properties-form'>        { @@ -29,6 +27,7 @@ class PropertiesForm extends Component {                  className='column-input'                  value={value[name] ? value[name] : ''}                  onChange={this.bindValue.bind(this)} +                onBlur={this.props.onBlur}                  checked={value[name]}                />              </label> @@ -39,10 +38,6 @@ class PropertiesForm extends Component {    }    bindValue(e) { -    if (!this.props.onChange) { -      return; -    } -      let name = e.target.name;      let next = { ...this.props.value };      if (e.target.type.toLowerCase() === 'checkbox') { @@ -57,4 +52,14 @@ class PropertiesForm extends Component {    }  } +PropertiesForm.propTypes = { +  value: PropTypes.objectOf(PropTypes.any), +  onChange: PropTypes.func, +}; + +PropertiesForm.defaultProps = { +  value: {}, +  onChange: () => {}, +}; +  export default PropertiesForm; diff --git a/src/settings/components/form/properties-form.scss b/src/settings/components/form/PropertiesForm.scss index 7c9e167..7c9e167 100644 --- a/src/settings/components/form/properties-form.scss +++ b/src/settings/components/form/PropertiesForm.scss diff --git a/src/settings/components/form/search-form.jsx b/src/settings/components/form/SearchForm.jsx index 2d5f01b..6b0bd01 100644 --- a/src/settings/components/form/search-form.jsx +++ b/src/settings/components/form/SearchForm.jsx @@ -1,15 +1,13 @@ -import './search-form.scss'; -import { h, Component } from 'preact'; -import AddButton from '../ui/add-button'; -import DeleteButton from '../ui/delete-button'; +import './SearchForm.scss'; +import React from 'react'; +import PropTypes from 'prop-types'; +import AddButton from '../ui/AddButton'; +import DeleteButton from '../ui/DeleteButton'; -class SearchForm extends Component { +class SearchForm extends React.Component {    render() {      let value = this.props.value; -    if (!value) { -      value = { default: '', engines: []}; -    }      if (!value.engines) {        value.engines = [];      } @@ -25,11 +23,15 @@ class SearchForm extends Component {            return <div key={index} className='form-search-form-row'>              <input data-index={index} type='text' name='name'                className='column-name' value={engine[0]} -              onChange={this.bindValue.bind(this)} /> +              onChange={this.bindValue.bind(this)} +              onBlur={this.props.onBlur} +            />              <input data-index={index} type='text' name='url'                placeholder='http://example.com/?q={}'                className='column-url' value={engine[1]} -              onChange={this.bindValue.bind(this)} /> +              onChange={this.bindValue.bind(this)} +              onBlur={this.props.onBlur} +            />              <div className='column-option'>                <input data-index={index} type='radio' name='default'                  checked={value.default === engine[0]} @@ -40,16 +42,12 @@ class SearchForm extends Component {            </div>;          })        } -      <AddButton name='add' style='float:right' +      <AddButton name='add' style={{ float: 'right' }}          onClick={this.bindValue.bind(this)} />      </div>;    }    bindValue(e) { -    if (!this.props.onChange) { -      return; -    } -      let value = this.props.value;      let name = e.target.name;      let index = e.target.getAttribute('data-index'); @@ -72,7 +70,23 @@ class SearchForm extends Component {      }      this.props.onChange(next); +    if (name === 'delete' || name === 'default') { +      this.props.onBlur(); +    }    }  } +SearchForm.propTypes = { +  value: PropTypes.shape({ +    default: PropTypes.string, +    engines: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), +  }), +  onChange: PropTypes.func, +}; + +SearchForm.defaultProps = { +  value: { default: '', engines: []}, +  onChange: () => {}, +}; +  export default SearchForm; diff --git a/src/settings/components/form/search-form.scss b/src/settings/components/form/SearchForm.scss index 26b2f44..26b2f44 100644 --- a/src/settings/components/form/search-form.scss +++ b/src/settings/components/form/SearchForm.scss diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index 9633359..4ef59d7 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -1,11 +1,11 @@  import './site.scss'; -import { h, Component } from 'preact'; -import { connect } from 'preact-redux'; -import Input from './ui/input'; -import SearchForm from './form/search-form'; -import KeymapsForm from './form/keymaps-form'; -import BlacklistForm from './form/blacklist-form'; -import PropertiesForm from './form/properties-form'; +import React from 'react'; +import { connect } from 'react-redux'; +import Input from './ui/Input'; +import SearchForm from './form/SearchForm'; +import KeymapsForm from './form/KeymapsForm'; +import BlacklistForm from './form/BlacklistForm'; +import PropertiesForm from './form/PropertiesForm';  import * as properties from 'shared/settings/properties';  import * as settingActions from 'settings/actions/setting'; @@ -13,7 +13,7 @@ const DO_YOU_WANT_TO_CONTINUE =    'Some settings in JSON can be lost when migrating.  ' +    'Do you want to continue?'; -class SettingsComponent extends Component { +class SettingsComponent extends React.Component {    componentDidMount() {      this.props.dispatch(settingActions.load());    } @@ -25,6 +25,7 @@ class SettingsComponent extends Component {          <KeymapsForm            value={form.keymaps}            onChange={value => this.bindForm('keymaps', value)} +          onBlur={this.save.bind(this)}          />        </fieldset>        <fieldset> @@ -32,6 +33,7 @@ class SettingsComponent extends Component {          <SearchForm            value={form.search}            onChange={value => this.bindForm('search', value)} +          onBlur={this.save.bind(this)}          />        </fieldset>        <fieldset> @@ -39,6 +41,7 @@ class SettingsComponent extends Component {          <BlacklistForm            value={form.blacklist}            onChange={value => this.bindForm('blacklist', value)} +          onBlur={this.save.bind(this)}          />        </fieldset>        <fieldset> @@ -47,6 +50,7 @@ class SettingsComponent extends Component {            types={properties.types}            value={form.properties}            onChange={value => this.bindForm('properties', value)} +          onBlur={this.save.bind(this)}          />        </fieldset>      </div>; @@ -61,6 +65,7 @@ class SettingsComponent extends Component {          spellCheck='false'          error={error}          onChange={this.bindJson.bind(this)} +        onBlur={this.save.bind(this)}          value={json}        />      </div>; @@ -109,7 +114,7 @@ class SettingsComponent extends Component {        form: { ...this.props.form },      };      settings.form[name] = value; -    this.props.dispatch(settingActions.save(settings)); +    this.props.dispatch(settingActions.set(settings));    }    bindJson(e) { @@ -118,7 +123,7 @@ class SettingsComponent extends Component {        json: e.target.value,        form: this.props.form,      }; -    this.props.dispatch(settingActions.save(settings)); +    this.props.dispatch(settingActions.set(settings));    }    bindSource(e) { @@ -135,8 +140,10 @@ class SettingsComponent extends Component {        }        this.props.dispatch(settingActions.switchToForm(this.props.json));      } +  } -    let settings = this.context.store.getState(); +  save() { +    let settings = this.props.store.getState();      this.props.dispatch(settingActions.save(settings));    }  } diff --git a/src/settings/components/ui/add-button.jsx b/src/settings/components/ui/AddButton.jsx index 79292d8..185a03b 100644 --- a/src/settings/components/ui/add-button.jsx +++ b/src/settings/components/ui/AddButton.jsx @@ -1,7 +1,7 @@ -import './add-button.scss'; -import { h, Component } from 'preact'; +import './AddButton.scss'; +import React from 'react'; -class AddButton extends Component { +class AddButton extends React.Component {    render() {      return <input        className='ui-add-button' type='button' value='✚' diff --git a/src/settings/components/ui/add-button.scss b/src/settings/components/ui/AddButton.scss index beb5688..beb5688 100644 --- a/src/settings/components/ui/add-button.scss +++ b/src/settings/components/ui/AddButton.scss diff --git a/src/settings/components/ui/delete-button.jsx b/src/settings/components/ui/DeleteButton.jsx index 8077a76..75811cd 100644 --- a/src/settings/components/ui/delete-button.jsx +++ b/src/settings/components/ui/DeleteButton.jsx @@ -1,7 +1,7 @@ -import './delete-button.scss'; -import { h, Component } from 'preact'; +import './DeleteButton.scss'; +import React from 'react'; -class DeleteButton extends Component { +class DeleteButton extends React.Component {    render() {      return <input        className='ui-delete-button' type='button' value='✖' diff --git a/src/settings/components/ui/delete-button.scss b/src/settings/components/ui/DeleteButton.scss index 5932a72..5932a72 100644 --- a/src/settings/components/ui/delete-button.scss +++ b/src/settings/components/ui/DeleteButton.scss diff --git a/src/settings/components/ui/input.jsx b/src/settings/components/ui/Input.jsx index e99dbc7..13a246b 100644 --- a/src/settings/components/ui/input.jsx +++ b/src/settings/components/ui/Input.jsx @@ -1,7 +1,8 @@ -import { h, Component } from 'preact'; -import './input.scss'; +import React from 'react'; +import PropTypes from 'prop-types'; +import './Input.scss'; -class Input extends Component { +class Input extends React.Component {    renderText(props) {      let inputClassName = props.error ? 'input-error' : ''; @@ -49,4 +50,11 @@ class Input extends Component {    }  } +Input.propTypes = { +  type: PropTypes.string, +  error: PropTypes.string, +  label: PropTypes.string, +  value: PropTypes.string, +}; +  export default Input; diff --git a/src/settings/components/ui/input.scss b/src/settings/components/ui/Input.scss index ad4daf8..ad4daf8 100644 --- a/src/settings/components/ui/input.scss +++ b/src/settings/components/ui/Input.scss diff --git a/src/settings/index.jsx b/src/settings/index.jsx index 8097d31..6aec7a0 100644 --- a/src/settings/index.jsx +++ b/src/settings/index.jsx @@ -1,7 +1,8 @@ -import { h, render } from 'preact'; +import React from 'react'; +import ReactDOM from 'react-dom';  import SettingsComponent from './components';  import reducer from './reducers/setting'; -import { Provider } from 'preact-redux'; +import { Provider } from 'react-redux';  import promise from 'redux-promise';  import { createStore, applyMiddleware } from 'redux'; @@ -12,9 +13,9 @@ const store = createStore(  document.addEventListener('DOMContentLoaded', () => {    let wrapper = document.getElementById('vimvixen-settings'); -  render( +  ReactDOM.render(      <Provider store={store}> -      <SettingsComponent /> +      <SettingsComponent store={store} />      </Provider>,      wrapper    ); diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/keymaps.js index ca51c96..ccfc74c 100644 --- a/src/settings/components/form/keymaps-form.jsx +++ b/src/settings/keymaps.js @@ -1,8 +1,4 @@ -import './keymaps-form.scss'; -import { h, Component } from 'preact'; -import Input from '../ui/input'; - -const KeyMapFields = [ +const fields = [    [      ['scroll.vertically?{"count":1}', 'Scroll down'],      ['scroll.vertically?{"count":-1}', 'Scroll up'], @@ -70,49 +66,9 @@ const KeyMapFields = [    ]  ]; -const AllowdOps = [].concat(...KeyMapFields.map(group => group.map(e => e[0]))); - -class KeymapsForm extends Component { - -  render() { -    let values = this.props.value; -    if (!values) { -      values = {}; -    } -    return <div className='form-keymaps-form'> -      { -        KeyMapFields.map((group, index) => { -          return <div key={index} className='form-keymaps-form-field-group'> -            { -              group.map((field) => { -                let name = field[0]; -                let label = field[1]; -                let value = values[name]; -                return <Input -                  type='text' id={name} name={name} key={name} -                  label={label} value={value} -                  onChange={this.bindValue.bind(this)} -                />; -              }) -            } -          </div>; -        }) -      } -    </div>; -  } - -  bindValue(e) { -    if (!this.props.onChange) { -      return; -    } - -    let next = { ...this.props.value }; -    next[e.target.name] = e.target.value; - -    this.props.onChange(next); -  } -} - -KeymapsForm.AllowdOps = AllowdOps; +const allowedOps = [].concat(...fields.map(group => group.map(e => e[0]))); -export default KeymapsForm; +export default { +  fields, +  allowedOps, +}; diff --git a/test/console/components/console/Completion.test.jsx b/test/console/components/console/Completion.test.jsx new file mode 100644 index 0000000..16bf11a --- /dev/null +++ b/test/console/components/console/Completion.test.jsx @@ -0,0 +1,168 @@ +import React from 'react'; +import Completion from 'console/components/console/Completion' +import ReactTestRenderer from 'react-test-renderer'; + +describe("console/components/console/completion", () => { +  let completions = [{ +    name: "Fruit", +    items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], +  }, { +    name: "Element", +    items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], +  }]; + +  it('renders Completion component', () => { +    let root = ReactTestRenderer.create(<Completion +      completions={completions} +      size={30} +      />).root; + +    expect(root.children).to.have.lengthOf(1); + +    let children = root.children[0].children; +    expect(children).to.have.lengthOf(8); +    expect(children[0].props.title).to.equal('Fruit'); +    expect(children[1].props.caption).to.equal('apple'); +    expect(children[2].props.caption).to.equal('banana'); +    expect(children[3].props.caption).to.equal('cherry'); +    expect(children[4].props.title).to.equal('Element'); +    expect(children[5].props.caption).to.equal('argon'); +    expect(children[6].props.caption).to.equal('boron'); +    expect(children[7].props.caption).to.equal('carbon'); +  }); + +  it('highlight current item', () => { +    let root = ReactTestRenderer.create(<Completion +      completions={completions} +      size={30} +      select={3} +      />).root; + +    let children = root.children[0].children; +    expect(children[5].props.highlight).to.be.true; +  }); + +  it('does not highlight any items', () => { +    let root = ReactTestRenderer.create(<Completion +      completions={completions} +      size={30} +      select={-1} +      />).root; + +    let children = root.children[0].children; +    for (let li of children[0].children) { +      expect(li.props.highlight).not.to.be.ok; +    } +  }); + +  it('limits completion items', () => { +    let root = ReactTestRenderer.create(<Completion +      completions={completions} +      size={3} +      select={-1} +      />).root; + +    let children = root.children[0].children; +    expect(children).to.have.lengthOf(3); + +    expect(children[0].props.title).to.equal('Fruit'); +    expect(children[1].props.caption).to.equal('apple'); +    expect(children[2].props.caption).to.equal('banana'); + +    root = ReactTestRenderer.create(<Completion +      completions={completions} +      size={3} select={0} +      />).root; + +    children = root.children[0].children; +    expect(children[1].props.highlight).to.be.true; +  }) + +  it('scrolls up to down with select', () => { +    let component = ReactTestRenderer.create(<Completion +      completions={completions} +      size={3} +      select={1} +      />); +    let instance = component.getInstance(); +    let root = component.root; + +    let children = root.children[0].children; +    expect(children).to.have.lengthOf(3); +    expect(children[0].props.title).to.equal('Fruit'); +    expect(children[1].props.caption).to.equal('apple'); +    expect(children[2].props.caption).to.equal('banana'); + +    component.update(<Completion +      completions={completions} +      size={3} +      select={2} +    />); + +    children = root.children[0].children; +    expect(children).to.have.lengthOf(3); +    expect(children[0].props.caption).to.equal('apple'); +    expect(children[1].props.caption).to.equal('banana'); +    expect(children[2].props.caption).to.equal('cherry'); +    expect(children[2].props.highlight).to.be.true; + +    component.update(<Completion +      completions={completions} +      size={3} +      select={3} +    />); + +    children = root.children[0].children; +    expect(children).to.have.lengthOf(3); +    expect(children[0].props.caption).to.equal('cherry'); +    expect(children[1].props.title).to.equal('Element'); +    expect(children[2].props.caption).to.equal('argon'); +    expect(children[2].props.highlight).to.be.true; +  }); + +  it('scrolls down to up with select', () => { +    let component = ReactTestRenderer.create(<Completion +      completions={completions} +      size={3} +      select={5} +      />); +    let root = component.root; +    let instance = component.getInstance(); + +    let children = root.children[0].children; +    expect(children).to.have.lengthOf(3); +    expect(children[0].props.caption).to.equal('argon'); +    expect(children[1].props.caption).to.equal('boron'); +    expect(children[2].props.caption).to.equal('carbon'); + +    component.update(<Completion +      completions={completions} +      size={3} +      select={4} +    />); + +    children = root.children[0].children; +    expect(children[1].props.highlight).to.be.true; + +    component.update(<Completion +      completions={completions} +      size={3} +      select={3} +    />); + +    children = root.children[0].children; +    expect(children[0].props.highlight).to.be.true; + +    component.update(<Completion +      completions={completions} +      size={3} +      select={2} +    />); + +    children = root.children[0].children; +    expect(children[0].props.caption).to.equal('cherry'); +    expect(children[1].props.title).to.equal('Element'); +    expect(children[2].props.caption).to.equal('argon'); +    expect(children[0].props.highlight).to.be.true; +  }); +}); diff --git a/test/console/components/console/completion.test.jsx b/test/console/components/console/completion.test.jsx deleted file mode 100644 index 0b48fe2..0000000 --- a/test/console/components/console/completion.test.jsx +++ /dev/null @@ -1,138 +0,0 @@ -import { h, render } from 'preact'; -import Completion from 'console/components/console/completion' - -describe("console/components/console/completion", () => { -  let completions = [{ -    name: "Fruit", -    items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], -  }, { -    name: "Element", -    items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], -  }]; - -  beforeEach(() => { -    document.body.innerHTML = ''; -  }); - -  it('renders Completion component', () => { -    let ul = render(<Completion -      completions={completions} -      size={30} -      />, document.body); - -    expect(ul.children).to.have.lengthOf(8); -    expect(ul.children[0].textContent).to.equal('Fruit'); -    expect(ul.children[1].textContent).to.equal('apple'); -    expect(ul.children[2].textContent).to.equal('banana'); -    expect(ul.children[3].textContent).to.equal('cherry'); -    expect(ul.children[4].textContent).to.equal('Element'); -    expect(ul.children[5].textContent).to.equal('argon'); -    expect(ul.children[6].textContent).to.equal('boron'); -    expect(ul.children[7].textContent).to.equal('carbon'); -  }); - -  it('highlight current item', () => { -    let ul = render(<Completion -      completions={completions} -      size={30} -      select={3} -      />, document.body); -    expect(ul.children[5].className.split(' ')).to.include('vimvixen-completion-selected'); -  }); - -  it('does not highlight any items', () => { -    let ul = render(<Completion -      completions={completions} -      size={30} -      select={-1} -      />, document.body); -    for (let li of ul.children) { -      expect(li.className.split(' ')).not.to.include('vimvixen-completion-selected'); -    } -  }); - - -  it('limits completion items', () => { -    let ul = render(<Completion -      completions={completions} -      size={3} -      select={-1} -      />, document.body); -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); - -    ul = render(<Completion -      completions={completions} -      size={3} select={0} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); -    expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); -  }) - -  it('scrolls up to down with select', () => { -    let ul = render(<Completion -      completions={completions} -      size={3} -      select={1} -      />, document.body); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); -    expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - -    ul = render(<Completion -      completions={completions} -      size={3} -      select={2} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['apple', 'banana', 'cherry']); -    expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - -    ul = render(<Completion -      completions={completions} -      size={3} -      select={3} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); -    expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); -  }); - -  it('scrolls up to down with select', () => { -    let ul = render(<Completion -      completions={completions} -      size={3} -      select={5} -      />, document.body); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); -    expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - -    ul = render(<Completion -      completions={completions} -      size={3} -      select={4} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); -    expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); - -    ul = render(<Completion -      completions={completions} -      size={3} -      select={3} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); -    expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); - -    ul = render(<Completion -      completions={completions} -      size={3} -      select={2} -      />, document.body, ul); - -    expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); -    expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); -  }); -}); diff --git a/test/settings/components/form/BlacklistForm.test.jsx b/test/settings/components/form/BlacklistForm.test.jsx new file mode 100644 index 0000000..2be5d96 --- /dev/null +++ b/test/settings/components/form/BlacklistForm.test.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import BlacklistForm from 'settings/components/form/BlacklistForm' + +describe("settings/form/BlacklistForm", () => { +  describe('render', () => { +    it('renders BlacklistForm', () => { +      let root = ReactTestRenderer.create( +        <BlacklistForm value={['*.slack.com', 'www.google.com/maps']} />, +      ).root; + +      let children = root.children[0].children; +      expect(children).to.have.lengthOf(3); +      expect(children[0].children[0].props.value).to.equal('*.slack.com'); +      expect(children[1].children[0].props.value).to.equal('www.google.com/maps'); +      expect(children[2].props.name).to.equal('add'); +    }); + +    it('renders blank value', () => { +      let root = ReactTestRenderer.create(<BlacklistForm />).root; + +      let children = root.children[0].children; +      expect(children).to.have.lengthOf(1); +      expect(children[0].props.name).to.equal('add'); +    }); +  }); + +  describe('onChange', () => { +    let container; + +    beforeEach(() => { +      container = document.createElement('div'); +      document.body.appendChild(container); +    }); + +    afterEach(() => { +      document.body.removeChild(container); +      container = null; +    }); + +    it('invokes onChange event on edit', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<BlacklistForm +          value={['*.slack.com', 'www.google.com/maps*']} +          onChange={value => { +            expect(value).to.have.lengthOf(2); +            expect(value).to.have.members(['gitter.im', 'www.google.com/maps*']); +            done(); +          }} +        />, container) +      }); + +      let input = document.querySelectorAll('input[type=text]')[0]; +      input.value = 'gitter.im'; +      ReactTestUtils.Simulate.change(input); +    }); + +    it('invokes onChange event on delete', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<BlacklistForm +          value={['*.slack.com', 'www.google.com/maps*']} +          onChange={value => { +            expect(value).to.have.lengthOf(1); +            expect(value).to.have.members(['www.google.com/maps*']); +            done(); +          }} +        />, container) +      }); + +      let button = document.querySelectorAll('input[type=button]')[0]; +      ReactTestUtils.Simulate.click(button); +    }); + +    it('invokes onChange event on add', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<BlacklistForm +          value={['*.slack.com']} +          onChange={value => { +            expect(value).to.have.lengthOf(2); +            expect(value).to.have.members(['*.slack.com', '']); +            done(); +          }} +        />, container); +      }); + +      let button = document.querySelector('input[type=button].ui-add-button'); +      ReactTestUtils.Simulate.click(button); +    }); +  }); +}); diff --git a/test/settings/components/form/KeymapsForm.test.jsx b/test/settings/components/form/KeymapsForm.test.jsx new file mode 100644 index 0000000..6ac57c9 --- /dev/null +++ b/test/settings/components/form/KeymapsForm.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import KeymapsForm from 'settings/components/form/KeymapsForm' + +describe("settings/form/KeymapsForm", () => { +  describe('render', () => { +    it('renders keymap fields', () => { +      let root = ReactTestRenderer.create(<KeymapsForm value={{ +        'scroll.vertically?{"count":1}': 'j', +        'scroll.vertically?{"count":-1}': 'k', +      }} />).root + +      let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); +      let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + +      expect(inputj.props.value).to.equal('j'); +      expect(inputk.props.value).to.equal('k'); +    }); + +    it('renders blank value', () => { +      let root = ReactTestRenderer.create(<KeymapsForm />).root; + +      let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); +      let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + +      expect(inputj.props.value).to.be.empty; +      expect(inputk.props.value).to.be.empty; +    }); +  }); + +  describe('onChange event', () => { +    let container; + +    beforeEach(() => { +      container = document.createElement('div'); +      document.body.appendChild(container); +    }); + +    afterEach(() => { +      document.body.removeChild(container); +      container = null; +    }); + +    it('invokes onChange event on edit', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<KeymapsForm +          value={{ +            'scroll.vertically?{"count":1}': 'j', +            'scroll.vertically?{"count":-1}': 'k', +          }} +          onChange={value => { +            expect(value['scroll.vertically?{"count":1}']).to.equal('jjj'); +            done(); +          }} />, container); +      }); + +      let input = document.getElementById('scroll.vertically?{"count":1}'); +      input.value = 'jjj'; +      ReactTestUtils.Simulate.change(input); +    }); +  }); +}); diff --git a/test/settings/components/form/PropertiesForm.test.jsx b/test/settings/components/form/PropertiesForm.test.jsx new file mode 100644 index 0000000..80f60d2 --- /dev/null +++ b/test/settings/components/form/PropertiesForm.test.jsx @@ -0,0 +1,104 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import PropertiesForm from 'settings/components/form/PropertiesForm' + +describe("settings/form/PropertiesForm", () => { +  describe('render', () => { +    it('renders PropertiesForm', () => { +      let types = { +        mystr: 'string', +        mynum: 'number', +        mybool: 'boolean', +        empty: 'string', +      } +      let value = { +        mystr: 'abc', +        mynum: 123, +        mybool: true, +      }; + +      let root = ReactTestRenderer.create( +        <PropertiesForm types={types} value={value} />, +      ).root + +      let input = root.findByProps({ name: 'mystr' }); +      expect(input.props.type).to.equals('text'); +      expect(input.props.value).to.equal('abc'); + +      input = root.findByProps({ name: 'mynum' }); +      expect(input.props.type).to.equals('number'); +      expect(input.props.value).to.equal(123); + +      input = root.findByProps({ name: 'mybool' }); +      expect(input.props.type).to.equals('checkbox'); +      expect(input.props.value).to.equal(true); +    }); +  }); + +  describe('onChange', () => { +    let container; + +    beforeEach(() => { +      container = document.createElement('div'); +      document.body.appendChild(container); +    }); + +    afterEach(() => { +      document.body.removeChild(container); +      container = null; +    }); + +    it('invokes onChange event on text changed', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<PropertiesForm +          types={{ 'myvalue': 'string' }} +          value={{ 'myvalue': 'abc' }} +          onChange={value => { +            expect(value).to.have.property('myvalue', 'abcd'); +            done(); +          }} +        />, container); +      }); + +      let input = document.querySelector('input[name=myvalue]'); +      input.value = 'abcd' +      ReactTestUtils.Simulate.change(input); +    }); + +    it('invokes onChange event on number changeed', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<PropertiesForm +          types={{ 'myvalue': 'number' }} +          value={{ '': 123 }} +          onChange={value => { +            expect(value).to.have.property('myvalue', 1234); +            done(); +          }} +        />, container); +      }); + +      let input = document.querySelector('input[name=myvalue]'); +      input.value = '1234' +      ReactTestUtils.Simulate.change(input); +    }); + +    it('invokes onChange event on checkbox changed', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<PropertiesForm +          types={{ 'myvalue': 'boolean' }} +          value={{ 'myvalue': false }} +          onChange={value => { +            expect(value).to.have.property('myvalue', true); +            done(); +          }} +        />, container); +      }); + +      let input = document.querySelector('input[name=myvalue]'); +      input.checked = true; +      ReactTestUtils.Simulate.change(input); +    }); +  }); +}); diff --git a/test/settings/components/form/SearchEngineForm.test.jsx b/test/settings/components/form/SearchEngineForm.test.jsx new file mode 100644 index 0000000..06822f2 --- /dev/null +++ b/test/settings/components/form/SearchEngineForm.test.jsx @@ -0,0 +1,128 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import SearchForm from 'settings/components/form/SearchForm' + +describe("settings/form/SearchForm", () => { +  describe('render', () => { +    it('renders SearchForm', () => { +      let root = ReactTestRenderer.create(<SearchForm value={{ +        default: 'google', +        engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']], +      }} />).root; + +      let names = root.findAllByProps({ name: 'name' }); +      expect(names).to.have.lengthOf(2); +      expect(names[0].props.value).to.equal('google'); +      expect(names[1].props.value).to.equal('yahoo'); + +      let urls = root.findAllByProps({ name: 'url' }); +      expect(urls).to.have.lengthOf(2); +      expect(urls[0].props.value).to.equal('google.com'); +      expect(urls[1].props.value).to.equal('yahoo.com'); +    }); + +    it('renders blank value', () => { +      let root = ReactTestRenderer.create(<SearchForm />).root; + +      let names = root.findAllByProps({ name: 'name' }); +      expect(names).to.be.empty; + +      let urls = root.findAllByProps({ name: 'url' }); +      expect(urls).to.be.empty; +    }); + +    it('renders blank engines', () => { +      let root = ReactTestRenderer.create( +        <SearchForm value={{ default: 'google' }} />, +      ).root; + +      let names = root.findAllByProps({ name: 'name' }); +      expect(names).to.be.empty; + +      let urls = root.findAllByProps({ name: 'url' }); +      expect(urls).to.be.empty; +    }); +  }); + +  describe('onChange event', () => { +    let container; + +    beforeEach(() => { +      container = document.createElement('div'); +      document.body.appendChild(container); +    }); + +    afterEach(() => { +      document.body.removeChild(container); +      container = null; +    }); + +    it('invokes onChange event on edit', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<SearchForm +          value={{ +            default: 'google', +              engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']] +          }} +          onChange={value => { +            expect(value.default).to.equal('louvre'); +            expect(value.engines).to.have.lengthOf(2) +            expect(value.engines).to.have.deep.members( +              [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] +            ); +            done(); +          }} />, container); +      }); + +      let radio = document.querySelectorAll('input[type=radio]'); +      radio.checked = true; + +      let name = document.querySelector('input[name=name]'); +      name.value = 'louvre'; + +      ReactTestUtils.Simulate.change(name); +    }); + +    it('invokes onChange event on delete', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<SearchForm value={{ +            default: 'yahoo', +            engines: [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] +          }} +          onChange={value => { +            expect(value.default).to.equal('yahoo'); +            expect(value.engines).to.have.lengthOf(1) +            expect(value.engines).to.have.deep.members( +              [['yahoo', 'yahoo.com']] +            ); +            done(); +          }} />, container); +      }); + +      let button = document.querySelector('input[type=button]'); +      ReactTestUtils.Simulate.click(button); +    }); + +    it('invokes onChange event on add', (done) => { +      ReactTestUtils.act(() => { +        ReactDOM.render(<SearchForm value={{ +          default: 'yahoo', +            engines: [['google', 'google.com']] +          }} +          onChange={value => { +            expect(value.default).to.equal('yahoo'); +            expect(value.engines).to.have.lengthOf(2) +            expect(value.engines).to.have.deep.members( +              [['google', 'google.com'], ['', '']], +            ); +            done(); +          }} />, container); +      }); + +      let button = document.querySelector('input[type=button].ui-add-button'); +      ReactTestUtils.Simulate.click(button); +    }); +  }); +}); diff --git a/test/settings/components/form/blacklist-form.test.jsx b/test/settings/components/form/blacklist-form.test.jsx deleted file mode 100644 index 1c46943..0000000 --- a/test/settings/components/form/blacklist-form.test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { h, render } from 'preact'; -import BlacklistForm from 'settings/components/form/blacklist-form' - -describe("settings/form/BlacklistForm", () => { -  beforeEach(() => { -    document.body.innerHTML = ''; -  }); - -  describe('render', () => { -    it('renders BlacklistForm', () => { -      render(<BlacklistForm value={['*.slack.com', 'www.google.com/maps']} />, document.body); - -      let inputs = document.querySelectorAll('input[type=text]'); -      expect(inputs).to.have.lengthOf(2); -      expect(inputs[0].value).to.equal('*.slack.com'); -      expect(inputs[1].value).to.equal('www.google.com/maps'); -    }); - -    it('renders blank value', () => { -      render(<BlacklistForm />, document.body); - -      let inputs = document.querySelectorAll('input[type=text]'); -      expect(inputs).to.be.empty; -    }); - -    it('renders blank value', () => { -      render(<BlacklistForm />, document.body); - -      let inputs = document.querySelectorAll('input[type=text]'); -      expect(inputs).to.be.empty; -    }); -  }); - -  describe('onChange', () => { -    it('invokes onChange event on edit', (done) => { -      render(<BlacklistForm -        value={['*.slack.com', 'www.google.com/maps*']} -        onChange={value => { -          expect(value).to.have.lengthOf(2) -            .and.have.members(['gitter.im', 'www.google.com/maps*']); - -          done(); -        }} -      />, document.body); - -      let input = document.querySelectorAll('input[type=text]')[0]; -      input.value = 'gitter.im'; -      input.dispatchEvent(new Event('change')) -    }); - -    it('invokes onChange event on delete', (done) => { -      render(<BlacklistForm -        value={['*.slack.com', 'www.google.com/maps*']} -        onChange={value => { -          expect(value).to.have.lengthOf(1) -            .and.have.members(['www.google.com/maps*']); - -          done(); -        }} -      />, document.body); - -      let button = document.querySelectorAll('input[type=button]')[0]; -      button.click(); -    }); - -    it('invokes onChange event on add', (done) => { -      render(<BlacklistForm -        value={['*.slack.com']} -        onChange={value => { -          expect(value).to.have.lengthOf(2) -            .and.have.members(['*.slack.com', '']); - -          done(); -        }} -      />, document.body); - -      let button = document.querySelector('input[type=button].ui-add-button'); -      button.click(); -    }); -  }); -}); diff --git a/test/settings/components/form/keymaps-form.test.jsx b/test/settings/components/form/keymaps-form.test.jsx deleted file mode 100644 index 55edf8c..0000000 --- a/test/settings/components/form/keymaps-form.test.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import { h, render } from 'preact'; -import KeymapsForm from 'settings/components/form/keymaps-form' - -describe("settings/form/KeymapsForm", () => { -  beforeEach(() => { -    document.body.innerHTML = ''; -  }); - -  describe('render', () => { -    it('renders KeymapsForm', () => { -      render(<KeymapsForm value={{ -        'scroll.vertically?{"count":1}': 'j', -        'scroll.vertically?{"count":-1}': 'k', -      }} />, document.body); - -      let inputj = document.getElementById('scroll.vertically?{"count":1}'); -      let inputk = document.getElementById('scroll.vertically?{"count":-1}'); - -      expect(inputj.value).to.equal('j'); -      expect(inputk.value).to.equal('k'); -    }); - -    it('renders blank value', () => { -      render(<KeymapsForm />, document.body); - -      let inputj = document.getElementById('scroll.vertically?{"count":1}'); -      let inputk = document.getElementById('scroll.vertically?{"count":-1}'); - -      expect(inputj.value).to.be.empty; -      expect(inputk.value).to.be.empty; -    }); -  }); - -  describe('onChange event', () => { -    it('invokes onChange event on edit', (done) => { -      render(<KeymapsForm -        value={{ -          'scroll.vertically?{"count":1}': 'j', -          'scroll.vertically?{"count":-1}': 'k', -        }} -        onChange={value => { -          expect(value['scroll.vertically?{"count":1}']).to.equal('jjj'); - -          done(); -        }} />, document.body); - -      let input = document.getElementById('scroll.vertically?{"count":1}'); -      input.value = 'jjj'; -      input.dispatchEvent(new Event('change')) -    }); -  }); -}); diff --git a/test/settings/components/form/properties-form.test.jsx b/test/settings/components/form/properties-form.test.jsx deleted file mode 100644 index 0efe382..0000000 --- a/test/settings/components/form/properties-form.test.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import { h, render } from 'preact'; -import PropertiesForm from 'settings/components/form/properties-form' - -describe("settings/form/PropertiesForm", () => { -  beforeEach(() => { -    document.body.innerHTML = ''; -  }); - -  describe('render', () => { -    it('renders PropertiesForm', () => { -      let types = { -        mystr: 'string', -        mynum: 'number', -        mybool: 'boolean', -        empty: 'string', -      } -      let value = { -        mystr: 'abc', -        mynum: 123, -        mybool: true, -      }; -      render(<PropertiesForm types={types} value={value} />, document.body); - -      let strInput = document.querySelector('input[name=mystr]'); -      let numInput = document.querySelector('input[name=mynum]'); -      let boolInput = document.querySelector('input[name=mybool]'); -      let emptyInput = document.querySelector('input[name=empty]'); - -      expect(strInput.type).to.equals('text'); -      expect(strInput.value).to.equal('abc'); -      expect(numInput.type).to.equals('number'); -      expect(numInput.value).to.equal('123'); -      expect(boolInput.type).to.equals('checkbox'); -      expect(boolInput.checked).to.be.true; -      expect(emptyInput.type).to.equals('text'); -      expect(emptyInput.value).to.be.empty; -    }); -  }); - -  describe('onChange', () => { -    it('invokes onChange event on text changed', (done) => { -      render(<PropertiesForm -        types={{ 'myvalue': 'string' }} -        value={{ 'myvalue': 'abc' }} -        onChange={value => { -          expect(value).to.have.property('myvalue', 'abcd'); -          done(); -        }} -      />, document.body); - -      let input = document.querySelector('input[name=myvalue]'); -      input.value = 'abcd' -      input.dispatchEvent(new Event('change')) -    }); - -    it('invokes onChange event on number changeed', (done) => { -      render(<PropertiesForm -        types={{ 'myvalue': 'number' }} -        value={{ '': 123 }} -        onChange={value => { -          expect(value).to.have.property('myvalue', 1234); -          done(); -        }} -      />, document.body); - -      let input = document.querySelector('input[name=myvalue]'); -      input.value = '1234' -      input.dispatchEvent(new Event('change')) -    }); - -    it('invokes onChange event on checkbox changed', (done) => { -      render(<PropertiesForm -        types={{ 'myvalue': 'boolean' }} -        value={{ 'myvalue': false }} -        onChange={value => { -          expect(value).to.have.property('myvalue', true); -          done(); -        }} -      />, document.body); - -      let input = document.querySelector('input[name=myvalue]'); -      input.click(); -    }); -  }); -}); diff --git a/test/settings/components/form/search-engine-form.test.jsx b/test/settings/components/form/search-engine-form.test.jsx deleted file mode 100644 index c52419d..0000000 --- a/test/settings/components/form/search-engine-form.test.jsx +++ /dev/null @@ -1,103 +0,0 @@ -import { h, render } from 'preact'; -import SearchForm from 'settings/components/form/search-form' - -describe("settings/form/SearchForm", () => { -  beforeEach(() => { -    document.body.innerHTML = ''; -  }); - -  describe('render', () => { -    it('renders SearchForm', () => { -      render(<SearchForm value={{ -        default: 'google', -        engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']], -      }} />, document.body); - -      let names = document.querySelectorAll('input[name=name]'); -      expect(names).to.have.lengthOf(2); -      expect(names[0].value).to.equal('google'); -      expect(names[1].value).to.equal('yahoo'); - -      let urls = document.querySelectorAll('input[name=url]'); -      expect(urls).to.have.lengthOf(2); -      expect(urls[0].value).to.equal('google.com'); -      expect(urls[1].value).to.equal('yahoo.com'); -    }); - -    it('renders blank value', () => { -      render(<SearchForm />, document.body); - -      let names = document.querySelectorAll('input[name=name]'); -      let urls = document.querySelectorAll('input[name=url]'); -      expect(names).to.have.lengthOf(0); -      expect(urls).to.have.lengthOf(0); -    }); - -    it('renders blank engines', () => { -      render(<SearchForm value={{ default: 'google' }} />, document.body); - -      let names = document.querySelectorAll('input[name=name]'); -      let urls = document.querySelectorAll('input[name=url]'); -      expect(names).to.have.lengthOf(0); -      expect(urls).to.have.lengthOf(0); -    }); -  }); - -  describe('onChange event', () => { -    it('invokes onChange event on edit', (done) => { -      render(<SearchForm -        value={{ -          default: 'google', -          engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']] -        }} -        onChange={value => { -          expect(value.default).to.equal('louvre'); -          expect(value.engines).to.have.lengthOf(2) -            .and.have.deep.members([['louvre', 'google.com'], ['yahoo', 'yahoo.com']]) - -          done(); -        }} />, document.body); - -      let radio = document.querySelectorAll('input[type=radio]'); -      radio.checked = true; - -      let name = document.querySelector('input[name=name]'); -      name.value = 'louvre'; -      name.dispatchEvent(new Event('change')) -    }); - -    it('invokes onChange event on delete', (done) => { -      render(<SearchForm value={{ -          default: 'yahoo', -          engines: [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] -        }} -        onChange={value => { -          expect(value.default).to.equal('yahoo'); -          expect(value.engines).to.have.lengthOf(1) -            .and.have.deep.members([['yahoo', 'yahoo.com']]) - -          done(); -        }} />, document.body); - -      let button = document.querySelector('input[type=button]'); -      button.click(); -    }); - -    it('invokes onChange event on add', (done) => { -      render(<SearchForm value={{ -          default: 'yahoo', -          engines: [['google', 'google.com']] -        }} -        onChange={value => { -          expect(value.default).to.equal('yahoo'); -          expect(value.engines).to.have.lengthOf(2) -            .and.have.deep.members([['google', 'google.com'], ['', '']]) - -          done(); -        }} />, document.body); - -      let button = document.querySelector('input[type=button].ui-add-button'); -      button.click(); -    }); -  }); -}); diff --git a/test/settings/components/ui/input.test.jsx b/test/settings/components/ui/input.test.jsx index 0711bba..432efcb 100644 --- a/test/settings/components/ui/input.test.jsx +++ b/test/settings/components/ui/input.test.jsx @@ -1,14 +1,28 @@ -import { h, render } from 'preact'; -import Input from 'settings/components/ui/input' +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestUtils from 'react-dom/test-utils'; +import Input from 'settings/components/ui/Input'  describe("settings/ui/Input", () => { +  let container; +    beforeEach(() => { -    document.body.innerHTML = ''; +    container = document.createElement('div'); +    document.body.appendChild(container); +  }); + +  afterEach(() => { +    document.body.removeChild(container); +    container = null;    });    context("type=text", () => {      it('renders text input', () => { -      render(<Input type='text' name='myname' label='myfield' value='myvalue'/>, document.body) +      ReactTestUtils.act(() => { +        ReactDOM.render( +          <Input type='text' name='myname' label='myfield' value='myvalue'/>, +          container); +      });        let label = document.querySelector('label');        let input = document.querySelector('input'); @@ -19,20 +33,26 @@ describe("settings/ui/Input", () => {      });      it('invoke onChange', (done) => { -      render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => { -        expect(e.target.value).to.equal('newvalue'); -        done(); -      }}/>, document.body); +      ReactTestUtils.act(() => { +        ReactDOM.render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => { +          expect(e.target.value).to.equal('newvalue'); +          done(); +        }}/>, container); +      });        let input = document.querySelector('input');        input.value = 'newvalue'; -      input.dispatchEvent(new Event('change')) +      ReactTestUtils.Simulate.change(input);      });    });    context("type=radio", () => {      it('renders radio button', () => { -      render(<Input type='radio' name='myname' label='myfield' value='myvalue'/>, document.body) +      ReactTestUtils.act(() => { +        ReactDOM.render( +          <Input type='radio' name='myname' label='myfield' value='myvalue'/>, +          container); +      });        let label = document.querySelector('label');        let input = document.querySelector('input'); @@ -43,20 +63,27 @@ describe("settings/ui/Input", () => {      });      it('invoke onChange', (done) => { -      render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => { -        expect(e.target.checked).to.be.true; -        done(); -      }}/>, document.body); +      ReactTestUtils.act(() => { +        ReactDOM.render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => { +          expect(e.target.checked).to.be.true; +          done(); +        }}/>, +        container); +      });        let input = document.querySelector('input');        input.checked = true; -      input.dispatchEvent(new Event('change')) +      ReactTestUtils.Simulate.change(input);      });    });    context("type=textarea", () => {      it('renders textarea button', () => { -      render(<Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />, document.body) +      ReactTestUtils.act(() => { +        ReactDOM.render( +          <Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />, +          container); +      });        let label = document.querySelector('label');        let textarea = document.querySelector('textarea'); @@ -69,14 +96,16 @@ describe("settings/ui/Input", () => {      });      it('invoke onChange', (done) => { -      render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => { -        expect(e.target.value).to.equal('newvalue'); -        done(); -      }}/>, document.body); +      ReactTestUtils.act(() => { +        ReactDOM.render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => { +          expect(e.target.value).to.equal('newvalue'); +          done(); +        }}/>, container); +      });        let input = document.querySelector('textarea');        input.value = 'newvalue' -      input.dispatchEvent(new Event('change')) +      ReactTestUtils.Simulate.change(input);      });    });  }); diff --git a/webpack.config.js b/webpack.config.js index 90fd526..d9c60cc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -24,7 +24,7 @@ config = {          exclude: /node_modules/,          loader: 'babel-loader',          query: { -          presets: ['preact', 'stage-2'] +          presets: ['@babel/react']          }        },        {  | 
