From d812828c123fe74a754046a019375ceb44ddac48 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Fri, 22 Dec 2017 15:07:08 +0300 Subject: [PATCH 01/48] Switching to node@8 --- .circleci/config.yml | 7 ++----- .nvmrc | 2 +- package.json | 10 ++++------ yarn.lock | 6 +++--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9397c08..4cff802 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2 job-configuration: &job-configuration working_directory: ~/app docker: - - image: circleci/node:6.10 + - image: circleci/node:8.9.1 prepare-git: &prepare-git name: Preparing git working directory @@ -28,12 +28,9 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - - run: - name: Install local yarn - command: npm run yarn:install - run: name: Install dependencies using local yarn - command: npm run yarn:install-deps + command: npm run install-deps - save_cache: key: dependency-cache-{{ checksum "yarn.lock" }} paths: diff --git a/.nvmrc b/.nvmrc index 5a33ecb..e5c1510 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6.10 +8.9.0 diff --git a/package.json b/package.json index bde4834..98b38fe 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,11 @@ "main": "dist/tvdml.js", "engine-strict": true, "engines": { - "node": ">=6.10.0", - "yarn": ">=1.3.0" + "node": "^8.9.0", + "yarn": "^1.3.0" }, "scripts": { - "install-deps": "npm run yarn:install && npm run yarn:install-deps", - "yarn:install": "npm i --no-save --no-package-lock yarn@$npm_package_engines_yarn", - "yarn:install-deps": "yarn install --frozen-lockfile --check-files", + "install-deps": "npx yarn@$npm_package_engines_yarn install --frozen-lockfile --check-files", "build": "webpack --progress", "watch": "webpack --watch --progress", "dist": "NODE_ENV=production webpack --progress", @@ -52,7 +50,7 @@ "jsdom": "^11.5.1", "mocha": "^3.1.2", "mocha-junit-reporter": "^1.15.0", - "webpack": "^3.8.1" + "webpack": "^3.10.0" }, "dependencies": { "@a-ignatov-parc/virtual-dom": "^2.2.0" diff --git a/yarn.lock b/yarn.lock index 0c62b9a..c3e88a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3552,9 +3552,9 @@ webpack-sources@^1.0.1: source-list-map "^2.0.0" source-map "~0.5.3" -webpack@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" +webpack@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" From 2a556e8f48ac1898f16521b16fc1b447c1e2c513 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Fri, 22 Dec 2017 15:24:43 +0300 Subject: [PATCH 02/48] Added react-reconciler module --- package.json | 9 +++++++-- yarn.lock | 22 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 98b38fe..caad86a 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,10 @@ "url": "https://github.com/a-ignatov-parc/tvdml/issues" }, "homepage": "https://github.com/a-ignatov-parc/tvdml#readme", + "dependencies": { + "@a-ignatov-parc/virtual-dom": "^2.2.0", + "react-reconciler": "^0.7.0" + }, "devDependencies": { "babel-core": "^6.22.1", "babel-loader": "^7.1.2", @@ -50,10 +54,11 @@ "jsdom": "^11.5.1", "mocha": "^3.1.2", "mocha-junit-reporter": "^1.15.0", + "react": "^16.2.0", "webpack": "^3.10.0" }, - "dependencies": { - "@a-ignatov-parc/virtual-dom": "^2.2.0" + "peerDependencies": { + "react": "^16.2.0" }, "files": [ "dist" diff --git a/yarn.lock b/yarn.lock index c3e88a8..a3a4728 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2367,7 +2367,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -2868,7 +2868,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.10: +prop-types@^15.5.10, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" dependencies: @@ -2944,6 +2944,24 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-reconciler@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" From c9b5864800d95129f174e56b901c909eb3be6ed7 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Fri, 22 Dec 2017 23:46:56 +0300 Subject: [PATCH 03/48] Switched to uglify-es for code minification --- package.json | 2 +- webpack.config.js | 20 ++- yarn.lock | 445 ++++++++++++++++++++++++++-------------------- 3 files changed, 268 insertions(+), 199 deletions(-) diff --git a/package.json b/package.json index caad86a..5be6fb1 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "devDependencies": { "babel-core": "^6.22.1", "babel-loader": "^7.1.2", - "babel-minify-webpack-plugin": "^0.2.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-register": "^6.26.0", @@ -55,6 +54,7 @@ "mocha": "^3.1.2", "mocha-junit-reporter": "^1.15.0", "react": "^16.2.0", + "uglifyjs-webpack-plugin": "^1.1.4", "webpack": "^3.10.0" }, "peerDependencies": { diff --git a/webpack.config.js b/webpack.config.js index 395f216..d6bb452 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,7 @@ const path = require('path'); const webpack = require('webpack'); -const MinifyPlugin = require('babel-minify-webpack-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); function resolveFromRoot(dir) { return path.resolve(__dirname, dir); @@ -41,10 +41,22 @@ const plugins = [ if (isProd) { plugins.push(...[ + new webpack.optimize.ModuleConcatenationPlugin(), new webpack.optimize.OccurrenceOrderPlugin(), - new MinifyPlugin({ - keepFnName: true, - keepClassName: true, + new UglifyJsPlugin({ + uglifyOptions: { + compress: { + keep_fnames: true, + warnings: false, + }, + output: { + comments: false, + }, + mangle: { + keep_fnames: true, + }, + }, + sourceMap: true, }), ]); } diff --git a/yarn.lock b/yarn.lock index a3a4728..9358c63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,6 +72,15 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.0.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + ajv@^5.1.0: version "5.5.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.0.tgz#eb2840746e9dc48bd5e063a36e3fd400c5eab5a9" @@ -127,7 +136,7 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" -aproba@^1.0.3: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -263,7 +272,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.22.1, babel-core@^6.24.1, babel-core@^6.26.0: +babel-core@^6.22.1, babel-core@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: @@ -300,34 +309,6 @@ babel-generator@^6.26.0: source-map "^0.5.6" trim-right "^1.0.1" -babel-helper-evaluate-path@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz#0bb2eb01996c0cef53c5e8405e999fe4a0244c08" - -babel-helper-flip-expressions@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz#160d2090a3d9f9c64a750905321a0bc218f884ec" - -babel-helper-is-nodes-equiv@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" - -babel-helper-is-void-0@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz#6ed0ada8a9b1c5b6e88af6b47c1b3b5c080860eb" - -babel-helper-mark-eval-scopes@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz#7648aaf2ec92aae9b09a20ad91e8df5e1fcc94b2" - -babel-helper-remove-or-void@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz#8e46ad5b30560d57d7510b3fd93f332ee7c67386" - -babel-helper-to-multiple-sequence-expressions@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz#d1a419634c6cb301f27858c659167cfee0a9d318" - babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" @@ -349,79 +330,6 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" -babel-minify-webpack-plugin@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.2.0.tgz#ef9694d11a1b8ab8f3204d89f5c9278dd28fc2a9" - dependencies: - babel-core "^6.24.1" - babel-preset-minify "^0.2.0" - webpack-sources "^1.0.1" - -babel-plugin-minify-builtins@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz#317f824b0907210b6348671bb040ca072e2e0c82" - dependencies: - babel-helper-evaluate-path "^0.2.0" - -babel-plugin-minify-constant-folding@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz#8c70b528b2eb7c13e94d95c8789077d4cdbc3970" - dependencies: - babel-helper-evaluate-path "^0.2.0" - -babel-plugin-minify-dead-code-elimination@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz#e8025ee10a1e5e4f202633a6928ce892c33747e3" - dependencies: - babel-helper-evaluate-path "^0.2.0" - babel-helper-mark-eval-scopes "^0.2.0" - babel-helper-remove-or-void "^0.2.0" - lodash.some "^4.6.0" - -babel-plugin-minify-flip-comparisons@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz#0c9c8e93155c8f09dedad8118b634c259f709ef5" - dependencies: - babel-helper-is-void-0 "^0.2.0" - -babel-plugin-minify-guarded-expressions@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz#8a8c950040fce3e258a12e6eb21eab94ad7235ab" - dependencies: - babel-helper-flip-expressions "^0.2.0" - -babel-plugin-minify-infinity@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz#30960c615ddbc657c045bb00a1d8eb4af257cf03" - -babel-plugin-minify-mangle-names@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz#719892297ff0106a6ec1a4b0fc062f1f8b6a8529" - dependencies: - babel-helper-mark-eval-scopes "^0.2.0" - -babel-plugin-minify-numeric-literals@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz#5746e851700167a380c05e93f289a7070459a0d1" - -babel-plugin-minify-replace@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz#3c1f06bc4e6d3e301eacb763edc1be611efc39b0" - -babel-plugin-minify-simplify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz#21ceec4857100c5476d7cef121f351156e5c9bc0" - dependencies: - babel-helper-flip-expressions "^0.2.0" - babel-helper-is-nodes-equiv "^0.0.1" - babel-helper-to-multiple-sequence-expressions "^0.2.0" - -babel-plugin-minify-type-constructors@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz#7f3b6458be0863cfd59e9985bed6d134aa7a2e17" - dependencies: - babel-helper-is-void-0 "^0.2.0" - babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -435,22 +343,6 @@ babel-plugin-transform-es2015-modules-commonjs@^6.26.0: babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-inline-consecutive-adds@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz#15dae78921057f4004f8eafd79e15ddc5f12f426" - -babel-plugin-transform-member-expression-literals@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz#e06ae305cf48d819822e93a70d79269f04d89eec" - -babel-plugin-transform-merge-sibling-variables@^6.8.6: - version "6.8.6" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz#6d21efa5ee4981f71657fae716f9594bb2622aef" - -babel-plugin-transform-minify-booleans@^6.8.3: - version "6.8.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz#5906ed776d3718250519abf1bace44b0b613ddf9" - babel-plugin-transform-object-rest-spread@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" @@ -458,34 +350,6 @@ babel-plugin-transform-object-rest-spread@^6.26.0: babel-plugin-syntax-object-rest-spread "^6.8.0" babel-runtime "^6.26.0" -babel-plugin-transform-property-literals@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz#67ed5930b34805443452c8b9690c7ebe1e206c40" - dependencies: - esutils "^2.0.2" - -babel-plugin-transform-regexp-constructors@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz#6aa5dd0acc515db4be929bbcec4ed4c946c534a3" - -babel-plugin-transform-remove-console@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz#fde9d2d3d725530b0fadd8d31078402410386810" - -babel-plugin-transform-remove-debugger@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz#809584d412bf918f071fdf41e1fdb15ea89cdcd5" - -babel-plugin-transform-remove-undefined@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz#94f052062054c707e8d094acefe79416b63452b1" - dependencies: - babel-helper-evaluate-path "^0.2.0" - -babel-plugin-transform-simplify-comparison-operators@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz#a838786baf40cc33a93b95ae09e05591227e43bf" - babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" @@ -493,38 +357,6 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-undefined-to-void@^6.8.3: - version "6.8.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz#fc52707f6ee1ddc71bb91b0d314fbefdeef9beb4" - -babel-preset-minify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz#006566552d9b83834472273f306c0131062a0acc" - dependencies: - babel-plugin-minify-builtins "^0.2.0" - babel-plugin-minify-constant-folding "^0.2.0" - babel-plugin-minify-dead-code-elimination "^0.2.0" - babel-plugin-minify-flip-comparisons "^0.2.0" - babel-plugin-minify-guarded-expressions "^0.2.0" - babel-plugin-minify-infinity "^0.2.0" - babel-plugin-minify-mangle-names "^0.2.0" - babel-plugin-minify-numeric-literals "^0.2.0" - babel-plugin-minify-replace "^0.2.0" - babel-plugin-minify-simplify "^0.2.0" - babel-plugin-minify-type-constructors "^0.2.0" - babel-plugin-transform-inline-consecutive-adds "^0.2.0" - babel-plugin-transform-member-expression-literals "^6.8.5" - babel-plugin-transform-merge-sibling-variables "^6.8.6" - babel-plugin-transform-minify-booleans "^6.8.3" - babel-plugin-transform-property-literals "^6.8.5" - babel-plugin-transform-regexp-constructors "^0.2.0" - babel-plugin-transform-remove-console "^6.8.5" - babel-plugin-transform-remove-debugger "^6.8.5" - babel-plugin-transform-remove-undefined "^0.2.0" - babel-plugin-transform-simplify-comparison-operators "^6.8.5" - babel-plugin-transform-undefined-to-void "^6.8.3" - lodash.isplainobject "^4.0.6" - babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -609,6 +441,10 @@ block-stream@*: dependencies: inherits "~2.0.0" +bluebird@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -734,6 +570,24 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" +cacache@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.1.tgz#3e05f6e616117d9b54665b1b20c8aeb93ea5d36f" + dependencies: + bluebird "^3.5.0" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^1.3.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.1" + ssri "^5.0.0" + unique-filename "^1.1.0" + y18n "^3.2.1" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -804,6 +658,10 @@ chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -871,6 +729,10 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" +commander@~2.12.1: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -879,7 +741,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -913,6 +775,17 @@ convert-source-map@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1001,6 +874,10 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": dependencies: cssom "0.3.x" +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -1129,6 +1006,15 @@ domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.0.tgz#81fe5df81b3f057052cde3a9fa9bf536a85b9ab0" +duplexify@^3.1.2, duplexify@^3.4.2: + version "3.5.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -1161,6 +1047,12 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" + dependencies: + once "^1.4.0" + enhanced-resolve@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" @@ -1176,6 +1068,12 @@ errno@^0.1.3: dependencies: prr "~0.0.0" +errno@^0.1.4: + version "0.1.6" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026" + dependencies: + prr "~1.0.1" + error-ex@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" @@ -1586,6 +1484,13 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flush-write-stream@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -1620,6 +1525,22 @@ form-data@~2.3.1: combined-stream "^1.0.5" mime-types "^2.1.12" +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1740,7 +1661,7 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -1901,6 +1822,10 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + ignore@^3.3.3: version "3.3.5" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" @@ -2339,10 +2264,6 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -2351,10 +2272,6 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash.some@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -2373,7 +2290,7 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0" -lru-cache@^4.0.1: +lru-cache@^4.0.1, lru-cache@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" dependencies: @@ -2481,6 +2398,21 @@ minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +mississippi@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-1.3.0.tgz#d201583eb12327e3c5c1642a404a9cacf94e34f5" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^1.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -2513,6 +2445,17 @@ mocha@^3.1.2: mkdirp "0.5.1" supports-color "3.1.2" +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2647,7 +2590,7 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3: +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -2715,6 +2658,14 @@ pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -2862,6 +2813,10 @@ progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -2880,6 +2835,10 @@ prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -2894,6 +2853,21 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.3.5.tgz#1b671c619940abcaeac0ad0e3a3c164be760993b" + dependencies: + duplexify "^3.1.2" + inherits "^2.0.1" + pump "^1.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -2977,7 +2951,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -3132,7 +3106,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -3151,6 +3125,12 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + rx-lite-aggregates@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" @@ -3169,10 +3149,20 @@ sax@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" +schema-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" + dependencies: + ajv "^5.0.0" + "semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -3242,6 +3232,10 @@ source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3, sour version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" +source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -3274,6 +3268,12 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" +ssri@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.0.0.tgz#13c19390b606c821f2a10d02b351c1729b94d8cf" + dependencies: + safe-buffer "^5.1.0" + stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -3285,6 +3285,13 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + stream-http@^2.3.1: version "2.7.2" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" @@ -3295,6 +3302,10 @@ stream-http@^2.3.1: to-arraybuffer "^1.0.0" xtend "^4.0.0" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + string-template@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" @@ -3412,6 +3423,13 @@ text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -3484,6 +3502,13 @@ ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" +uglify-es@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.2.2.tgz#15c62b7775002c81b7987a1c49ecd3f126cace73" + dependencies: + commander "~2.12.1" + source-map "~0.6.1" + uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -3505,10 +3530,35 @@ uglifyjs-webpack-plugin@^0.4.6: uglify-js "^2.8.29" webpack-sources "^1.0.1" +uglifyjs-webpack-plugin@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.4.tgz#e43ad6e736c315024eb99481a7cc9362d6a066be" + dependencies: + cacache "^10.0.0" + find-cache-dir "^1.0.0" + schema-utils "^0.3.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.2.1" + webpack-sources "^1.0.1" + worker-farm "^1.4.1" + uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -3643,6 +3693,13 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +worker-farm@^1.4.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" + dependencies: + errno "^0.1.4" + xtend "^4.0.1" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -3676,7 +3733,7 @@ xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" -xtend@^4.0.0, xtend@~4.0.0: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 4bdac8cc24377c12843a41030b522930126fff30 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sat, 23 Dec 2017 01:49:23 +0300 Subject: [PATCH 04/48] Implemented simple tvml renderer --- src/index.js | 1 + src/renderReact.js | 230 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 src/renderReact.js diff --git a/src/index.js b/src/index.js index acf3d39..1197d62 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import { subscribe, broadcast } from './event-bus'; export { subscribe }; export * from './render'; +export * from './renderReact'; export * from './pipelines'; export * from './navigation'; export { default as jsx } from './jsx'; diff --git a/src/renderReact.js b/src/renderReact.js new file mode 100644 index 0000000..688889e --- /dev/null +++ b/src/renderReact.js @@ -0,0 +1,230 @@ +/* global navigationDocument */ + +import React from 'react'; +import ReactFiberReconciler from 'react-reconciler'; + +import { createPipeline } from './pipelines'; +import { createEmptyDocument } from './render/document'; + +const ELEMENT_NODE = 1; +const TEXT_NODE = 3; +const PROCESSING_INSTRUCTION_NODE = 7; +const COMMENT_NODE = 8; +const DOCUMENT_NODE = 9; +const DOCUMENT_TYPE_NODE = 10; +const DOCUMENT_FRAGMENT_NODE = 11; + +const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; + +const emptyObject = {}; + +function getOwnerDocumentFromRootContainer(rootContainerElement) { + return rootContainerElement.nodeType === DOCUMENT_NODE + ? rootContainerElement + : rootContainerElement.ownerDocument; +} + +function createElement(type, props, rootContainerElement, parentNamespace) { + console.log( + 'createElement', + type, + props, + rootContainerElement, + parentNamespace, + ); + + const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); + const domElement = ownerDocument.createElement(type); + return domElement; +} + +function createTextNode(text, rootContainerElement) { + const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); + const textNode = ownerDocument.createTextNode(text); + return textNode; +} + +function setInitialProperties(domElement, tag, rawProps, rootContainerElement) { + console.log('setInitialProperties', domElement, tag, rawProps); +} + +const TVMLRenderer = ReactFiberReconciler({ + getRootHostContext(rootContainerInstance) { + const nodeType = rootContainerInstance.nodeType; + + let namespace; + + switch (nodeType) { + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: { + let root = rootContainerInstance.documentElement; + namespace = root ? root.namespaceURI : HTML_NAMESPACE; + break; + } + default: { + namespace = HTML_NAMESPACE; + break; + } + } + return namespace; + }, + + getChildHostContext(parentHostContext, type) { + return HTML_NAMESPACE; + }, + + getPublicInstance(instance) { + return instance; + }, + + prepareForCommit() { + // noop + }, + + resetAfterCommit() { + // noop + }, + + createInstance(type, props, rootContainerInstance, hostContext) { + const domElement = createElement( + type, + props, + rootContainerInstance, + hostContext, + ); + + return domElement; + }, + + appendInitialChild(parentInstance, child) { + console.log('appendInitialChild', parentInstance, child); + parentInstance.appendChild(child); + }, + + finalizeInitialChildren(domElement, type, props, rootContainerInstance) { + setInitialProperties(domElement, type, props, rootContainerInstance); + return false; + }, + + prepareUpdate( + domElement, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext, + ) { + console.log( + 'prepareUpdate', + domElement, + type, + oldProps, + newProps, + rootContainerInstance, + ); + + return null; + }, + + shouldSetTextContent(type, props) { + return false; + }, + + shouldDeprioritizeSubtree(type, props) { + return false; + }, + + createTextInstance(text, rootContainerInstance, hostContext) { + const textNode = createTextNode(text, rootContainerInstance); + return textNode; + }, + + now: () => Date.now(), + + useSyncScheduling: true, + + mutation: { + commitMount(domElement, type, newProps) { + console.log( + 'commitMount', + domElement, + type, + newProps, + ); + }, + + commitUpdate(domElement, updatePayload, type, oldProps, newProps) { + console.log( + 'commitUpdate', + domElement, + updatePayload, + type, + oldProps, + newProps, + ); + }, + + resetTextContent(domElement) { + domElement.textContent = ''; + }, + + commitTextUpdate(textInstance, oldText, newText) { + textInstance.nodeValue = newText; + }, + + appendChild(parentInstance, child) { + parentInstance.appendChild(child); + }, + + appendChildToContainer(container, child) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.insertBefore(child, container); + } else { + container.appendChild(child); + } + }, + + insertBefore(parentInstance, child, beforeChild) { + parentInstance.insertBefore(child, beforeChild); + }, + + insertInContainerBefore(container, child, beforeChild) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.insertBefore(child, beforeChild); + } else { + container.insertBefore(child, beforeChild); + } + }, + + removeChild(parentInstance, child) { + parentInstance.removeChild(child); + }, + + removeChildFromContainer(container, child) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.removeChild(child); + } else { + container.removeChild(child); + } + }, + }, +}); + +export function renderModalReact(Component) { + console.log('renderModalReact', Component); +} + +export function renderReact(Component) { + return createPipeline() + .pipe(payload => { + const document = createEmptyDocument(); + const root = TVMLRenderer.createContainer(document, false, false); + const children = React.createElement(Component, payload); + + console.log('renderReact', payload, document, root, children); + + TVMLRenderer.updateContainer(children, root, null, () => { + navigationDocument.pushDocument(document); + }); + }); +} From f3d889824a2470f188766f5b4679c1f93c711fd7 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sat, 23 Dec 2017 04:10:37 +0300 Subject: [PATCH 05/48] Implemented main update mechanism --- src/renderReact.js | 180 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 157 insertions(+), 23 deletions(-) diff --git a/src/renderReact.js b/src/renderReact.js index 688889e..393a4b4 100644 --- a/src/renderReact.js +++ b/src/renderReact.js @@ -3,6 +3,7 @@ import React from 'react'; import ReactFiberReconciler from 'react-reconciler'; +import { broadcast } from './event-bus'; import { createPipeline } from './pipelines'; import { createEmptyDocument } from './render/document'; @@ -16,8 +17,20 @@ const DOCUMENT_FRAGMENT_NODE = 11; const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; +const CHILDREN = 'children'; + const emptyObject = {}; +const isEventNameRegex = /^on[A-Z]/; + +const supportedEventMapping = { + onPlay: 'play', + onSelect: 'select', + onChange: 'change', + onHighlight: 'highlight', + onHoldselect: 'holdselect', +}; + function getOwnerDocumentFromRootContainer(rootContainerElement) { return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement @@ -25,14 +38,6 @@ function getOwnerDocumentFromRootContainer(rootContainerElement) { } function createElement(type, props, rootContainerElement, parentNamespace) { - console.log( - 'createElement', - type, - props, - rootContainerElement, - parentNamespace, - ); - const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); const domElement = ownerDocument.createElement(type); return domElement; @@ -44,8 +49,148 @@ function createTextNode(text, rootContainerElement) { return textNode; } -function setInitialProperties(domElement, tag, rawProps, rootContainerElement) { - console.log('setInitialProperties', domElement, tag, rawProps); +function setInitialProperties(domElement, type, props, rootContainerElement) { + console.log('setInitialProperties', domElement, type, props); + + Object + .keys(props) + .forEach(propName => { + const propValue = props[propName]; + + if (propName === CHILDREN) { + if (type === 'style') { + domElement.innerHTML = propValue; + } else if (typeof propValue === 'string') { + if (propValue !== '') domElement.textContent = propValue; + } else if (typeof propValue === 'number') { + domElement.textContent = `${propValue}`; + } + } else if (isEventNameRegex.test(propName)) { + const eventName = supportedEventMapping[propName]; + + if (eventName && typeof propValue === 'function') { + domElement.addEventListener(eventName, propValue); + } + } else if (propValue != null) { + domElement.setAttribute(propName, propValue); + } + }); + + if (type === 'menuItem') { + domElement.addEventListener('select', ({ target: menuItem }) => { + const menuBar = menuItem.parentNode; + const feature = menuBar.getFeature('MenuBarDocument'); + + broadcast('menu-item-select', { + menuItem, + menuBar: feature, + }); + }); + } +} + +function diffProperties( + domElement, + type, + oldProps, + newProps, + rootContainerInstance, +) { + let updatePayload = null; + + Object + .keys(oldProps) + .forEach(propName => { + const propValue = oldProps[propName]; + const shouldSkip = newProps.hasOwnProperty(propName) + || !oldProps.hasOwnProperty(propName) + || oldProps[propName] == null; + + if (shouldSkip) return; + (updatePayload = updatePayload || []).push(propName, null); + }); + + Object + .keys(newProps) + .forEach(propName => { + const propValue = newProps[propName]; + const oldPropValue = oldProps != null ? oldProps[propName] : undefined; + + const shouldSkip = !newProps.hasOwnProperty(propName) + || propValue === oldPropValue + || (propValue == null && oldPropValue == null); + + if (shouldSkip) return; + if (propName === CHILDREN) { + const shouldUpdate = oldPropValue !== propValue + && ( + typeof propValue === 'string' + || typeof propValue === 'number' + ); + + if (shouldUpdate) { + (updatePayload = updatePayload || []).push(propName, '' + propValue); + } + } else { + (updatePayload = updatePayload || []).push(propName, propValue); + } + }); + + if (updatePayload) { + console.log( + 'diffProperties', + domElement, + type, + oldProps, + newProps, + updatePayload, + ); + } + + return updatePayload; +} + +function updateProperties(domElement, updatePayload, type, oldProps, newProps) { + for (let i = 0; i < updatePayload.length; i += 2) { + const propName = updatePayload[i]; + const propValue = updatePayload[i + 1]; + + console.log( + 'updateProperties', + domElement, + type, + propName, + propValue, + oldProps, + newProps, + ); + + if (propName === CHILDREN) { + if (type === 'style') { + domElement.innerHTML = propValue; + } else { + domElement.textContent = propValue; + } + } else if (isEventNameRegex.test(propName)) { + const eventName = supportedEventMapping[propName]; + + if (eventName) { + if (oldProps[propName] !== newProps[propName]) { + domElement.removeEventListener(eventName, oldProps[propName]); + } + + if (typeof propValue === 'function') { + domElement.addEventListener(eventName, propValue); + } + } + } else { + if (propValue === null || typeof propValue === 'undefined') { + domElement.removeAttribute(propName); + } else { + domElement.setAttribute(propName, propValue); + } + } + } } const TVMLRenderer = ReactFiberReconciler({ @@ -97,7 +242,6 @@ const TVMLRenderer = ReactFiberReconciler({ }, appendInitialChild(parentInstance, child) { - console.log('appendInitialChild', parentInstance, child); parentInstance.appendChild(child); }, @@ -114,16 +258,13 @@ const TVMLRenderer = ReactFiberReconciler({ rootContainerInstance, hostContext, ) { - console.log( - 'prepareUpdate', + return diffProperties( domElement, type, oldProps, newProps, rootContainerInstance, ); - - return null; }, shouldSetTextContent(type, props) { @@ -154,14 +295,7 @@ const TVMLRenderer = ReactFiberReconciler({ }, commitUpdate(domElement, updatePayload, type, oldProps, newProps) { - console.log( - 'commitUpdate', - domElement, - updatePayload, - type, - oldProps, - newProps, - ); + updateProperties(domElement, updatePayload, type, oldProps, newProps); }, resetTextContent(domElement) { From 4dea3d8e8552fd762783391d03282fb9fd9d3a6c Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sat, 23 Dec 2017 05:00:31 +0300 Subject: [PATCH 06/48] Implmented proper react document rendering --- src/renderReact.js | 63 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/renderReact.js b/src/renderReact.js index 393a4b4..935d533 100644 --- a/src/renderReact.js +++ b/src/renderReact.js @@ -4,8 +4,9 @@ import React from 'react'; import ReactFiberReconciler from 'react-reconciler'; import { broadcast } from './event-bus'; -import { createPipeline } from './pipelines'; +import { promisedTimeout } from './utils'; import { createEmptyDocument } from './render/document'; +import { passthrough, createPipeline } from './pipelines'; const ELEMENT_NODE = 1; const TEXT_NODE = 3; @@ -19,7 +20,7 @@ const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; const CHILDREN = 'children'; -const emptyObject = {}; +const RENDERING_ANIMATION = 600; const isEventNameRegex = /^on[A-Z]/; @@ -350,15 +351,59 @@ export function renderModalReact(Component) { export function renderReact(Component) { return createPipeline() - .pipe(payload => { - const document = createEmptyDocument(); - const root = TVMLRenderer.createContainer(document, false, false); + .pipe(passthrough((payload) => { + const { + route, + redirect, + navigation = {}, + } = payload; + + const { menuBar, menuItem } = navigation; + + let { reactRenderRoot } = payload; + + if (!reactRenderRoot) { + const target = createEmptyDocument(); + target.route = route; + + reactRenderRoot = TVMLRenderer.createContainer( + target, // container + false, // isAsync + false, // hydrate + ); + } + + const document = reactRenderRoot.containerInfo; + const { possiblyDismissedByUser } = document; + + /** + * If we received dismissed document it means that user pressed menu + * button and our pipeline is canceled. Now we must silently succeed + * the rest of the pipeline without rendering anything. + */ + if (possiblyDismissedByUser) return null; + const children = React.createElement(Component, payload); - console.log('renderReact', payload, document, root, children); + TVMLRenderer.updateContainer(children, reactRenderRoot, null); + + if (redirect) { + const index = navigationDocument.documents.indexOf(document); + const prevDocument = navigationDocument.documents[index - 1]; - TVMLRenderer.updateContainer(children, root, null, () => { + if (prevDocument) { + navigationDocument.replaceDocument(document, prevDocument); + } + } else if (!document.isAttached) { navigationDocument.pushDocument(document); - }); - }); + } + + document.isAttached = true; + + return { + reactRenderRoot, + redirect: false, + }; + })) + .pipe(passthrough(() => promisedTimeout(RENDERING_ANIMATION))); } From 420f5bf0c403c4e99a9dba0dbff29f8d020db1c8 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sat, 23 Dec 2017 05:19:52 +0300 Subject: [PATCH 07/48] Bugfix + code refactoring --- src/navigation/hooks.js | 2 +- src/renderReact.js | 55 ++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index f13add8..146b5a4 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -12,7 +12,7 @@ function destroyComponents(document) { */ // eslint-disable-next-line no-param-reassign document.possiblyDismissedByUser = true; - if (document.destroyComponent) document.destroyComponent(); + if (document.unmount) document.unmount(); } function handleUnload({ target: { ownerDocument: document } }) { diff --git a/src/renderReact.js b/src/renderReact.js index 935d533..f61f8f3 100644 --- a/src/renderReact.js +++ b/src/renderReact.js @@ -360,48 +360,57 @@ export function renderReact(Component) { const { menuBar, menuItem } = navigation; - let { reactRenderRoot } = payload; + let { document } = payload; - if (!reactRenderRoot) { - const target = createEmptyDocument(); - target.route = route; + if (!document) { + document = createEmptyDocument(); - reactRenderRoot = TVMLRenderer.createContainer( - target, // container + const root = TVMLRenderer.createContainer( + document, // container false, // isAsync false, // hydrate ); - } - const document = reactRenderRoot.containerInfo; - const { possiblyDismissedByUser } = document; + Object.assign(document, { + route, + reactRoot: root, + + render(children, callback) { + TVMLRenderer.updateContainer(children, root, null, callback); + }, + + unmount(callback) { + TVMLRenderer.updateContainer(null, root, null, callback); + }, + }); + } /** * If we received dismissed document it means that user pressed menu * button and our pipeline is canceled. Now we must silently succeed * the rest of the pipeline without rendering anything. */ - if (possiblyDismissedByUser) return null; + if (document.possiblyDismissedByUser) return null; - const children = React.createElement(Component, payload); + document.render(React.createElement(Component, payload)); - TVMLRenderer.updateContainer(children, reactRenderRoot, null); + if (!document.isAttached) { + if (redirect) { + const index = navigationDocument.documents.indexOf(document); + const prevDocument = navigationDocument.documents[index - 1]; - if (redirect) { - const index = navigationDocument.documents.indexOf(document); - const prevDocument = navigationDocument.documents[index - 1]; - - if (prevDocument) { - navigationDocument.replaceDocument(document, prevDocument); + if (prevDocument) { + navigationDocument.replaceDocument(document, prevDocument); + } + } else { + navigationDocument.pushDocument(document); } - } else if (!document.isAttached) { - navigationDocument.pushDocument(document); - } - document.isAttached = true; + document.isAttached = true; + } return { - reactRenderRoot, + document, redirect: false, }; })) From 5c564b6de57f152a371c41ad4a7c0ee7415651f8 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 00:42:31 +0300 Subject: [PATCH 08/48] Code refactoring and removed old virtual-dom modules --- src/index.js | 4 +- src/jsx.js | 82 ----- src/{renderReact.js => react-tvml/index.js} | 161 +++++----- src/react-tvml/node-types.js | 7 + src/render.js | 163 +++------- src/render/component.js | 180 ----------- src/render/custom-node.js | 11 - src/render/document.js | 170 ---------- test/component.js | 331 -------------------- 9 files changed, 138 insertions(+), 971 deletions(-) delete mode 100644 src/jsx.js rename src/{renderReact.js => react-tvml/index.js} (75%) create mode 100644 src/react-tvml/node-types.js delete mode 100644 src/render/component.js delete mode 100644 src/render/custom-node.js delete mode 100644 src/render/document.js delete mode 100644 test/component.js diff --git a/src/index.js b/src/index.js index 1197d62..5cbec7f 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,9 @@ import { subscribe, broadcast } from './event-bus'; export { subscribe }; export * from './render'; -export * from './renderReact'; export * from './pipelines'; export * from './navigation'; -export { default as jsx } from './jsx'; -export { default as createComponent } from './render/component'; +export { default as ReactTVML } from './react-tvml'; subscribe('uncontrolled-document-pop').pipe(({ document }) => { const { diff --git a/src/jsx.js b/src/jsx.js deleted file mode 100644 index e836b05..0000000 --- a/src/jsx.js +++ /dev/null @@ -1,82 +0,0 @@ -/* global DataItem */ - -import h from '@a-ignatov-parc/virtual-dom/h'; - -import CustomNode from './render/custom-node'; - -class Ref { - constructor(handler) { - this.handler = handler; - } - - hook(node) { - if (typeof this.handler === 'function') { - this.handler(node); - } - } -} - -export default function createElement(tag, attrs, ...children) { - const node = { tag }; - - if (attrs) { - Object - .keys(attrs) - .forEach((name) => { - if (name === 'key') { - node.key = attrs[name]; - } else if (name === 'ref') { - node.ref = new Ref(attrs[name]); - } else if (name === 'content' && tag === 'style') { - node.content = attrs[name]; - } else if (name === 'dataItem') { - const value = attrs[name]; - - if (value instanceof DataItem) { - node.dataItem = value; - } else { - node.dataItem = new DataItem(); - Object - .keys(value) - .forEach((propName) => { - node.dataItem.setPropertyPath(propName, value[propName]); - }); - } - } else if (typeof attrs[name] === 'function') { - if (!node.events) node.events = {}; - node.events[name] = attrs[name]; - } else { - if (!node.attrs) node.attrs = {}; - node.attrs[name] = attrs[name]; - } - }); - } - - if (children.length === 1) { - const [first] = children; - node.children = first; - } else if (children.length > 1) { - node.children = children; - } - - if (node.tag instanceof CustomNode) { - return node.tag.toNode(node.attrs); - } else if (typeof node.tag === 'function') { - return node.tag(node); - } - - const props = { - tvml: true, - key: node.key, - ref: node.ref, - events: node.events, - attributes: node.attrs, - dataItem: node.dataItem, - }; - - if (node.content) { - props.innerHTML = node.content; - } - - return h(node.tag, props, node.children); -} diff --git a/src/renderReact.js b/src/react-tvml/index.js similarity index 75% rename from src/renderReact.js rename to src/react-tvml/index.js index f61f8f3..dbf8091 100644 --- a/src/renderReact.js +++ b/src/react-tvml/index.js @@ -1,28 +1,18 @@ -/* global navigationDocument */ - import React from 'react'; import ReactFiberReconciler from 'react-reconciler'; -import { broadcast } from './event-bus'; -import { promisedTimeout } from './utils'; -import { createEmptyDocument } from './render/document'; -import { passthrough, createPipeline } from './pipelines'; - -const ELEMENT_NODE = 1; -const TEXT_NODE = 3; -const PROCESSING_INSTRUCTION_NODE = 7; -const COMMENT_NODE = 8; -const DOCUMENT_NODE = 9; -const DOCUMENT_TYPE_NODE = 10; -const DOCUMENT_FRAGMENT_NODE = 11; +import { broadcast } from '../event-bus'; -const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; +import { + COMMENT_NODE, + DOCUMENT_NODE, + DOCUMENT_FRAGMENT_NODE, +} from './node-types'; +const NAMESPACE = 'http://www.w3.org/1999/xhtml'; const CHILDREN = 'children'; -const RENDERING_ANIMATION = 600; - -const isEventNameRegex = /^on[A-Z]/; +const eventNameRegex = /^on[A-Z]/; const supportedEventMapping = { onPlay: 'play', @@ -66,7 +56,7 @@ function setInitialProperties(domElement, type, props, rootContainerElement) { } else if (typeof propValue === 'number') { domElement.textContent = `${propValue}`; } - } else if (isEventNameRegex.test(propName)) { + } else if (eventNameRegex.test(propName)) { const eventName = supportedEventMapping[propName]; if (eventName && typeof propValue === 'function') { @@ -172,7 +162,7 @@ function updateProperties(domElement, updatePayload, type, oldProps, newProps) { } else { domElement.textContent = propValue; } - } else if (isEventNameRegex.test(propName)) { + } else if (eventNameRegex.test(propName)) { const eventName = supportedEventMapping[propName]; if (eventName) { @@ -204,11 +194,11 @@ const TVMLRenderer = ReactFiberReconciler({ case DOCUMENT_NODE: case DOCUMENT_FRAGMENT_NODE: { let root = rootContainerInstance.documentElement; - namespace = root ? root.namespaceURI : HTML_NAMESPACE; + namespace = root ? root.namespaceURI : NAMESPACE; break; } default: { - namespace = HTML_NAMESPACE; + namespace = NAMESPACE; break; } } @@ -216,7 +206,7 @@ const TVMLRenderer = ReactFiberReconciler({ }, getChildHostContext(parentHostContext, type) { - return HTML_NAMESPACE; + return NAMESPACE; }, getPublicInstance(instance) { @@ -345,74 +335,83 @@ const TVMLRenderer = ReactFiberReconciler({ }, }); -export function renderModalReact(Component) { - console.log('renderModalReact', Component); -} - -export function renderReact(Component) { - return createPipeline() - .pipe(passthrough((payload) => { - const { - route, - redirect, - navigation = {}, - } = payload; - - const { menuBar, menuItem } = navigation; - - let { document } = payload; +class ReactRoot { + constructor(container) { + const root = TVMLRenderer.createContainer( + container, + false, // isAsync + false, // hydrate + ); - if (!document) { - document = createEmptyDocument(); + this._internalRoot = root; + } - const root = TVMLRenderer.createContainer( - document, // container - false, // isAsync - false, // hydrate - ); + render(children, callback) { + const root = this._internalRoot; + TVMLRenderer.updateContainer(children, root, null, callback); + } - Object.assign(document, { - route, - reactRoot: root, + unmount(callback) { + const root = this._internalRoot; + TVMLRenderer.updateContainer(null, root, null, callback); + } +}; - render(children, callback) { - TVMLRenderer.updateContainer(children, root, null, callback); - }, +function createRoot(container) { + while ((rootSibling = container.lastChild)) { + container.removeChild(rootSibling); + } - unmount(callback) { - TVMLRenderer.updateContainer(null, root, null, callback); - }, - }); - } + return new ReactRoot(container); +} - /** - * If we received dismissed document it means that user pressed menu - * button and our pipeline is canceled. Now we must silently succeed - * the rest of the pipeline without rendering anything. - */ - if (document.possiblyDismissedByUser) return null; +const ReactTVML = { + render(element, container, callback) { + let root = container._reactRootContainer; - document.render(React.createElement(Component, payload)); + if (!root) { + // Initial mount + root = container._reactRootContainer = createRoot(container); - if (!document.isAttached) { - if (redirect) { - const index = navigationDocument.documents.indexOf(document); - const prevDocument = navigationDocument.documents[index - 1]; + TVMLRenderer.unbatchedUpdates(() => { + root.render(children, () => { + if (typeof callback === 'function') { + const instance = TVMLRenderer.getPublicRootInstance( + root._internalRoot, + ); - if (prevDocument) { - navigationDocument.replaceDocument(document, prevDocument); + callback.call(instance); } - } else { - navigationDocument.pushDocument(document); + }); + }); + } else { + // Update + root.render(children, () => { + if (typeof callback === 'function') { + const instance = TVMLRenderer.getPublicRootInstance( + root._internalRoot, + ); + + callback.call(instance); } + }); + } - document.isAttached = true; - } + return TVMLRenderer.getPublicRootInstance(root._internalRoot); + }, - return { - document, - redirect: false, - }; - })) - .pipe(passthrough(() => promisedTimeout(RENDERING_ANIMATION))); -} + unmountComponentAtNode(container) { + if (container._reactRootContainer) { + TVMLRenderer.unbatchedUpdates(() => { + this.render(null, container, () => { + container._reactRootContainer = null; + }); + }); + return true; + } else { + return false; + } + }, +}; + +export default ReactTVML; diff --git a/src/react-tvml/node-types.js b/src/react-tvml/node-types.js new file mode 100644 index 0000000..8320cc4 --- /dev/null +++ b/src/react-tvml/node-types.js @@ -0,0 +1,7 @@ +export const ELEMENT_NODE = 1; +export const TEXT_NODE = 3; +export const PROCESSING_INSTRUCTION_NODE = 7; +export const COMMENT_NODE = 8; +export const DOCUMENT_NODE = 9; +export const DOCUMENT_TYPE_NODE = 10; +export const DOCUMENT_FRAGMENT_NODE = 11; diff --git a/src/render.js b/src/render.js index 7c2c168..0c51359 100644 --- a/src/render.js +++ b/src/render.js @@ -1,145 +1,82 @@ -/* global navigationDocument */ +/* global navigationDocument, DOMImplementationRegistry */ + +import ReactTVML from './react-tvml'; import { promisedTimeout } from './utils'; import { passthrough, createPipeline } from './pipelines'; -import { vdomToDocument, createEmptyDocument } from './render/document'; - -let hasModal = false; const RENDERING_ANIMATION = 600; -function createDocument(template, payload) { - if (typeof template === 'string') { - throw new Error('String templates aren\'t supported. Use jsx templates.'); - } - - if (typeof template === 'function') { - // eslint-disable-next-line no-param-reassign - template = template(payload); - } - - if (typeof template === 'object' && template) { - return vdomToDocument(template, payload); - } - - return createEmptyDocument(); -} - -export function parseDocument(template) { - return createPipeline().pipe(passthrough((payload) => { - const { possiblyDismissedByUser } = (payload || {}).renderedDocument || {}; - - let parsedDocument = null; - - // We don't want to process documents in canceled pipeline. - if (!possiblyDismissedByUser) { - parsedDocument = createDocument(template, payload); - } - - return { parsedDocument }; - })); -} - -export function removeModal() { - hasModal = false; - navigationDocument.dismissModal(true); +export function renderModalReact(Component) { + console.log('renderModalReact', Component); } -export function renderModal(template) { +export function render(Component) { return createPipeline() - .pipe(passthrough(() => { - if (!hasModal) return null; - removeModal(); - return promisedTimeout(RENDERING_ANIMATION); - })) - .pipe(parseDocument(template)) - .pipe(passthrough(({ parsedDocument: document, route }) => { - const lastDocument = navigationDocument.documents.pop(); - - hasModal = true; - - // eslint-disable-next-line no-param-reassign - document.modal = true; - - // eslint-disable-next-line no-param-reassign - document.route = route || (lastDocument || {}).route; - - navigationDocument.presentModal(document); - })); -} - -export function render(template) { - return createPipeline() - .pipe(parseDocument(template)) .pipe(passthrough((payload) => { const { route, redirect, navigation = {}, - parsedDocument: document, } = payload; - let { document: renderedDocument } = payload; - const { menuBar, menuItem } = navigation; - const { possiblyDismissedByUser } = renderedDocument || {}; + + let { document } = payload; + + if (!document) { + document = DOMImplementationRegistry + .getDOMImplementation() + .createDocument(); + + const root = TVMLRenderer.createContainer( + document, // container + false, // isAsync + false, // hydrate + ); + + Object.assign(document, { + route, + reactRoot: root, + + render(children, callback) { + TVMLRenderer.updateContainer(children, root, null, callback); + }, + + unmount(callback) { + TVMLRenderer.updateContainer(null, root, null, callback); + }, + }); + } /** * If we received dismissed document it means that user pressed menu * button and our pipeline is canceled. Now we must silently succeed * the rest of the pipeline without rendering anything. */ - if (possiblyDismissedByUser) { - // eslint-disable-next-line max-len - console.warn('Rendering pipeline was canceled by user. Skipping further renders...'); - return null; - } - - const prevRouteDocument = renderedDocument - ? renderedDocument.prevRouteDocument - : navigationDocument.documents.slice(-1)[0]; - - document.route = route; - document.prevRouteDocument = prevRouteDocument; + if (document.possiblyDismissedByUser) return null; - if (prevRouteDocument === renderedDocument) { - document.prevRouteDocument = null; - } - - if (hasModal) removeModal(); + document.render(React.createElement(Component, payload)); - if (redirect && prevRouteDocument) { - renderedDocument = prevRouteDocument; - } + if (!document.isAttached) { + if (redirect) { + const index = navigationDocument.documents.indexOf(document); + const prevDocument = navigationDocument.documents[index - 1]; - if (menuBar && menuItem) { - const menuItemDocument = menuBar.getDocument(menuItem); - - if (menuItemDocument !== document) { - /** - * Documents rendered by `menuBar` should be mounted here manualy - * because they are not invoking any system hooks on `setDocument`. - * - * P.S. Documents in other cases are mounted implicitly - * in `navigation/hooks.js`. - */ - if (document.didMount) document.didMount(); - - /** - * Setting new document to `menuBar` only after timeout for smooth - * switching with fade animation. - */ - setTimeout(() => { - menuBar.setDocument(document, menuItem); - }, RENDERING_ANIMATION); + if (prevDocument) { + navigationDocument.replaceDocument(document, prevDocument); + } + } else { + navigationDocument.pushDocument(document); } - } else if (renderedDocument) { - navigationDocument.replaceDocument(document, renderedDocument); - } else { - navigationDocument.pushDocument(document); + + document.isAttached = true; } - return { document, redirect: false }; + return { + document, + redirect: false, + }; })) .pipe(passthrough(() => promisedTimeout(RENDERING_ANIMATION))); } diff --git a/src/render/component.js b/src/render/component.js deleted file mode 100644 index a8ab9da..0000000 --- a/src/render/component.js +++ /dev/null @@ -1,180 +0,0 @@ -/* eslint-disable no-underscore-dangle */ - -import diff from '@a-ignatov-parc/virtual-dom/diff'; -import patch from '@a-ignatov-parc/virtual-dom/patch'; -import createElement from '@a-ignatov-parc/virtual-dom/create-element'; - -import Text from '@a-ignatov-parc/virtual-dom/vnode/vtext'; - -import CustomNode from './custom-node'; - -const excludeList = [ - 'init', - 'update', - 'destroy', - 'setState', - 'updateProps', -]; - -function render() { - const hasOuterQueue = !!this._queue; - - let result; - - if (!hasOuterQueue) this._queue = {}; - - try { - result = this.render(); - } catch (error) { - console.error(error); - } - - if (this._queue.state) { - console.error('You can\'t use setState during rendering phase'); - } - - if (!hasOuterQueue) this._queue = null; - - if (typeof result === 'boolean' || result === null) { - return new Text(''); - } - - if (typeof result === 'string' || typeof result === 'number') { - return new Text(result); - } - - return result; -} - -function update(nextProps, nextState) { - const prevProps = this.props; - const prevState = this.state; - - // eslint-disable-next-line no-param-reassign - if (!nextProps) nextProps = prevProps; - - // eslint-disable-next-line no-param-reassign - if (!nextState) nextState = prevState; - - const shouldUpdate = this.shouldComponentUpdate(nextProps, nextState); - - this.props = nextProps; - this.state = nextState; - - if (shouldUpdate) { - this._queue = {}; - - const prev = this._vdom; - - this.componentWillUpdate(nextProps, nextState); - - const next = render.call(this); - const updateTree = diff(prev, next); - - this._vdom = next; - this._rootNode = patch(this._rootNode, updateTree); - this._queue = null; - - this.componentDidUpdate(prevProps, prevState); - } -} - -export class Component { - constructor(props, spec) { - Object - .keys(spec) - .filter((name) => { - // eslint-disable-next-line no-bitwise - const isExcluded = !!~excludeList.indexOf(name); - - if (isExcluded) { - throw new Error(`Can't override base method "${name}"`); - } - return !isExcluded; - }) - .forEach((name) => { - this[name] = spec[name].bind(this); - }); - - this._props = { ...props }; - this.type = 'Widget'; - } - - init(options) { - this._queue = null; - - this.props = { ...this.getDefaultProps.call(null), ...this._props }; - this.state = { ...this.getInitialState() }; - - this.componentWillMount(); - this._vdom = render.call(this); - this._rootNode = createElement(this._vdom, options); - - return this._rootNode; - } - - update(previous, domNode) { - const props = this._props; - - this._queue = {}; - this._rootNode = domNode; - this._vdom = previous._vdom; - this.componentWillReceiveProps(props); - - const { state } = this._queue; - this._queue = null; - - update.call(this, props, { ...previous.state, ...state }); - } - - updateProps(nextProps) { - this._props = nextProps; - this.update(this, this._rootNode); - } - - destroy() { - this.componentWillUnmount(); - this._rootNode = null; - this._queue = null; - this._vdom = null; - } - - setState(newState = {}) { - const nextState = { ...this.state, ...newState }; - - if (this._queue) { - this._queue.state = nextState; - return; - } - - update.call(this, null, nextState); - } - - getDefaultProps() {} - - getInitialState() {} - - componentWillMount() {} - - componentDidMount() {} - - componentWillReceiveProps() {} - - shouldComponentUpdate() { - return true; - } - - render() { - return null; - } - - componentWillUpdate() {} - - componentDidUpdate() {} - - componentWillUnmount() {} -} - -export default function createComponent(spec) { - return new CustomNode(Component, spec); -} diff --git a/src/render/custom-node.js b/src/render/custom-node.js deleted file mode 100644 index 4703ab6..0000000 --- a/src/render/custom-node.js +++ /dev/null @@ -1,11 +0,0 @@ -export default class CustomNode { - constructor(Constructor, lifecycle) { - this.Constructor = Constructor; - this.lifecycle = lifecycle; - } - - toNode(payload) { - const { Constructor, lifecycle } = this; - return new Constructor(payload, lifecycle); - } -} diff --git a/src/render/document.js b/src/render/document.js deleted file mode 100644 index 3c1fdeb..0000000 --- a/src/render/document.js +++ /dev/null @@ -1,170 +0,0 @@ -/* global DOMImplementationRegistry */ - -import createElement from '@a-ignatov-parc/virtual-dom/create-element'; - -import CustomNode from './custom-node'; -import { Component } from './component'; -import { broadcast } from '../event-bus'; -import { noop } from '../utils'; - -const DEFAULT_HANDLER = 'default'; - -/** - * Because TVJS doesn't expose node types we need to hardcode them. - * - * Node types taken from MDN: - * https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType - */ -const ELEMENT_NODE = 1; -// const TEXT_NODE = 3; -// const PROCESSING_INSTRUCTION_NODE = 7; -// const COMMENT_NODE = 8; -// const DOCUMENT_NODE = 9; -// const DOCUMENT_TYPE_NODE = 10; -// const DOCUMENT_FRAGMENT_NODE = 11; - -function createDefaultHandler(handlerName) { - return function defaultHandler(...args) { - const [event] = args; - const { events = {} } = event.target; - const handler = events[handlerName]; - - if (typeof handler === 'function') { - handler.apply(this, args); - } - }; -} - -const handlers = { - play: { - [DEFAULT_HANDLER]: createDefaultHandler('onPlay'), - }, - - select: { - [DEFAULT_HANDLER]: createDefaultHandler('onSelect'), - - menuItem({ target: menuItem }) { - const menuBar = menuItem.parentNode; - const feature = menuBar.getFeature('MenuBarDocument'); - - broadcast('menu-item-select', { - menuItem, - menuBar: feature, - }); - }, - }, - - change: { - [DEFAULT_HANDLER]: createDefaultHandler('onChange'), - }, - - highlight: { - [DEFAULT_HANDLER]: createDefaultHandler('onHighlight'), - }, - - holdselect: { - [DEFAULT_HANDLER]: createDefaultHandler('onHoldselect'), - }, -}; - -const eventsList = [ - 'play', - 'select', - 'change', - 'highlight', - 'holdselect', -]; - -export function createEmptyDocument() { - const document = DOMImplementationRegistry - .getDOMImplementation() - .createDocument(); - - document.extra = {}; - - // eslint-disable-next-line no-plusplus - for (let i = document.childNodes.length; i; i--) { - document.removeChild(document.childNodes.item(i - 1)); - } - - return document; -} - -function createEventHandler(handlersCollection = {}) { - return function eventHandler(...args) { - const [event] = args; - const { target } = event; - const { tagName } = target; - - const handler = handlersCollection[tagName] - || handlersCollection[DEFAULT_HANDLER] - || noop(); - - return handler.apply(this, args); - }; -} - -export function vdomToDocument(vdom, payload, targetDocument) { - const { navigation } = payload || {}; - const { menuBar, menuItem } = navigation || {}; - - let vnode; - - if (vdom instanceof CustomNode) { - vnode = vdom.toNode(payload); - } else { - vnode = vdom; - } - - if (menuItem) { - const menuItemDocument = menuBar.getDocument(menuItem); - - if (menuItemDocument && menuItemDocument.updateComponent) { - menuItemDocument.updateComponent(payload); - return menuItemDocument; - } - } - - const document = targetDocument || createEmptyDocument(); - const childNode = createElement(vnode, { document }); - - const menuBars = childNode.nodeType === ELEMENT_NODE - ? childNode.getElementsByTagName('menuBar') - : []; - - if (menuBars.length) { - document.menuBarDocument = menuBars.item(0).getFeature('MenuBarDocument'); - } - - if (vnode instanceof Component) { - /** - * `didMount` handler invokes in `navigation/hooks.js` because - * this is the best to not to forget to notify component about mounting. - */ - document.didMount = vnode.componentDidMount.bind(vnode); - document.updateComponent = vnode.updateProps.bind(vnode); - - /** - * `destroyComponent` handler invokes in `navigation/hooks.js` because - * we are not always in control of documents dismissal process. - * - * It's a little magic but we don't have any other options to detect: - * 1. When document was removed by user's activity like pressing "Menu" - * button. - * 2. When modal document was closed. `dismissModal` isn't fires `unload` - * event on document. - */ - document.destroyComponent = vnode.destroy.bind(vnode, childNode); - } - - document.appendChild(childNode); - - eventsList.forEach((eventName) => { - document.addEventListener( - eventName, - createEventHandler(handlers[eventName]), - ); - }); - - return document; -} diff --git a/test/component.js b/test/component.js deleted file mode 100644 index 6f45965..0000000 --- a/test/component.js +++ /dev/null @@ -1,331 +0,0 @@ -/* global describe it */ - -import assert from 'assert'; -import { JSDOM } from 'jsdom'; - -import createComponent from '../src/render/component'; -import { vdomToDocument } from '../src/render/document'; - -const GET_DEFAULT_PROPS = 'getDefaultProps'; -const GET_INITIAL_STATE = 'getInitialState'; -const COMPONENT_WILL_MOUNT = 'componentWillMount'; -const COMPONENT_DID_MOUNT = 'componentDidMount'; -const COMPONENT_WILL_RECEIVE_PROPS = 'componentWillReceiveProps'; -const SHOULD_COMPONENT_UPDATE = 'shouldComponentUpdate'; -const RENDER = 'render'; -const COMPONENT_WILL_UPDATE = 'componentWillUpdate'; -const COMPONENT_DID_UPDATE = 'componentDidUpdate'; -const COMPONENT_WILL_UNMOUNT = 'componentWillUnmount'; - -describe('Component', () => { - it('initial render lifecycle', () => { - const dom = new JSDOM(); - const lifecycleCallOrder = []; - - const vdom = createComponent({ - getDefaultProps() { - lifecycleCallOrder.push(GET_DEFAULT_PROPS); - - assert.equal(this.props, undefined, ` - "this.props" in "getDefaultProps" lifecycle hook should be undefined. - `); - - assert.equal(this.state, undefined, ` - "this.state" in "getDefaultProps" lifecycle hook should be undefined. - `); - - return { b: 1, c: 1 }; - }, - - getInitialState() { - lifecycleCallOrder.push(GET_INITIAL_STATE); - - assert.equal(this.state, undefined, ` - "this.state" in "getInitialState" lifecycle hook should be undefined. - `); - - assert.deepEqual(this.props, { a: 1, b: 2, c: 1 }, ` - "this.props" in "getInitialState" lifecycle hook should result - in combination of the incoming props and props resolved - in "getDefaultProps". - `); - - return { d: 1 }; - }, - - componentWillMount() { - lifecycleCallOrder.push(COMPONENT_WILL_MOUNT); - - assert.deepEqual(this.props, { a: 1, b: 2, c: 1 }, ` - "this.props" in "componentWillMount" lifecycle hook should be same - as in "getInitialState" hook. - `); - - assert.deepEqual(this.state, { d: 1 }, ` - "this.state" in "componentWillMount" lifecycle hook should - be same as resolved in "getInitialState". - `); - }, - - componentDidMount() { - lifecycleCallOrder.push(COMPONENT_DID_MOUNT); - - assert.deepEqual(this.props, { a: 1, b: 2, c: 1 }, ` - "this.props" in "componentDidMount" lifecycle hook should be same - as in "componentWillMount" hook. - `); - - assert.deepEqual(this.state, { d: 1 }, ` - "this.state" in "componentDidMount" lifecycle hook should be same - as in "componentWillMount" hook. - `); - }, - - componentWillReceiveProps() { - lifecycleCallOrder.push(COMPONENT_WILL_RECEIVE_PROPS); - }, - - shouldComponentUpdate() { - lifecycleCallOrder.push(SHOULD_COMPONENT_UPDATE); - return true; - }, - - componentWillUpdate() { - lifecycleCallOrder.push(COMPONENT_WILL_UPDATE); - }, - - componentDidUpdate() { - lifecycleCallOrder.push(COMPONENT_DID_UPDATE); - }, - - componentWillUnmount() { - lifecycleCallOrder.push(COMPONENT_WILL_UNMOUNT); - }, - - render() { - lifecycleCallOrder.push(RENDER); - return null; - }, - }); - - const resolvedDocument = vdomToDocument(vdom, { - a: 1, - b: 2, - }, dom.window.document); - - assert.equal(typeof resolvedDocument.didMount, 'function', ` - "resolvedDocument" should have "didMount" handler. - `); - - // Explicitly calling mount event on resolved document. - resolvedDocument.didMount(); - - assert.deepEqual(lifecycleCallOrder, [ - GET_DEFAULT_PROPS, - GET_INITIAL_STATE, - COMPONENT_WILL_MOUNT, - RENDER, - COMPONENT_DID_MOUNT, - ], 'lifecycle order should be as expected'); - }); - - it('update lifecycle', () => { - const dom = new JSDOM(); - const lifecycleCallOrder = []; - - let counter = 1; - - const vdom = createComponent({ - getDefaultProps() { - lifecycleCallOrder.push(GET_DEFAULT_PROPS); - }, - - getInitialState() { - lifecycleCallOrder.push(GET_INITIAL_STATE); - }, - - componentWillMount() { - lifecycleCallOrder.push(COMPONENT_WILL_MOUNT); - }, - - componentDidMount() { - lifecycleCallOrder.push(COMPONENT_DID_MOUNT); - }, - - componentWillReceiveProps(nextProps) { - lifecycleCallOrder.push(COMPONENT_WILL_RECEIVE_PROPS); - - assert.deepEqual(this.props, {}, ` - "this.props" in "componentWillReceiveProps" should be unchanged. - `); - - assert.deepEqual(this.state, {}, ` - "this.state" in "componentWillReceiveProps" should be unchanged. - `); - - assert.deepEqual(nextProps, { a: 1, b: 1 }, ` - "componentWillReceiveProps" should receive updated payload. - `); - }, - - shouldComponentUpdate() { - lifecycleCallOrder.push(SHOULD_COMPONENT_UPDATE); - return true; - }, - - componentWillUpdate() { - lifecycleCallOrder.push(COMPONENT_WILL_UPDATE); - }, - - componentDidUpdate() { - lifecycleCallOrder.push(COMPONENT_DID_UPDATE); - - if (this.props.a && !this.state.didUpdated) { - // eslint-disable-next-line react/no-did-update-set-state - this.setState({ didUpdated: true }); - } - }, - - componentWillUnmount() { - lifecycleCallOrder.push(COMPONENT_WILL_UNMOUNT); - }, - - render() { - lifecycleCallOrder.push(RENDER); - - switch (counter) { - case 1: - assert.deepEqual(this.props, {}, ` - "this.props" on first render should be empty. - `); - - assert.deepEqual(this.state, {}, ` - "this.state" on first render should be empty. - `); - break; - case 2: - assert.deepEqual(this.props, { a: 1, b: 1 }, ` - "this.props" on second render should be updated to new ones. - `); - - assert.deepEqual(this.state, {}, ` - "this.state" on second render should be empty. - `); - break; - case 3: - assert.deepEqual(this.props, { a: 1, b: 1 }, ` - "this.props" on third render should not changed. - `); - - assert.deepEqual(this.state, { didUpdated: true }, ` - "this.state" on third render should be set to new one. - `); - break; - default: - assert.ok(false, 'should not reach this statement'); - } - - counter += 1; - - return null; - }, - }); - - const resolvedDocument = vdomToDocument(vdom, null, dom.window.document); - - // Explicitly calling mount event on resolved document. - resolvedDocument.didMount(); - - assert.equal(typeof resolvedDocument.updateComponent, 'function', ` - "resolvedDocument" should have "updateComponent" handler. - `); - - resolvedDocument.updateComponent({ a: 1, b: 1 }); - - assert.deepEqual(lifecycleCallOrder, [ - GET_DEFAULT_PROPS, - GET_INITIAL_STATE, - COMPONENT_WILL_MOUNT, - RENDER, - COMPONENT_DID_MOUNT, - COMPONENT_WILL_RECEIVE_PROPS, - SHOULD_COMPONENT_UPDATE, - COMPONENT_WILL_UPDATE, - RENDER, - COMPONENT_DID_UPDATE, - SHOULD_COMPONENT_UPDATE, - COMPONENT_WILL_UPDATE, - RENDER, - COMPONENT_DID_UPDATE, - ], 'lifecycle order should be as expected'); - }); - - it('unmount lifecycle', () => { - const dom = new JSDOM(); - const lifecycleCallOrder = []; - - const vdom = createComponent({ - getDefaultProps() { - lifecycleCallOrder.push(GET_DEFAULT_PROPS); - }, - - getInitialState() { - lifecycleCallOrder.push(GET_INITIAL_STATE); - }, - - componentWillMount() { - lifecycleCallOrder.push(COMPONENT_WILL_MOUNT); - }, - - componentDidMount() { - lifecycleCallOrder.push(COMPONENT_DID_MOUNT); - }, - - componentWillReceiveProps() { - lifecycleCallOrder.push(COMPONENT_WILL_RECEIVE_PROPS); - }, - - shouldComponentUpdate() { - lifecycleCallOrder.push(SHOULD_COMPONENT_UPDATE); - return true; - }, - - componentWillUpdate() { - lifecycleCallOrder.push(COMPONENT_WILL_UPDATE); - }, - - componentDidUpdate() { - lifecycleCallOrder.push(COMPONENT_DID_UPDATE); - }, - - componentWillUnmount() { - lifecycleCallOrder.push(COMPONENT_WILL_UNMOUNT); - }, - - render() { - lifecycleCallOrder.push(RENDER); - return null; - }, - }); - - const resolvedDocument = vdomToDocument(vdom, null, dom.window.document); - - // Explicitly calling mount event on resolved document. - resolvedDocument.didMount(); - - assert.equal(typeof resolvedDocument.destroyComponent, 'function', ` - "resolvedDocument" should have "destroyComponent" handler. - `); - - resolvedDocument.destroyComponent(); - - assert.deepEqual(lifecycleCallOrder, [ - GET_DEFAULT_PROPS, - GET_INITIAL_STATE, - COMPONENT_WILL_MOUNT, - RENDER, - COMPONENT_DID_MOUNT, - COMPONENT_WILL_UNMOUNT, - ], 'lifecycle order should be as expected'); - }); -}); From 04fb3454b6fee583d216587b0c6176a22a3f250a Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 00:45:40 +0300 Subject: [PATCH 09/48] Removed unused dependencies --- package.json | 2 - yarn.lock | 390 ++------------------------------------------------- 2 files changed, 12 insertions(+), 380 deletions(-) diff --git a/package.json b/package.json index 5be6fb1..16444b4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ }, "homepage": "https://github.com/a-ignatov-parc/tvdml#readme", "dependencies": { - "@a-ignatov-parc/virtual-dom": "^2.2.0", "react-reconciler": "^0.7.0" }, "devDependencies": { @@ -50,7 +49,6 @@ "eslint-plugin-import": "^2.8.0", "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-react": "^7.4.0", - "jsdom": "^11.5.1", "mocha": "^3.1.2", "mocha-junit-reporter": "^1.15.0", "react": "^16.2.0", diff --git a/yarn.lock b/yarn.lock index 9358c63..49ed474 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,27 +2,6 @@ # yarn lockfile v1 -"@a-ignatov-parc/virtual-dom@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@a-ignatov-parc/virtual-dom/-/virtual-dom-2.2.0.tgz#7050cc99a0b83e165a0fbed4c0266ab4f242ac31" - dependencies: - browser-split "0.0.1" - error "^4.3.0" - ev-store "^7.0.0" - global "^4.3.0" - is-object "^1.0.1" - next-tick "^0.2.2" - x-is-array "0.1.0" - x-is-string "0.1.0" - -"@types/node@*": - version "8.0.53" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8" - -abab@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -33,12 +12,6 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" -acorn-globals@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" - dependencies: - acorn "^5.0.0" - acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -57,10 +30,6 @@ acorn@^5.0.0, acorn@^5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" -acorn@^5.1.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" - ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" @@ -81,15 +50,6 @@ ajv@^5.0.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^5.1.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.0.tgz#eb2840746e9dc48bd5e063a36e3fd400c5eab5a9" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - ajv@^5.1.5, ajv@^5.2.0, ajv@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" @@ -169,10 +129,6 @@ arr-flatten@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - array-includes@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" @@ -250,11 +206,7 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: +aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" @@ -455,18 +407,6 @@ boom@2.x.x: dependencies: hoek "2.x.x" -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -486,14 +426,6 @@ brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" -browser-process-hrtime@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" - -browser-split@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/browser-split/-/browser-split-0.0.1.tgz#7b097574f8e3ead606fb4664e64adfdda2981a93" - browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" @@ -606,10 +538,6 @@ camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -767,10 +695,6 @@ contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -content-type-parser@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" - convert-source-map@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" @@ -843,12 +767,6 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - crypto-browserify@^3.11.0: version "3.11.1" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" @@ -864,16 +782,6 @@ crypto-browserify@^3.11.0: public-encrypt "^4.0.0" randombytes "^2.0.0" -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" - -"cssstyle@>= 0.2.37 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - dependencies: - cssom "0.3.x" - cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -994,18 +902,10 @@ doctrine@^2.0.0: esutils "^2.0.2" isarray "^1.0.0" -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" -domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.0.tgz#81fe5df81b3f057052cde3a9fa9bf536a85b9ab0" - duplexify@^3.1.2, duplexify@^3.4.2: version "3.5.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" @@ -1080,14 +980,6 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -error@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/error/-/error-4.4.0.tgz#bf69ff251fb4a279c19adccdaa6b61e90d9bf12a" - dependencies: - camelize "^1.0.0" - string-template "~0.2.0" - xtend "~4.0.0" - es-abstract@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" @@ -1162,17 +1054,6 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.5.6" - escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -1304,10 +1185,6 @@ espree@^3.5.1: acorn "^5.1.1" acorn-jsx "^3.0.0" -esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -1333,12 +1210,6 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -ev-store@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/ev-store/-/ev-store-7.0.0.tgz#1ab0c7f82136505dd74b31d17701cb2be6d26558" - dependencies: - individual "^3.0.0" - event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" @@ -1381,7 +1252,7 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -extend@~3.0.0, extend@~3.0.1: +extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -1517,14 +1388,6 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" -form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - from2@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -1639,13 +1502,6 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -global@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - globals@^9.17.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -1677,10 +1533,6 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -1688,13 +1540,6 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -1748,15 +1593,6 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" @@ -1773,10 +1609,6 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -1788,12 +1620,6 @@ hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" -html-encoding-sniffer@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - dependencies: - whatwg-encoding "^1.0.1" - http-signature@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" @@ -1802,19 +1628,11 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: +iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -1838,10 +1656,6 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -individual@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/individual/-/individual-3.0.0.tgz#e7ca4f85f8957b018734f285750dc22ec2f9862d" - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1974,10 +1788,6 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -2074,35 +1884,6 @@ jschardet@^1.4.2: version "1.5.1" resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" -jsdom@^11.5.1: - version "11.5.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.5.1.tgz#5df753b8d0bca20142ce21f4f6c039f99a992929" - dependencies: - abab "^1.0.3" - acorn "^5.1.2" - acorn-globals "^4.0.0" - array-equal "^1.0.0" - browser-process-hrtime "^0.1.2" - content-type-parser "^1.0.1" - cssom ">= 0.3.2 < 0.4.0" - cssstyle ">= 0.2.37 < 0.3.0" - domexception "^1.0.0" - escodegen "^1.9.0" - html-encoding-sniffer "^1.0.1" - left-pad "^1.2.0" - nwmatcher "^1.4.3" - parse5 "^3.0.2" - pn "^1.0.0" - request "^2.83.0" - request-promise-native "^1.0.3" - sax "^1.2.1" - symbol-tree "^3.2.1" - tough-cookie "^2.3.3" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.1" - whatwg-url "^6.3.0" - xml-name-validator "^2.0.1" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -2182,10 +1963,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -left-pad@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -2272,11 +2049,7 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - -lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0: +lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -2360,7 +2133,7 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: @@ -2370,12 +2143,6 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -2472,10 +2239,6 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -next-tick@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-0.2.2.tgz#75da4a927ee5887e39065880065b7336413b310d" - node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -2567,11 +2330,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -nwmatcher@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" - -oauth-sign@~0.8.1, oauth-sign@~0.8.2: +oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -2602,7 +2361,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -2691,12 +2450,6 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" -parse5@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - dependencies: - "@types/node" "*" - path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" @@ -2747,10 +2500,6 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2781,10 +2530,6 @@ pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" -pn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" - prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -2805,10 +2550,6 @@ process@^0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -2876,18 +2617,10 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" -qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -3000,20 +2733,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - dependencies: - lodash "^4.13.1" - -request-promise-native@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" - dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.3" - request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -3041,33 +2760,6 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.83.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -3145,10 +2837,6 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -sax@^1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" @@ -3212,12 +2900,6 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -3228,7 +2910,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6: +source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -3274,10 +2956,6 @@ ssri@^5.0.0: dependencies: safe-buffer "^5.1.0" -stealthy-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -3306,10 +2984,6 @@ stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" -string-template@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -3335,7 +3009,7 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4, stringstream@~0.0.5: +stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -3379,10 +3053,6 @@ supports-color@^4.0.0, supports-color@^4.2.1: dependencies: has-flag "^2.0.0" -symbol-tree@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" - table@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" @@ -3454,18 +3124,12 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: +tough-cookie@~2.3.0: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" -tr46@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - dependencies: - punycode "^2.1.0" - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -3576,7 +3240,7 @@ util@0.10.3, util@^0.10.3: dependencies: inherits "2.0.1" -uuid@^3.0.0, uuid@^3.1.0: +uuid@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -3609,10 +3273,6 @@ watchpack@^1.4.0: chokidar "^1.7.0" graceful-fs "^4.1.2" -webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - webpack-sources@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf" @@ -3647,24 +3307,10 @@ webpack@^3.10.0: webpack-sources "^1.0.1" yargs "^8.0.2" -whatwg-encoding@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" - dependencies: - iconv-lite "0.4.19" - whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" -whatwg-url@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.3.0.tgz#597ee5488371abe7922c843397ddec1ae94c048d" - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.0" - webidl-conversions "^4.0.1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -3717,23 +3363,11 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -x-is-array@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-array/-/x-is-array-0.1.0.tgz#de520171d47b3f416f5587d629b89d26b12dc29d" - -x-is-string@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" - -xml-name-validator@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" - xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 729ded629838368132f370b4b53438d9f26a2439 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 00:46:59 +0300 Subject: [PATCH 10/48] libs update --- package.json | 8 +- yarn.lock | 204 +++++++++++++++++---------------------------------- 2 files changed, 73 insertions(+), 139 deletions(-) diff --git a/package.json b/package.json index 16444b4..3a8ea58 100644 --- a/package.json +++ b/package.json @@ -44,12 +44,12 @@ "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-register": "^6.26.0", - "eslint": "^4.9.0", + "eslint": "^4.13.1", "eslint-config-airbnb": "^16.1.0", "eslint-plugin-import": "^2.8.0", - "eslint-plugin-jsx-a11y": "^6.0.2", - "eslint-plugin-react": "^7.4.0", - "mocha": "^3.1.2", + "eslint-plugin-jsx-a11y": "^6.0.3", + "eslint-plugin-react": "^7.5.1", + "mocha": "^4.0.1", "mocha-junit-reporter": "^1.15.0", "react": "^16.2.0", "uglifyjs-webpack-plugin": "^1.1.4", diff --git a/yarn.lock b/yarn.lock index 49ed474..812d9c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,10 +26,14 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0, acorn@^5.1.1: +acorn@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +acorn@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" + ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" @@ -41,7 +45,7 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0: +ajv@^5.0.0, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -50,7 +54,7 @@ ajv@^5.0.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^5.1.5, ajv@^5.2.0, ajv@^5.2.3: +ajv@^5.1.5, ajv@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" dependencies: @@ -651,11 +655,9 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" commander@~2.12.1: version "2.12.2" @@ -806,9 +808,9 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.6.8: - version "2.6.8" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" +debug@3.1.0, debug@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" @@ -818,12 +820,6 @@ debug@^2.2.0, debug@^2.6.8: dependencies: ms "2.0.0" -debug@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -876,9 +872,9 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -diff@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" diffie-hellman@^5.0.0: version "5.0.2" @@ -902,6 +898,12 @@ doctrine@^2.0.0: esutils "^2.0.2" isarray "^1.0.0" +doctrine@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" + dependencies: + esutils "^2.0.2" + domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -1104,9 +1106,9 @@ eslint-plugin-import@^2.8.0: minimatch "^3.0.3" read-pkg-up "^2.0.0" -eslint-plugin-jsx-a11y@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.2.tgz#659277a758b036c305a7e4a13057c301cd3be73f" +eslint-plugin-jsx-a11y@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz#54583d1ae442483162e040e13cc31865465100e5" dependencies: aria-query "^0.7.0" array-includes "^3.0.3" @@ -1114,16 +1116,16 @@ eslint-plugin-jsx-a11y@^6.0.2: axobject-query "^0.1.0" damerau-levenshtein "^1.0.0" emoji-regex "^6.1.0" - jsx-ast-utils "^1.4.0" + jsx-ast-utils "^2.0.0" -eslint-plugin-react@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz#300a95861b9729c087d362dd64abcc351a74364a" +eslint-plugin-react@^7.5.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b" dependencies: doctrine "^2.0.0" has "^1.0.1" jsx-ast-utils "^2.0.0" - prop-types "^15.5.10" + prop-types "^15.6.0" eslint-restricted-globals@^0.1.1: version "0.1.1" @@ -1136,32 +1138,32 @@ eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.9.0.tgz#76879d274068261b191fe0f2f56c74c2f4208e8b" +eslint@^4.13.1: + version "4.13.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.13.1.tgz#0055e0014464c7eb7878caf549ef2941992b444f" dependencies: - ajv "^5.2.0" + ajv "^5.3.0" babel-code-frame "^6.22.0" chalk "^2.1.0" concat-stream "^1.6.0" cross-spawn "^5.1.0" debug "^3.0.1" - doctrine "^2.0.0" + doctrine "^2.0.2" eslint-scope "^3.7.1" - espree "^3.5.1" + espree "^3.5.2" esquery "^1.0.0" estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^9.17.0" + globals "^11.0.1" ignore "^3.3.3" imurmurhash "^0.1.4" inquirer "^3.0.6" is-resolvable "^1.0.0" js-yaml "^3.9.1" - json-stable-stringify "^1.0.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" lodash "^4.17.4" minimatch "^3.0.2" @@ -1178,11 +1180,11 @@ eslint@^4.9.0: table "^4.0.1" text-table "~0.2.0" -espree@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" +espree@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" dependencies: - acorn "^5.1.1" + acorn "^5.2.1" acorn-jsx "^3.0.0" esprima@^4.0.0: @@ -1480,18 +1482,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: +glob@7.1.2, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -1502,7 +1493,11 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^9.17.0, globals@^9.18.0: +globals@^11.0.1: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.1.0.tgz#632644457f5f0e3ae711807183700ebf2e4633e4" + +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -1521,13 +1516,9 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" har-schema@^1.0.5: version "1.0.5" @@ -1546,10 +1537,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" @@ -1900,6 +1887,10 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -1910,10 +1901,6 @@ json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json3@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -1931,10 +1918,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsx-ast-utils@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" - jsx-ast-utils@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" @@ -1998,57 +1981,10 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash._baseassign@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keys "^3.0.0" - -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - -lodash._basecreate@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - lodash.cond@^4.3.0: version "4.5.2" resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" -lodash.create@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" - dependencies: - lodash._baseassign "^3.0.0" - lodash._basecreate "^3.0.0" - lodash._isiterateecall "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -2195,22 +2131,20 @@ mocha-junit-reporter@^1.15.0: mkdirp "~0.5.1" xml "^1.0.0" -mocha@^3.1.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" +mocha@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.0.1.tgz#0aee5a95cf69a4618820f5e51fa31717117daf1b" dependencies: browser-stdout "1.3.0" - commander "2.9.0" - debug "2.6.8" - diff "3.2.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" escape-string-regexp "1.0.5" - glob "7.1.1" - growl "1.9.2" + glob "7.1.2" + growl "1.10.3" he "1.1.1" - json3 "3.3.2" - lodash.create "3.1.1" mkdirp "0.5.1" - supports-color "3.1.2" + supports-color "4.4.0" move-concurrently@^1.0.1: version "1.0.1" @@ -2564,7 +2498,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.10, prop-types@^15.6.0: +prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" dependencies: @@ -3037,11 +2971,11 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" -supports-color@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" dependencies: - has-flag "^1.0.0" + has-flag "^2.0.0" supports-color@^2.0.0: version "2.0.0" From 044be509998e41adc566bfeaae19b7f4184e1907 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 00:59:59 +0300 Subject: [PATCH 11/48] package tags update + implemented proper react element mount/unmount --- package.json | 3 +-- src/navigation/hooks.js | 4 ++-- src/react-tvml/index.js | 1 - src/render.js | 26 ++++++-------------------- 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 3a8ea58..4f63b92 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,11 @@ "url": "git+https://github.com/a-ignatov-parc/tvdml.git" }, "keywords": [ - "virtual", + "react", "apple", "tvos", "tvjs", "tvml", - "dom", "tv" ], "author": "Anton Ignatov ", diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index 146b5a4..4005418 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -1,5 +1,6 @@ /* global navigationDocument */ +import ReactTVML from '../react-tvml'; import { broadcast } from '../event-bus'; let enabled = false; @@ -10,9 +11,8 @@ function destroyComponents(document) { * Mark document as removed by menu button press. * This is just a guess but still can be handy. */ - // eslint-disable-next-line no-param-reassign document.possiblyDismissedByUser = true; - if (document.unmount) document.unmount(); + ReactTVML.unmountComponentAtNode(document); } function handleUnload({ target: { ownerDocument: document } }) { diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index dbf8091..8adeba2 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import ReactFiberReconciler from 'react-reconciler'; import { broadcast } from '../event-bus'; diff --git a/src/render.js b/src/render.js index 0c51359..caa4d01 100644 --- a/src/render.js +++ b/src/render.js @@ -1,7 +1,8 @@ /* global navigationDocument, DOMImplementationRegistry */ -import ReactTVML from './react-tvml'; +import React from 'react'; +import ReactTVML from './react-tvml'; import { promisedTimeout } from './utils'; import { passthrough, createPipeline } from './pipelines'; @@ -29,24 +30,7 @@ export function render(Component) { .getDOMImplementation() .createDocument(); - const root = TVMLRenderer.createContainer( - document, // container - false, // isAsync - false, // hydrate - ); - - Object.assign(document, { - route, - reactRoot: root, - - render(children, callback) { - TVMLRenderer.updateContainer(children, root, null, callback); - }, - - unmount(callback) { - TVMLRenderer.updateContainer(null, root, null, callback); - }, - }); + document.route = route; } /** @@ -56,7 +40,9 @@ export function render(Component) { */ if (document.possiblyDismissedByUser) return null; - document.render(React.createElement(Component, payload)); + const element = React.createElement(Component, payload); + + ReactTVML.render(element, document); if (!document.isAttached) { if (redirect) { From 12994c8d785cf893aa6da0e757a8f67af981e4b7 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 01:08:57 +0300 Subject: [PATCH 12/48] react marked as external dependency --- webpack.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webpack.config.js b/webpack.config.js index d6bb452..7988aa2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -70,6 +70,7 @@ module.exports = { path: resolveFromRoot('./dist'), }, devtool: isProd ? 'source-map' : 'eval-source-map', + externals: ['react'], // peerDependencies module: { rules }, plugins, stats, From 229deae4b8ceaf3e4e12b5db91d22b92baaa745f Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 01:12:45 +0300 Subject: [PATCH 13/48] Bugfix --- src/react-tvml/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index 8adeba2..ee84377 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -357,6 +357,8 @@ class ReactRoot { }; function createRoot(container) { + let rootSibling; + while ((rootSibling = container.lastChild)) { container.removeChild(rootSibling); } @@ -373,7 +375,7 @@ const ReactTVML = { root = container._reactRootContainer = createRoot(container); TVMLRenderer.unbatchedUpdates(() => { - root.render(children, () => { + root.render(element, () => { if (typeof callback === 'function') { const instance = TVMLRenderer.getPublicRootInstance( root._internalRoot, @@ -385,7 +387,7 @@ const ReactTVML = { }); } else { // Update - root.render(children, () => { + root.render(element, () => { if (typeof callback === 'function') { const instance = TVMLRenderer.getPublicRootInstance( root._internalRoot, From e6c769fdec6da49aedb4cfec02ac9539f5e0758c Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 01:39:50 +0300 Subject: [PATCH 14/48] Fixed linter errors --- .eslintrc | 11 +++++- src/navigation/hooks.js | 1 - src/react-tvml/index.js | 75 ++++++++++++++++++++--------------------- src/render.js | 4 ++- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/.eslintrc b/.eslintrc index aaa64d0..71dd197 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,6 +2,15 @@ "extends": "airbnb", "rules": { "max-len": ["error", 80], - "no-console": ["error", { allow: ["info", "warn", "error"] }] + "no-console": ["error", { + allow: ["info", "warn", "error"] + }], + "no-param-reassign": ["error", { + "props": false + }], + "no-underscore-dangle": ["error", { + "allow": ["_internalRoot", "_reactRootContainer"] + }], + "no-prototype-builtins": "off" }, } diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index 4005418..4eea5da 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -97,7 +97,6 @@ const methodsToPatch = Object.keys(handlers); const originalMethods = methodsToPatch .map(name => ({ name, method: navigationDocument[name] })) .reduce((result, { name, method }) => { - // eslint-disable-next-line no-param-reassign result[name] = method; return result; }, {}); diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index ee84377..bfecb46 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -27,7 +27,7 @@ function getOwnerDocumentFromRootContainer(rootContainerElement) { : rootContainerElement.ownerDocument; } -function createElement(type, props, rootContainerElement, parentNamespace) { +function createElement(type, props, rootContainerElement) { const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); const domElement = ownerDocument.createElement(type); return domElement; @@ -40,11 +40,17 @@ function createTextNode(text, rootContainerElement) { } function setInitialProperties(domElement, type, props, rootContainerElement) { - console.log('setInitialProperties', domElement, type, props); + console.info( + 'setInitialProperties', + domElement, + type, + props, + rootContainerElement, + ); Object .keys(props) - .forEach(propName => { + .forEach((propName) => { const propValue = props[propName]; if (propName === CHILDREN) { @@ -84,17 +90,17 @@ function diffProperties( type, oldProps, newProps, - rootContainerInstance, + // rootContainerInstance, ) { let updatePayload = null; Object .keys(oldProps) - .forEach(propName => { + .forEach((propName) => { const propValue = oldProps[propName]; const shouldSkip = newProps.hasOwnProperty(propName) || !oldProps.hasOwnProperty(propName) - || oldProps[propName] == null; + || propValue == null; if (shouldSkip) return; (updatePayload = updatePayload || []).push(propName, null); @@ -102,7 +108,7 @@ function diffProperties( Object .keys(newProps) - .forEach(propName => { + .forEach((propName) => { const propValue = newProps[propName]; const oldPropValue = oldProps != null ? oldProps[propName] : undefined; @@ -119,7 +125,7 @@ function diffProperties( ); if (shouldUpdate) { - (updatePayload = updatePayload || []).push(propName, '' + propValue); + (updatePayload = updatePayload || []).push(propName, `${propValue}`); } } else { (updatePayload = updatePayload || []).push(propName, propValue); @@ -127,7 +133,7 @@ function diffProperties( }); if (updatePayload) { - console.log( + console.info( 'diffProperties', domElement, type, @@ -145,7 +151,7 @@ function updateProperties(domElement, updatePayload, type, oldProps, newProps) { const propName = updatePayload[i]; const propValue = updatePayload[i + 1]; - console.log( + console.info( 'updateProperties', domElement, type, @@ -173,26 +179,23 @@ function updateProperties(domElement, updatePayload, type, oldProps, newProps) { domElement.addEventListener(eventName, propValue); } } + } else if (propValue === null || typeof propValue === 'undefined') { + domElement.removeAttribute(propName); } else { - if (propValue === null || typeof propValue === 'undefined') { - domElement.removeAttribute(propName); - } else { - domElement.setAttribute(propName, propValue); - } + domElement.setAttribute(propName, propValue); } } } const TVMLRenderer = ReactFiberReconciler({ getRootHostContext(rootContainerInstance) { - const nodeType = rootContainerInstance.nodeType; - + const { nodeType } = rootContainerInstance; let namespace; switch (nodeType) { case DOCUMENT_NODE: case DOCUMENT_FRAGMENT_NODE: { - let root = rootContainerInstance.documentElement; + const root = rootContainerInstance.documentElement; namespace = root ? root.namespaceURI : NAMESPACE; break; } @@ -204,7 +207,7 @@ const TVMLRenderer = ReactFiberReconciler({ return namespace; }, - getChildHostContext(parentHostContext, type) { + getChildHostContext(/* parentHostContext, type */) { return NAMESPACE; }, @@ -246,7 +249,6 @@ const TVMLRenderer = ReactFiberReconciler({ oldProps, newProps, rootContainerInstance, - hostContext, ) { return diffProperties( domElement, @@ -257,15 +259,15 @@ const TVMLRenderer = ReactFiberReconciler({ ); }, - shouldSetTextContent(type, props) { + shouldSetTextContent(/* type, props */) { return false; }, - shouldDeprioritizeSubtree(type, props) { + shouldDeprioritizeSubtree(/* type, props */) { return false; }, - createTextInstance(text, rootContainerInstance, hostContext) { + createTextInstance(text, rootContainerInstance) { const textNode = createTextNode(text, rootContainerInstance); return textNode; }, @@ -276,7 +278,7 @@ const TVMLRenderer = ReactFiberReconciler({ mutation: { commitMount(domElement, type, newProps) { - console.log( + console.info( 'commitMount', domElement, type, @@ -354,13 +356,14 @@ class ReactRoot { const root = this._internalRoot; TVMLRenderer.updateContainer(null, root, null, callback); } -}; +} function createRoot(container) { - let rootSibling; + let rootSibling = container.lastChild; - while ((rootSibling = container.lastChild)) { + while (rootSibling) { container.removeChild(rootSibling); + rootSibling = container.lastChild; } return new ReactRoot(container); @@ -372,15 +375,14 @@ const ReactTVML = { if (!root) { // Initial mount - root = container._reactRootContainer = createRoot(container); + root = createRoot(container); + container._reactRootContainer = root; TVMLRenderer.unbatchedUpdates(() => { root.render(element, () => { if (typeof callback === 'function') { - const instance = TVMLRenderer.getPublicRootInstance( - root._internalRoot, - ); - + const { _internalRoot } = root; + const instance = TVMLRenderer.getPublicRootInstance(_internalRoot); callback.call(instance); } }); @@ -389,10 +391,8 @@ const ReactTVML = { // Update root.render(element, () => { if (typeof callback === 'function') { - const instance = TVMLRenderer.getPublicRootInstance( - root._internalRoot, - ); - + const { _internalRoot } = root; + const instance = TVMLRenderer.getPublicRootInstance(_internalRoot); callback.call(instance); } }); @@ -409,9 +409,8 @@ const ReactTVML = { }); }); return true; - } else { - return false; } + return false; }, }; diff --git a/src/render.js b/src/render.js index caa4d01..d701b4b 100644 --- a/src/render.js +++ b/src/render.js @@ -9,7 +9,7 @@ import { passthrough, createPipeline } from './pipelines'; const RENDERING_ANIMATION = 600; export function renderModalReact(Component) { - console.log('renderModalReact', Component); + console.info('renderModalReact', Component); } export function render(Component) { @@ -23,6 +23,8 @@ export function render(Component) { const { menuBar, menuItem } = navigation; + console.info(1, menuBar, menuItem); + let { document } = payload; if (!document) { From c720c36d71cadd43a23fe715c2db7a0d992a2617 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 01:53:50 +0300 Subject: [PATCH 15/48] Removed unused code --- src/navigation/hooks.js | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index 4eea5da..08dce4f 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -6,7 +6,7 @@ import { broadcast } from '../event-bus'; let enabled = false; let modalDocument = null; -function destroyComponents(document) { +function unmount(document) { /** * Mark document as removed by menu button press. * This is just a guess but still can be handy. @@ -16,14 +16,14 @@ function destroyComponents(document) { } function handleUnload({ target: { ownerDocument: document } }) { - destroyComponents(document); + unmount(document); broadcast('uncontrolled-document-pop', { document }); } const handlers = { presentModal(document) { if (modalDocument) { - destroyComponents(modalDocument); + unmount(modalDocument); modalDocument.removeEventListener('unload', handleUnload); } modalDocument = document; @@ -32,7 +32,7 @@ const handlers = { dismissModal(custom) { if (modalDocument && custom) { - destroyComponents(modalDocument); + unmount(modalDocument); modalDocument.removeEventListener('unload', handleUnload); } modalDocument = null; @@ -47,14 +47,14 @@ const handlers = { }, replaceDocument(document, oldDocument) { - destroyComponents(oldDocument); + unmount(oldDocument); oldDocument.removeEventListener('unload', handleUnload); document.addEventListener('unload', handleUnload); }, clear() { navigationDocument.documents.forEach((document) => { - destroyComponents(document); + unmount(document); document.removeEventListener('unload', handleUnload); }); }, @@ -62,7 +62,7 @@ const handlers = { popDocument() { const document = navigationDocument.documents.pop(); - destroyComponents(document); + unmount(document); document.removeEventListener('unload', handleUnload); }, @@ -72,7 +72,7 @@ const handlers = { navigationDocument.documents .slice(index + 1) .forEach((documentItem) => { - destroyComponents(documentItem); + unmount(documentItem); documentItem.removeEventListener('unload', handleUnload); }); }, @@ -81,13 +81,13 @@ const handlers = { navigationDocument.documents .slice(1) .forEach((document) => { - destroyComponents(document); + unmount(document); document.removeEventListener('unload', handleUnload); }); }, removeDocument(document) { - destroyComponents(document); + unmount(document); document.removeEventListener('unload', handleUnload); }, }; @@ -106,25 +106,10 @@ export function enable() { throw new Error('Hooks already enabled'); } - const shouldMountComponentFor = { - presentModal: true, - pushDocument: true, - replaceDocument: true, - insertBeforeDocument: true, - }; - methodsToPatch.forEach((name) => { navigationDocument[name] = function TVDMLWrapper(...args) { if (handlers[name]) handlers[name].apply(this, args); - - const result = originalMethods[name].apply(this, args); - const [document] = args; - - if (shouldMountComponentFor[name] && document.didMount) { - document.didMount(); - } - - return result; + return originalMethods[name].apply(this, args); }; }); From 324520ec2977799a746c6b1005b437906abfab51 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 02:28:00 +0300 Subject: [PATCH 16/48] Bugfix + implemented rendering to madal --- src/render.js | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/render.js b/src/render.js index d701b4b..6079ef8 100644 --- a/src/render.js +++ b/src/render.js @@ -8,13 +8,47 @@ import { passthrough, createPipeline } from './pipelines'; const RENDERING_ANIMATION = 600; -export function renderModalReact(Component) { - console.info('renderModalReact', Component); +let hasModal = false; + +function createDocument() { + return DOMImplementationRegistry.getDOMImplementation().createDocument(); +} + +export function removeModal() { + hasModal = false; + navigationDocument.dismissModal(true); +} + +export function renderModal(Component) { + return createPipeline() + .pipe(passthrough(() => { + if (!hasModal) return null; + removeModal(); + return promisedTimeout(RENDERING_ANIMATION); + })) + .pipe(passthrough((payload = {}) => { + const { route } = payload; + const document = createDocument(); + const lastDocument = navigationDocument.documents.pop() || {}; + + document.modal = true; + document.route = route || lastDocument.route; + + const element = React.createElement(Component, payload); + + ReactTVML.render(element, document); + + hasModal = true; + + navigationDocument.presentModal(document); + + document.isAttached = true; + })); } export function render(Component) { return createPipeline() - .pipe(passthrough((payload) => { + .pipe(passthrough((payload = {}) => { const { route, redirect, @@ -28,10 +62,7 @@ export function render(Component) { let { document } = payload; if (!document) { - document = DOMImplementationRegistry - .getDOMImplementation() - .createDocument(); - + document = createDocument(); document.route = route; } From 289c9bd4a7d30764bb9f7f3dfec0904a10a15a14 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 02:49:37 +0300 Subject: [PATCH 17/48] yarn.lock regeneration --- yarn.lock | 271 ++++++++++++++++++++++++++---------------------------- 1 file changed, 128 insertions(+), 143 deletions(-) diff --git a/yarn.lock b/yarn.lock index 812d9c8..7af74f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,17 +26,13 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" - -acorn@^5.2.1: +acorn@^5.0.0, acorn@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" ajv@^4.9.1: version "4.11.8" @@ -45,7 +41,7 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.3.0: +ajv@^5.0.0, ajv@^5.1.5, ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -54,15 +50,6 @@ ajv@^5.0.0, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^5.1.5, ajv@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - json-schema-traverse "^0.3.0" - json-stable-stringify "^1.0.1" - align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -163,8 +150,8 @@ asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" asn1.js@^4.0.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + version "4.9.2" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a" dependencies: bn.js "^4.0.0" inherits "^2.0.1" @@ -197,8 +184,8 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" async@^2.1.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: lodash "^4.14.0" @@ -388,8 +375,8 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" block-stream@*: version "0.0.9" @@ -480,11 +467,11 @@ browserify-sign@^4.0.0: inherits "^2.0.1" parse-asn1 "^5.0.0" -browserify-zlib@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" dependencies: - pako "~0.2.0" + pako "~1.0.5" buffer-xor@^1.0.3: version "1.0.3" @@ -564,13 +551,17 @@ chalk@^1.1.3: supports-color "^2.0.0" chalk@^2.0.0, chalk@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.2.0.tgz#477b3bf2f9b8fd5ca9e429747e37f724ee7af240" + version "2.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -640,8 +631,8 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" color-convert@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" @@ -698,8 +689,8 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" copy-concurrently@^1.0.0: version "1.0.5" @@ -717,8 +708,8 @@ core-js@^1.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -770,8 +761,8 @@ cryptiles@2.x.x: boom "2.x.x" crypto-browserify@^3.11.0: - version "3.11.1" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -783,6 +774,7 @@ crypto-browserify@^3.11.0: pbkdf2 "^3.0.3" public-encrypt "^4.0.0" randombytes "^2.0.0" + randomfill "^1.0.3" cyclist@~0.2.2: version "0.2.2" @@ -808,7 +800,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@3.1.0, debug@^3.0.1: +debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -872,6 +864,10 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" @@ -891,14 +887,7 @@ doctrine@1.5.0: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.0.2: +doctrine@^2.0.0, doctrine@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: @@ -964,13 +953,7 @@ enhanced-resolve@^3.4.0: object-assign "^4.0.1" tapable "^0.2.7" -errno@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" - dependencies: - prr "~0.0.0" - -errno@^0.1.4: +errno@^0.1.3, errno@^0.1.4: version "0.1.6" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026" dependencies: @@ -983,8 +966,8 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -1001,8 +984,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.35" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" dependencies: es6-iterator "~2.0.1" es6-symbol "~3.1.1" @@ -1138,21 +1121,25 @@ eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + eslint@^4.13.1: - version "4.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.13.1.tgz#0055e0014464c7eb7878caf549ef2941992b444f" + version "4.14.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.14.0.tgz#96609768d1dd23304faba2d94b7fefe5a5447a82" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" chalk "^2.1.0" concat-stream "^1.6.0" cross-spawn "^5.1.0" - debug "^3.0.1" + debug "^3.1.0" doctrine "^2.0.2" eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" espree "^3.5.2" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" @@ -1204,7 +1191,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -1259,11 +1246,11 @@ extend@~3.0.0: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" external-editor@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc" + version "2.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" dependencies: + chardet "^0.4.0" iconv-lite "^0.4.17" - jschardet "^1.4.2" tmp "^0.0.33" extglob@^0.3.1: @@ -1272,10 +1259,14 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -1411,11 +1402,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" dependencies: nan "^2.3.0" - node-pre-gyp "^0.6.36" + node-pre-gyp "^0.6.39" fstream-ignore@^1.0.5: version "1.0.5" @@ -1615,9 +1606,9 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" @@ -1632,8 +1623,8 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" ignore@^3.3.3: - version "3.3.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" imurmurhash@^0.1.4: version "0.1.4" @@ -1659,8 +1650,8 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inquirer@^3.0.6: version "3.3.0" @@ -1682,8 +1673,8 @@ inquirer@^3.0.6: through "^2.3.6" interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" invariant@^2.2.2: version "2.2.2" @@ -1706,8 +1697,8 @@ is-binary-path@^1.0.0: binary-extensions "^1.0.0" is-buffer@^1.1.5, is-buffer@~1.1.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" @@ -1786,8 +1777,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -1810,10 +1801,8 @@ is-regex@^1.0.4: has "^1.0.1" is-resolvable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" - dependencies: - tryit "^1.0.1" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.1.tgz#acca1cd36dbe44b974b924321555a70ba03b1cf4" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" @@ -1867,10 +1856,6 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" -jschardet@^1.4.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -2007,10 +1992,10 @@ lru-cache@^4.0.1, lru-cache@^4.1.1: yallist "^2.1.2" make-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + version "1.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" dependencies: - pify "^2.3.0" + pify "^3.0.0" md5.js@^1.3.4: version "1.3.4" @@ -2166,8 +2151,8 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.3.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" natural-compare@^1.4.0: version "1.4.0" @@ -2181,37 +2166,38 @@ node-fetch@^1.0.1: is-stream "^1.0.1" node-libs-browser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" dependencies: assert "^1.1.1" - browserify-zlib "^0.1.4" + browserify-zlib "^0.2.0" buffer "^4.3.0" console-browserify "^1.1.0" constants-browserify "^1.0.0" crypto-browserify "^3.11.0" domain-browser "^1.1.1" events "^1.0.0" - https-browserify "0.0.1" - os-browserify "^0.2.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" path-browserify "0.0.0" - process "^0.11.0" + process "^0.11.10" punycode "^1.2.4" querystring-es3 "^0.2.0" - readable-stream "^2.0.5" + readable-stream "^2.3.3" stream-browserify "^2.0.1" - stream-http "^2.3.1" - string_decoder "^0.10.25" - timers-browserify "^2.0.2" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" tty-browserify "0.0.0" url "^0.11.0" util "^0.10.3" vm-browserify "0.0.4" -node-pre-gyp@^0.6.36: - version "0.6.38" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" dependencies: + detect-libc "^1.0.2" hawk "3.1.3" mkdirp "^0.5.1" nopt "^4.0.1" @@ -2306,9 +2292,9 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -os-browserify@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" os-homedir@^1.0.0: version "1.0.2" @@ -2347,9 +2333,9 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" -pako@~0.2.0: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" parallel-transform@^1.1.0: version "1.1.0" @@ -2434,10 +2420,14 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" -pify@^2.0.0, pify@^2.3.0: +pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -2480,7 +2470,7 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -process@^0.11.0: +process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" @@ -2506,10 +2496,6 @@ prop-types@^15.6.0: loose-envify "^1.3.1" object-assign "^4.1.1" -prr@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -2570,12 +2556,19 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" -randombytes@^2.0.0, randombytes@^2.0.1: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + rc@^1.1.7: version "1.2.2" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" @@ -2618,7 +2611,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -2640,8 +2633,8 @@ readdirp@^2.0.0: set-immediate-shim "^1.0.1" regenerator-runtime@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regex-cache@^0.4.2: version "0.4.4" @@ -2714,8 +2707,8 @@ resolve-from@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" @@ -2844,7 +2837,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: +source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -2904,7 +2897,7 @@ stream-each@^1.1.0: end-of-stream "^1.1.0" stream-shift "^1.0.0" -stream-http@^2.3.1: +stream-http@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" dependencies: @@ -2933,11 +2926,7 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^0.10.25: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.3: +string_decoder@^1.0.0, string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: @@ -3003,8 +2992,8 @@ tapable@^0.2.7: resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" tar-pack@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" dependencies: debug "^2.2.0" fstream "^1.0.10" @@ -3038,7 +3027,7 @@ through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" -timers-browserify@^2.0.2: +timers-browserify@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6" dependencies: @@ -3068,10 +3057,6 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tryit@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -3208,11 +3193,11 @@ watchpack@^1.4.0: graceful-fs "^4.1.2" webpack-sources@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf" + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" - source-map "~0.5.3" + source-map "~0.6.1" webpack@^3.10.0: version "3.10.0" From 03443a03f8799509b10bf3d0884a6f2524aa96b3 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 03:37:36 +0300 Subject: [PATCH 18/48] Added menuItem support + removed reconciler debug logs --- src/react-tvml/index.js | 44 ++++++++++++----------------------------- src/render.js | 34 ++++++++++++++++++------------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index bfecb46..f31c878 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -39,15 +39,12 @@ function createTextNode(text, rootContainerElement) { return textNode; } -function setInitialProperties(domElement, type, props, rootContainerElement) { - console.info( - 'setInitialProperties', - domElement, - type, - props, - rootContainerElement, - ); - +function setInitialProperties( + domElement, + type, + props, + // rootContainerElement, +) { Object .keys(props) .forEach((propName) => { @@ -132,35 +129,20 @@ function diffProperties( } }); - if (updatePayload) { - console.info( - 'diffProperties', - domElement, - type, - oldProps, - newProps, - updatePayload, - ); - } - return updatePayload; } -function updateProperties(domElement, updatePayload, type, oldProps, newProps) { +function updateProperties( + domElement, + updatePayload, + type, + oldProps, + newProps, +) { for (let i = 0; i < updatePayload.length; i += 2) { const propName = updatePayload[i]; const propValue = updatePayload[i + 1]; - console.info( - 'updateProperties', - domElement, - type, - propName, - propValue, - oldProps, - newProps, - ); - if (propName === CHILDREN) { if (type === 'style') { domElement.innerHTML = propValue; diff --git a/src/render.js b/src/render.js index 6079ef8..c7d18ae 100644 --- a/src/render.js +++ b/src/render.js @@ -56,28 +56,34 @@ export function render(Component) { } = payload; const { menuBar, menuItem } = navigation; + const isMenuDocument = menuBar && menuItem; + const menuItemDocument = isMenuDocument && menuBar.getDocument(menuItem); - console.info(1, menuBar, menuItem); + const element = React.createElement(Component, payload); let { document } = payload; - if (!document) { + if (document) { + /** + * If we received dismissed document it means that user pressed menu + * button and our pipeline is canceled. Now we must silently succeed + * the rest of the pipeline without rendering anything. + */ + if (document.possiblyDismissedByUser) return null; + } else if (menuItemDocument) { + document = menuItemDocument; + } else { document = createDocument(); document.route = route; } - /** - * If we received dismissed document it means that user pressed menu - * button and our pipeline is canceled. Now we must silently succeed - * the rest of the pipeline without rendering anything. - */ - if (document.possiblyDismissedByUser) return null; - - const element = React.createElement(Component, payload); - ReactTVML.render(element, document); - if (!document.isAttached) { + if (isMenuDocument) { + if (!menuItemDocument) { + menuBar.setDocument(document, menuItem); + } + } else if (!document.isAttached) { if (redirect) { const index = navigationDocument.documents.indexOf(document); const prevDocument = navigationDocument.documents[index - 1]; @@ -88,10 +94,10 @@ export function render(Component) { } else { navigationDocument.pushDocument(document); } - - document.isAttached = true; } + document.isAttached = true; + return { document, redirect: false, From 80ac18ed8a60b28a9351eecd0f5825247c4757bd Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 04:22:22 +0300 Subject: [PATCH 19/48] Fixed "menu-button-press" event --- src/index.js | 14 +++++--------- src/navigation/hooks.js | 1 + src/render.js | 32 ++++++++++++++++++++++---------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/index.js b/src/index.js index 5cbec7f..91b6107 100644 --- a/src/index.js +++ b/src/index.js @@ -14,14 +14,10 @@ subscribe('uncontrolled-document-pop').pipe(({ document }) => { prevRouteDocument, } = document; - const prevDocument = modal ? document : prevRouteDocument; - const { route: prevRoute } = prevDocument; - - let { modal: prevModal } = prevDocument; - - if (modal) { - prevModal = false; - } + const { + route: prevRoute, + modal: prevModal, + } = prevRouteDocument; broadcast('menu-button-press', { from: { @@ -31,7 +27,7 @@ subscribe('uncontrolled-document-pop').pipe(({ document }) => { }, to: { route: prevRoute, - document: prevDocument, + document: prevRouteDocument, modal: !!prevModal, }, }); diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index 08dce4f..afe3c57 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -13,6 +13,7 @@ function unmount(document) { */ document.possiblyDismissedByUser = true; ReactTVML.unmountComponentAtNode(document); + document.isAttached = false; } function handleUnload({ target: { ownerDocument: document } }) { diff --git a/src/render.js b/src/render.js index c7d18ae..51a870a 100644 --- a/src/render.js +++ b/src/render.js @@ -14,25 +14,31 @@ function createDocument() { return DOMImplementationRegistry.getDOMImplementation().createDocument(); } +export function dismissModal() { + return createPipeline() + .pipe(passthrough(() => { + if (!hasModal) return null; + hasModal = false; + navigationDocument.dismissModal(true); + return promisedTimeout(RENDERING_ANIMATION); + })); +} + export function removeModal() { - hasModal = false; - navigationDocument.dismissModal(true); + return dismissModal().sink(); } export function renderModal(Component) { return createPipeline() - .pipe(passthrough(() => { - if (!hasModal) return null; - removeModal(); - return promisedTimeout(RENDERING_ANIMATION); - })) + .pipe(dismissModal()) .pipe(passthrough((payload = {}) => { const { route } = payload; const document = createDocument(); - const lastDocument = navigationDocument.documents.pop() || {}; + const lastDocument = navigationDocument.documents.pop(); document.modal = true; - document.route = route || lastDocument.route; + document.prevRouteDocument = lastDocument; + document.route = `${route || (lastDocument || {}).route}-modal`; const element = React.createElement(Component, payload); @@ -74,7 +80,13 @@ export function render(Component) { document = menuItemDocument; } else { document = createDocument(); - document.route = route; + + document.route = route + || (!navigationDocument.documents.length && 'main'); + + document.prevRouteDocument = menuBar + ? menuBar.ownerDocument + : navigationDocument.documents.pop(); } ReactTVML.render(element, document); From 6e1caa949d6b96e258834afc5c5dc0b87a5b8a52 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 04:32:42 +0300 Subject: [PATCH 20/48] Changed renderModal behaviour + added dismissModal method --- src/render.js | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/render.js b/src/render.js index 51a870a..dd360bb 100644 --- a/src/render.js +++ b/src/render.js @@ -3,22 +3,29 @@ import React from 'react'; import ReactTVML from './react-tvml'; +import { subscribe } from './event-bus'; import { promisedTimeout } from './utils'; import { passthrough, createPipeline } from './pipelines'; const RENDERING_ANIMATION = 600; -let hasModal = false; +let modalDocument = null; function createDocument() { return DOMImplementationRegistry.getDOMImplementation().createDocument(); } +subscribe('uncontrolled-document-pop').pipe(({ document }) => { + if (document === modalDocument) { + modalDocument = null; + } +}); + export function dismissModal() { return createPipeline() .pipe(passthrough(() => { - if (!hasModal) return null; - hasModal = false; + if (!modalDocument) return null; + modalDocument = null; navigationDocument.dismissModal(true); return promisedTimeout(RENDERING_ANIMATION); })); @@ -30,25 +37,26 @@ export function removeModal() { export function renderModal(Component) { return createPipeline() - .pipe(dismissModal()) .pipe(passthrough((payload = {}) => { - const { route } = payload; - const document = createDocument(); - const lastDocument = navigationDocument.documents.pop(); + if (!modalDocument) { + const { route } = payload; + const document = createDocument(); + const lastDocument = navigationDocument.documents.pop(); - document.modal = true; - document.prevRouteDocument = lastDocument; - document.route = `${route || (lastDocument || {}).route}-modal`; + document.modal = true; + document.prevRouteDocument = lastDocument; + document.route = `${route || (lastDocument || {}).route}-modal`; - const element = React.createElement(Component, payload); + modalDocument = document; - ReactTVML.render(element, document); + navigationDocument.presentModal(document); - hasModal = true; + document.isAttached = true; + } - navigationDocument.presentModal(document); + const element = React.createElement(Component, payload); - document.isAttached = true; + ReactTVML.render(element, modalDocument); })); } From 32b33bb32acc05213e63af844a2fd5be33b3fc58 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 04:46:36 +0300 Subject: [PATCH 21/48] "uncontrolled-document-pop" -> "uncontrolled-document-dismiss" --- src/index.js | 2 +- src/navigation/hooks.js | 2 +- src/render.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 91b6107..9b2e6ca 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,7 @@ export * from './pipelines'; export * from './navigation'; export { default as ReactTVML } from './react-tvml'; -subscribe('uncontrolled-document-pop').pipe(({ document }) => { +subscribe('uncontrolled-document-dismiss').pipe((document) => { const { modal, route, diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index afe3c57..403cb21 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -18,7 +18,7 @@ function unmount(document) { function handleUnload({ target: { ownerDocument: document } }) { unmount(document); - broadcast('uncontrolled-document-pop', { document }); + broadcast('uncontrolled-document-dismiss', document); } const handlers = { diff --git a/src/render.js b/src/render.js index dd360bb..6825892 100644 --- a/src/render.js +++ b/src/render.js @@ -15,7 +15,7 @@ function createDocument() { return DOMImplementationRegistry.getDOMImplementation().createDocument(); } -subscribe('uncontrolled-document-pop').pipe(({ document }) => { +subscribe('uncontrolled-document-dismiss').pipe((document) => { if (document === modalDocument) { modalDocument = null; } From 7fc4baccfcfa20b40d38a3f2d077d853a099c736 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 04:48:55 +0300 Subject: [PATCH 22/48] Better event naming --- src/index.js | 2 +- src/navigation/hooks.js | 2 +- src/render.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 9b2e6ca..3515749 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,7 @@ export * from './pipelines'; export * from './navigation'; export { default as ReactTVML } from './react-tvml'; -subscribe('uncontrolled-document-dismiss').pipe((document) => { +subscribe('uncontrolled-document-dismissal').pipe((document) => { const { modal, route, diff --git a/src/navigation/hooks.js b/src/navigation/hooks.js index 403cb21..4113ad9 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.js @@ -18,7 +18,7 @@ function unmount(document) { function handleUnload({ target: { ownerDocument: document } }) { unmount(document); - broadcast('uncontrolled-document-dismiss', document); + broadcast('uncontrolled-document-dismissal', document); } const handlers = { diff --git a/src/render.js b/src/render.js index 6825892..4436d8b 100644 --- a/src/render.js +++ b/src/render.js @@ -15,7 +15,7 @@ function createDocument() { return DOMImplementationRegistry.getDOMImplementation().createDocument(); } -subscribe('uncontrolled-document-dismiss').pipe((document) => { +subscribe('uncontrolled-document-dismissal').pipe((document) => { if (document === modalDocument) { modalDocument = null; } From dcb5572b56f65136543d7bb57a724a3d9d0629f4 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 05:48:08 +0300 Subject: [PATCH 23/48] Readme updates --- README.md | 244 +++++++++++++++++------------------------------------- 1 file changed, 78 insertions(+), 166 deletions(-) diff --git a/README.md b/README.md index 4301ef8..66e5a9e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TVDML [![CircleCI](https://circleci.com/gh/a-ignatov-parc/tvdml.svg?style=svg)](https://circleci.com/gh/a-ignatov-parc/tvdml) - [Intro](#intro) -- [Requirements](#requirements) +- [System Requirements](#system-requirements) - [Getting started](#getting-started) - [Routing](#routing) - [Templating and styling](#templating-and-styling) @@ -35,29 +35,23 @@ ## Intro -This is library that main goal is to greatly simplify app development for Apple TV using pure Javascript and [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html) providing tools to solve problems like: +This is a library that main goal is to greatly simplify app development for Apple TV using [React.js](https://reactjs.org/) and providing tools to solve problems like: -- Routing -- Templating and updating data -- Event binding -- Detecting "Menu" button presses +- React.js integration with TVML and TVJS. +- Routing. +- Event binding. +- Detecting "Menu" button. -**What else is in the box?** - -TVDML tries to be as simple as possible and not include more than it needs to provide functionality for its core features. But yeah we've got something inside: - -- [`virtual-dom`](https://www.npmjs.com/package/virtual-dom) library to provide you easy to use update mechanism. [Patched](https://github.com/Matt-Esch/virtual-dom/compare/master...a-ignatov-parc:tvml) and ready to be used with TVML. - -## Requirements +## System Requirements Starting from `v4.X.X` TVDML drops support for tvOS < 10. If you need that support please consider using [`v3.X.X`](https://github.com/a-ignatov-parc/tvdml/tree/v3.0.4). ## Getting started -TVDML is shipping as [npm package](https://www.npmjs.com/package/tvdml) and can be installed with npm +TVDML is shipping as [npm package](https://www.npmjs.com/package/tvdml) and can be installed with npm. In addition you need to install React.js. ``` -npm install --save tvdml +npm install --save tvdml react ``` TVDML is written in ES6 and built using UMD wrapper so it can be used in any environment with any of this ways: @@ -95,13 +89,13 @@ App.onLaunch = function(options) { ], function(success) { if (success) { TVDML - .render(TVDML.jsx( + .render(React.createElement( 'document', null, - TVDML.jsx( + React.createElement( 'alertTemplate', null, - TVDML.jsx( + React.createElement( 'title', null, 'Hello world' @@ -117,8 +111,7 @@ App.onLaunch = function(options) { Doesn't look as nice as this ```javascript -/** @jsx TVDML.jsx */ - +import React from 'react'; import * as TVDML from 'tvdml'; TVDML @@ -134,11 +127,6 @@ TVDML So what we need to be able to write code as in second example? Well it's not that simple but this [tvdml-boilerplate](https://github.com/a-ignatov-parc/tvdml-app-boilerplate) repo will shed the light on basic build configuration. -Also to be able to properly transform JSX you need to specify JSX pragma for babel runtime. You can do this: - -1. By adding `/** @jsx TVDML.jsx */` in the beggining of each module. -1. Or by configuring `pragma` option in [`transform-react-jsx`](https://www.npmjs.com/package/babel-plugin-transform-react-jsx#pragma) plugin. - Well! Now we know how to write apps using ES6 and JSX so let's start from the basic features! ## Routing @@ -148,8 +136,7 @@ tvOS provided great foundation to write apps using [TVML](https://developer.appl To help you solving this issues TVDML provides navigation module. ```javascript -/** @jsx TVDML.jsx */ - +import React from 'react'; import * as TVDML from 'tvdml'; TVDML @@ -158,7 +145,7 @@ TVDML TVDML .handleRoute('start') - .pipe(TVDML.render( + .pipe(TVDML.render(() => ( This is initial view @@ -168,18 +155,18 @@ TVDML - )); + ))); TVDML .handleRoute('next') - .pipe(TVDML.render( + .pipe(TVDML.render(() => ( This is next view Now you know how to use routes! - )); + ))); ``` > This is small example of using navigation and rendering modules to handle routes and show them to user. @@ -258,186 +245,111 @@ Also there are some predefined routes that may help you: The next big thing is... -## Templating and styling +## Using React.js -Using TVDML you have multiple ways to create documents for TVML depending on your need. +With TVDML your main way to create documents will be React.js. -> Here is a [list of all possible documents](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/TextboxTemplate.html) you can use in TVML. +> Here is a [list of all available documents](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/TextboxTemplate.html) in TVML. -### Rendering static document +To render any react component you need to provide rendering factory to `TVDML.render` pipeline. -The simples way to create view: +Pipeline's payload will be passed as first argument to rendering factory so you'll be able to map it's props to rendering tree. ```javascript -/** @jsx TVDML.jsx */ - +import React from 'react'; import * as TVDML from 'tvdml'; TVDML .subscribe(TVDML.event.LAUNCH) - .pipe(() => TVDML.navigate('start')); - -TVDML - .handleRoute('start') - .pipe(TVDML.render( + .pipe(TVDML.render(payload => ( Hello world - - )); + ))); ``` -> TVDML works only with templates created using JSX. Please check how to configure your build to be able to use it in [Getting started](#getting-started) section. - -### Rendering custom data using factory approach +Here is how to render any component you like: ```javascript -/** @jsx TVDML.jsx */ - +import React from 'react'; +import PropTypes from 'prop-types'; import * as TVDML from 'tvdml'; -TVDML - .subscribe(TVDML.event.LAUNCH) - .pipe(() => { - TVDML.navigate('start', { title: 'Hello everybody!' }); // Passing params to route pipeline - }); - -TVDML - .handleRoute('start') - - // Extracting `title` param from `navigation` object. - .pipe(({ navigation: { title } }) => ({title})) - - // Rendering custom `title` - .pipe(TVDML.render(({ title }) => { - return ( - - - {title} - - - - ); - })); -``` - -Using this approach you can render any data that you need. But you may ask yourself how can we request data from remote server and then render it into document? - -Easy! - -### Requesting and rendering data +function Hello(props) { + return ( + + + Hello {props.name} + + + ); +} -TVDML's pipelines support promises so you can pause them when you need it. For example to retreive any data you need from remote server. +Hello.propTypes = { + name: PropTypes.string, +}; -```javascript -/** @jsx TVDML.jsx */ - -import * as TVDML from 'tvdml'; +Hello.defaultProps = { + name: 'world', +}; TVDML .subscribe(TVDML.event.LAUNCH) - .pipe(() => TVDML.navigate('start')); + .pipe(TVDML.render(payload => ( + + ))); +``` -TVDML - .handleRoute('start') - .pipe(downloadTVShows()) - .pipe(TVDML.render(tvshows => { - return ( - - - - TV Shows - - - - {tvshows.map(tvshow => { - return ( - - - {tvshow.title} - - ); - })} - - - - - ); - })); +It's just plain old React.js. -function downloadTVShows() { - return payload => { - // Creating and returning promise to pause current pipeline from executing next - // step until we load data. - return new Promise((resolve) => { - const XHR = new XMLHttpRequest(); +But there are some things you need to remember about TVML and React.js. - // Configuring XHR instance to load data that we need. - XHR.open('GET', '/tvshows/all'); +Because TVML and TVJS are not your normal browser they have some limitations. And to be able to work with them as best as possible react's tvml renderer have some quirks: - // Adding event listener to retreive data when it will be loaded. - XHR.addEventListener('load', event => { - // Parsing request response to JSON and resolving promise - resolve(JSON.parse(event.target.responseText)); - }); +1. `style` prop is just simple string not an object. +1. To set `class` attribute just use `class` prop. There is no `className`. +1. Events are normal DOM events provided by TVML. - // Initiating request. - XHR.send(); - }); - }; -} -``` +Everythin else should be as you expected. -Now lets figure out how can we react to user activity. +So lets talk about styling. -#### Important note +### Styling elements -It is important to remember that `TVDML.render()` uses `document` property in passed pipe's payload to update existing document. If there will be no `document` then new navigation record will be created. +There are two ways to style elements: -Explanation: +1. Using `style` prop. +1. Using ` + - Hello world - + Hello user + + Nice to see you + - )) - .pipe(payload => { - console.log(payload.document); // Updated document with "Hello world". - return payload; // As if this is the last pipe we don't need to return anything but it's a good practice to return current payload. - }); + ))); ``` +All available styles can be found here: [TVML Styles](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/ITMLStyles.html). + ### Events It's easy to bind event handlers using JSX. All you need to do is add one of the available handlers as attribute on controllable element. From 46b0b6421b75c32d661dbf90030033c609e7621f Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 05:54:31 +0300 Subject: [PATCH 24/48] Small updates to Readme --- README.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 66e5a9e..46fec1a 100644 --- a/README.md +++ b/README.md @@ -85,23 +85,26 @@ But you should agree that this... ```javascript App.onLaunch = function(options) { evaluateScripts([ - options.BASEURL + 'libs/tvdml.js' + options.BASEURL + 'libs/tvdml.js', + options.BASEURL + 'libs/react.js', ], function(success) { if (success) { TVDML - .render(React.createElement( - 'document', - null, - React.createElement( - 'alertTemplate', + .render(function(payload) { + return React.createElement( + 'document', null, React.createElement( - 'title', + 'alertTemplate', null, - 'Hello world' + React.createElement( + 'title', + null, + 'Hello world' + ) ) - ) - )) + ); + }) .sink(); } }); @@ -116,13 +119,13 @@ import * as TVDML from 'tvdml'; TVDML .subscribe(TVDML.event.LAUNCH) - .pipe(TVDML.render( + .pipe(TVDML.render(payload => ( Hello world - )); + ))); ``` So what we need to be able to write code as in second example? Well it's not that simple but this [tvdml-boilerplate](https://github.com/a-ignatov-parc/tvdml-app-boilerplate) repo will shed the light on basic build configuration. @@ -310,6 +313,7 @@ Because TVML and TVJS are not your normal browser they have some limitations. An 1. `style` prop is just simple string not an object. 1. To set `class` attribute just use `class` prop. There is no `className`. +1. Attribute names should be written in props as they written in [docs](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/TVJSAttributes.html). 1. Events are normal DOM events provided by TVML. Everythin else should be as you expected. From f3853952b0cfbb7ed546f391882ae29d8a9e73ef Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Sun, 24 Dec 2017 06:02:28 +0300 Subject: [PATCH 25/48] Readme updates --- README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 46fec1a..741384f 100644 --- a/README.md +++ b/README.md @@ -313,19 +313,19 @@ Because TVML and TVJS are not your normal browser they have some limitations. An 1. `style` prop is just simple string not an object. 1. To set `class` attribute just use `class` prop. There is no `className`. -1. Attribute names should be written in props as they written in [docs](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/TVJSAttributes.html). +1. Attribute names should be written in props as they are written in [docs](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/TVJSAttributes.html). 1. Events are normal DOM events provided by TVML. Everythin else should be as you expected. -So lets talk about styling. +Now lets talk about styling. ### Styling elements There are two ways to style elements: -1. Using `style` prop. -1. Using ` - Hello user - + Hello user + Nice to see you @@ -353,26 +352,9 @@ TVDML All available styles can be found here: [TVML Styles](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/ITMLStyles.html). -If you need to set multiple inline styles on one element you can use ES6 template literals (template strings) in JSX. - -```javascript - -``` - ### Events -It's easy to bind event handlers using JSX. All you need to do is add one of the available handlers as attribute on controllable element. +Here is everything as in React.js except that all events are native TVML events. List of controllable elements: @@ -398,11 +380,10 @@ List of available handlers: Modals are perfect when you need to show some useful information but don't want to interupt opened view context. You can use `TVDML.renderModal()` method to render any document you want in overlay. `TVDML.renderModal()` behaviour is similar to `TVDML.render()`. -There is also `TVDML.removeModal()` method that removes any presented modal document. +There is also `TVDML.removeModal()` method that removes any presented modal document. Or `TVDML.dismissModal()` to pipe modal dismissal with other operations. ```javascript -/** @jsx TVDML.jsx */ - +import React from 'react'; import * as TVDML from 'tvdml'; TVDML @@ -412,375 +393,44 @@ TVDML TVDML .handleRoute('start') .pipe(downloadTVShows()) - .pipe(TVDML.render(tvshows => { - return ( - - - - TV Shows - - - - {tvshows.map(tvshow => { - return ( - - - {tvshow.title} - - ); - })} - - - - - ); - })); + .pipe(TVDML.render(payload => ( + + + + TV Shows + + + + {payload.tvshows.map(tvshow => { + return ( + + + {tvshow.title} + + ); + })} + + + + + ))); function showTVShowDescription(tvshow) { - TVDML - - // Creating modal document rendering pipeline. - .renderModal( - - - {tvshow.title} - {tvshow.description} - - - ) - - // Invoking created pipeline. - .sink(); -} -``` - -### Working with rendered elements - -TVDML provides you with `ref` mechanism to help with access to rendered document nodes. This is useful when you need to get features of elements like: `textField`, `searchField` and `menuBar`. - -```javascript - - - { - console.log(node.getFeature('Keyboard').text); - }} /> - - -``` - -That was easy! Right? But how can we update views depending on user activity? - -That is a good question and that is where TVDML components comes to the rescue! - -### Creating interactive components - -I think at least someone has notised that some approaches used in TVDML are similar to those that used is react.js and you will be right! No! There is no react.js inside TVDML but it's hard to argue that its ideas are greatly fit to app development for Apple TV. React.js Components lifecycle are one of them. - -`TVDML.createComponent` tries to behave as much as posible as React.js component but with some limitations: - -1. There is no need for child components in TVDML so this feature isn't supported. But is a subject to change in future. -1. Rendering mechanism are different from ones used in react.js so interoperability with react components are not tested and most likely not possible. - -What is not supported (from [Component Specs and Lifecycle](https://facebook.github.io/react/docs/component-specs.html)): - -- `propTypes` -- `mixins` -- `statics` -- `displayName` - -Lets see how previous example will look like if it were written using TVDML components: - -```javascript -/** @jsx TVDML.jsx */ - -import * as TVDML from 'tvdml'; - -TVDML - .subscribe(TVDML.event.LAUNCH) - .pipe(() => TVDML.navigate('start')); - -TVDML - .handleRoute('start') - .pipe(downloadTVShows()) - .pipe(TVDML.render(TVDML.createComponent({ - render() { - return ( - - - - TV Shows - - - - {this.props.tvshows.map(tvshow => { - return ( - - - {tvshow.title} - - ); - })} - - - - - ); - }, - }))); -``` - -As you can see the main diference is that we need to specify `render` method and `tvshows` are now retrieved from `this.props` object. - -> The whole payload passed to `TVDML.render()` will be available as `this.props`. - -Now lets implement "Load more" button with pagination and spinner for initial loading. - -```javascript -/** @jsx TVDML.jsx */ - -import * as TVDML from 'tvdml'; - -TVDML - .subscribe(TVDML.event.LAUNCH) - .pipe(() => TVDML.navigate('start')); - -TVDML - .handleRoute('start') - .pipe(TVDML.render(TVDML.createComponent({ - getInitialState() { - return { - page: 1, - tvshows: [], - loading: true, - }; - }, - - componentDidMount() { - // Loading initial tv shows list when component is mounted - downloadTVShows(this.state.page).then(tvshows => { - this.setState({ - tvshows, - loading: false, - }); - }); - }, - - render() { - // Showing spinner while initial data is loading - if (this.state.loading) { - return ( - - - - - - ); - } - - return ( - - - - TV Shows - - - - {this.state.tvshows.map(tvshow => { - return ( - - - {tvshow.title} - - ); - })} - - - - - - - - ); - }, - - onLoadNextPage() { - const nextPage = this.state.page + 1; - - // Loading next page and merging new data with existing. - // Document update will be immediately invoked on state change. - downloadTVShows(nextPage).then(tvshows => { - this.setState({ - page: nextPage, - tvshows: this.state.tvshows.concat(tvshows), - }); - }); - }, - }))); -``` - -Looks nice! But what can we do with document parts that are need to be reused in other places? Please welcome partials! - -### Partials - -Partials are elements that can encapsulate complex markup and logic. They can be distinguished by names that starts with capital letters. - -```javascript -TVDML.createComponent({ - render() { - // Showing spinner while initial data is loading - if (this.state.loading) { - return ; - } - }, -}) -``` - -So how is `` looks from the inside. - -```javascript -function Loader({ attrs = {} }) { - const { title } = attrs; - - return ( + // Creating modal document rendering pipeline. + const pipeline = TVDML.renderModal(( - - - {title} - - + + {tvshow.title} + {tvshow.description} + - ); -} -``` - -Partials will receive `node` object in [UVDOM notation](https://github.com/gcanti/uvdom#uvdom-formal-type-definition) as first argument. - -`Loader` partial in our example will receive next object: + )); -```javascript -{ - tag: function Loader() {...}, - attrs: { - title: 'Loading...' - } + // Invoking created pipeline. + pipeline.sink(); } ``` -Full `node` specification: - -```javascript -{ - tag: string | function, - attrs: { - key: string, - ... - }, - events: { - eventName: function, - ... - }, - key: string, - ref: function, - children: string | node | array -} -``` - -The last thing that we need to cover is how to style elements. - -### Styling elements - -There is a big [section in TVML documentation](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/ITMLStyles.html) related to elements styling. And there are two ways you can attach styles to elements. - -#### Inline styles - -You can write styles directly on elements using `style` attribute. - -```javascript - - Hello world - -``` - -If you need to set multiple of styles on one element you can use ES6 template literals (template strings) in JSX. - -```javascript -{counter} -``` - -#### Document styles and class names - -If you have repeated styles or want to keep all styles in one place then you should use document styles. They are must be defined in ` - - Hello user - - Nice to see you - + Hello - ))); -``` - -All available styles can be found here: [TVML Styles](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/ITMLStyles.html). - -### Events - -Here is everything as in React.js except that all events are native TVML events. + )); -List of controllable elements: + pipeline.sink({ document }).then(() => { + player.interactiveOverlayDocument = document; + }); + ``` -- `button` -- `lockup` -- `listItemLockup` +1. Use TVML renderer directly -List of available handlers: + ```js + const document = TVDML.createEmptyDocument(); -- `onPlay` — Triggers when "Play" button is pressed. -- `onSelect` — Triggers when Touchpad is pressed. -- `onChange` — Triggers when element change its value. `` for example. -- `onHighlight` — Triggers when element becoming highlighted. -- `onHoldselect` — Triggers when Touchpad is pressed with a long press. - -```javascript - -``` + TVDML.ReactTVML.render(( + + + Hello + + + ), document, () => { + player.interactiveOverlayDocument = document; + }) + ``` ### Modals @@ -379,7 +357,7 @@ Modals are perfect when you need to show some useful information but don't want There is also `TVDML.removeModal()` method that removes any presented modal document. Or `TVDML.dismissModal()` to compose modal dismissal with other operations. -```javascript +```js import React from 'react'; import * as TVDML from 'tvdml'; @@ -434,7 +412,7 @@ One of the trickiest things in TVML is configure and use [menu bar](https://deve TVDML provides easy to use solution for this issue. -```javascript +```js import React from 'react'; import * as TVDML from 'tvdml'; @@ -482,6 +460,64 @@ Views switching will be handled by TVDML. All you have to do is to create `menuI > If you want to select specific menu item use `autoHighlight` attribute for this purpose. +### Styling elements + +There are two ways to style elements: + +1. Using `style` prop to write inline styles. `style` prop is key-value dictionary. Keys are style names written in camelCase. +1. Using ` + + + Hello user + + Nice to see you + + + + ))); +``` + +All available styles can be found here: [TVML Styles](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/ITMLStyles.html). + +### Events + +Here is everything as in React.js except that all events are native TVML events. + +List of controllable elements: + +- `button` +- `lockup` +- `listItemLockup` + +List of available handlers: + +- `onPlay` — Triggers when "Play" button is pressed. +- `onSelect` — Triggers when Touchpad is pressed. +- `onChange` — Triggers when element change its value. `` for example. +- `onHighlight` — Triggers when element becoming highlighted. +- `onHoldselect` — Triggers when Touchpad is pressed with a long press. + +```js + +``` + ### Working with `DataItem` In tvOS 11 [`DataItem`](https://developer.apple.com/documentation/tvmljs/dataitem) binding api was presented to fix performance issues with large documents that may ended up with very long parsing and rendering. @@ -492,7 +528,7 @@ So now you may wondering how we can use this cool feature in JSX? We got you covered! Here is an updated example from "[Requesting and rendering data](#requesting-and-rendering-data)" section: -```javascript +```js TVDML .handleRoute('start') .pipe(downloadTVShows()) @@ -532,7 +568,7 @@ TVDML The key difference from the example provided by Apple is `dataItem` attribute. It's responsible to apply `DataItems` to final document and this: -```javascript +```js
function parseJson(information) { @@ -578,7 +614,7 @@ function parseJson(information) { ### Complete rendering module api -- `TVDML.render(renderFactory)` — ... +- `TVDML.render(renderFactory)` — Main rendering pipeline for React.js components. Responsible for rendering new document to `navigationDocument` or update previously rendered documents passed through pipeline. - `TVDML.renderModal(renderFactory)` — ... @@ -589,6 +625,8 @@ function parseJson(information) { - `TVDML.ReactTVML.render(element, container, callback)` — ... - `TVDML.ReactTVML.unmountComponentAtNode(container)` — ... +- `TVDML.createEmptyDocument()` — ... + ## Pipelines and Streams To be able to easily manage your data flows TVDML provides two additional utils. They are **Streams** and **Pipelines**. They have similar api but a little different behaviours. All core functionality in TVDML is based upon them. @@ -597,7 +635,7 @@ To be able to easily manage your data flows TVDML provides two additional utils. Streams can be created using `TVDML.createStream()` factory and can be described as event bus with ability to combine transforms and create forks. Here is an example: -```javascript +```js const head = TVDML.createStream(); head.pipe(value => console.log(value)); @@ -608,7 +646,7 @@ head.sink(1); Console: -```javascript +```js 1 1 ``` @@ -617,7 +655,7 @@ This code will be resulted with two records in the console because we create two Every `pipe` creates another stream that can be used separately: -```javascript +```js const head = TVDML.createStream(); const tail = head.pipe(value => log(value + 1)); @@ -634,7 +672,7 @@ function log(value) { Console: -```javascript +```js 2 // ┬── 1 + 1 3 // │ ─── 1 * 3 6 // └── 2 * 3 @@ -646,7 +684,7 @@ As you can see `2` and `6` were produced by sinking `1` to `head` stream and `3` Streams can be combined: -```javascript +```js const head1 = TVDML.createStream(); const head2 = TVDML.createStream(); @@ -669,7 +707,7 @@ function log(value) { Console: -```javascript +```js 2 // ┬─┬ 1 + 1 5 // │ ├── 2 + 3 9 // │ └── 5 + 4 @@ -678,7 +716,7 @@ Console: Pipe transformations supports promised operations: -```javascript +```js const head = TVDML.createPipeline(); head @@ -698,7 +736,7 @@ function log(value) { Console: -```javascript +```js 2 // (100ms) 4 ``` @@ -715,7 +753,7 @@ Pipelines are streams too. But instead sinking values from the starting point of Let's compare with streams' first example: -```javascript +```js const head = TVDML.createPipeline(); head.pipe(value => console.log(value)); @@ -726,7 +764,7 @@ head Console: -```javascript +```js 1 ``` @@ -734,7 +772,7 @@ As we can see only sinked branch were exected. Let's compare other examples: -```javascript +```js const head = TVDML.createPipeline(); const tail = head.pipe(value => log(value + 1)); @@ -751,7 +789,7 @@ function log(value) { Console: -```javascript +```js 2 // ─── 1 + 1 2 // ┬── 1 + 1 6 // └── 2 * 3 @@ -759,7 +797,7 @@ Console: Combining pipelines: -```javascript +```js const head1 = TVDML.createPipeline(); const head2 = TVDML.createPipeline(); @@ -781,7 +819,7 @@ function log(value) { Console: -```javascript +```js 2 // ┬── 1 + 1 5 // ├── 2 + 3 9 // ├── 5 + 4 @@ -805,7 +843,7 @@ Console: tvOS and TVJS aren't providing any way to detect Menu button activity on Apple TV Remote (Siri Remote). To be able to detect when user returns from active screen to previous TVDML provides special event that describes activitiy that is posible only with press of the Menu button. -```javascript +```js TVDML .subscribe('menu-button-press') .pipe(transition => { @@ -815,7 +853,7 @@ TVDML With this snippet you can detect when user returned to specific screen and perform some activity like update results etc. -```javascript +```js TVDML .createPipeline() .pipe(TVDML.render(TVDML.createComponent({ diff --git a/src/render.js b/src/render.js index c5295dd..28bac17 100644 --- a/src/render.js +++ b/src/render.js @@ -9,16 +9,16 @@ const RENDERING_ANIMATION = 600; let modalDocument = null; -function createDocument() { - return DOMImplementationRegistry.getDOMImplementation().createDocument(); -} - subscribe('uncontrolled-document-dismissal').pipe((document) => { if (document === modalDocument) { modalDocument = null; } }); +export function createEmptyDocument() { + return DOMImplementationRegistry.getDOMImplementation().createDocument(); +} + export function dismissModal() { return createPipeline() .pipe(passthrough(() => { @@ -38,7 +38,7 @@ export function renderModal(renderFactory) { .pipe(passthrough((payload = {}) => { if (!modalDocument) { const { route } = payload; - const document = createDocument(); + const document = createEmptyDocument(); const lastDocument = navigationDocument.documents.pop(); document.modal = true; @@ -85,7 +85,7 @@ export function render(renderFactory) { } else if (menuItemDocument) { document = menuItemDocument; } else { - document = createDocument(); + document = createEmptyDocument(); document.route = route || (!navigationDocument.documents.length && 'main'); From ccf51ba2b529976992ce8e6e7197370533671941 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 17:26:02 +0300 Subject: [PATCH 36/48] Fixed readme examples --- README.md | 56 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 58b3ab6..77cff83 100644 --- a/README.md +++ b/README.md @@ -319,37 +319,37 @@ Everythin else should be as you expected. 1. Sink empty document to `TVDML.render()`: - ```js - const document = TVDML.createEmptyDocument(); - - const pipeline = TVDML.renderModal(() => ( - - - Hello - - - )); - - pipeline.sink({ document }).then(() => { - player.interactiveOverlayDocument = document; - }); - ``` + ```js + const document = TVDML.createEmptyDocument(); + + const pipeline = TVDML.renderModal(() => ( + + + Hello + + + )); + + pipeline.sink({ document }).then(() => { + player.interactiveOverlayDocument = document; + }); + ``` 1. Use TVML renderer directly - ```js - const document = TVDML.createEmptyDocument(); - - TVDML.ReactTVML.render(( - - - Hello - - - ), document, () => { - player.interactiveOverlayDocument = document; - }) - ``` + ```js + const document = TVDML.createEmptyDocument(); + + TVDML.ReactTVML.render(( + + + Hello + + + ), document, () => { + player.interactiveOverlayDocument = document; + }) + ``` ### Modals From 4b2e4e22ea5e9fd673ebefa9c80291e28ec4e57e Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 17:38:46 +0300 Subject: [PATCH 37/48] Added description for public rendering api --- README.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 77cff83..ed5d292 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ Because TVML and TVJS are not your normal browser they have some limitations. An Everythin else should be as you expected. -### Rendering to player documents +### Rendering to player's documents `player.overlayDocument` and `player.interactiveOverlayDocument` are not default targets for rendering components but there are two ways to do this: @@ -348,9 +348,13 @@ Everythin else should be as you expected. ), document, () => { player.interactiveOverlayDocument = document; - }) + }); ``` +Just don't forget to unmount components when you clear player's documents or you may face memory leaks and many other issues. + +You can unmount component by passing previously rendered document to `TVDML.ReactTVML.unmountComponentAtNode(document)`. + ### Modals Modals are perfect when you need to show some useful information but don't want to interupt opened view context. You can use `TVDML.renderModal()` method to render any document you want in overlay. `TVDML.renderModal()` behaviour is similar to `TVDML.render()`. @@ -616,16 +620,22 @@ function parseJson(information) { - `TVDML.render(renderFactory)` — Main rendering pipeline for React.js components. Responsible for rendering new document to `navigationDocument` or update previously rendered documents passed through pipeline. -- `TVDML.renderModal(renderFactory)` — ... +- `TVDML.renderModal(renderFactory)` — Same as `TVDML.render()` but for modals. -- `TVDML.dismissModal()` — ... +- `TVDML.dismissModal()` — Pipeline that removes active modal with ability to track progress. -- `TVDML.ReactTVML` — ... +- `TVDML.removeModal()` — Utility over `TVDML.dismissModal()`. Use it when you don't need to track modal dismissal and don't want to invoke pipeline manually. - - `TVDML.ReactTVML.render(element, container, callback)` — ... - - `TVDML.ReactTVML.unmountComponentAtNode(container)` — ... +- `TVDML.ReactTVML` — Publicly exposed React.js' reconciler for TVML. May be useful for advanced usage. It contains next methods: -- `TVDML.createEmptyDocument()` — ... + - `render(element, container, callback)` — Mount React.js element to container (usualy TVML document). + - `unmountComponentAtNode(container)` — Unmount active React.js components at container and clears markup. + +- `TVDML.createEmptyDocument()` — Method to create empty TVML document. May be useful when using `TVDML.ReactTVML` directly. It does same as: + + ```jsx + DOMImplementationRegistry.getDOMImplementation().createDocument(); + ``` ## Pipelines and Streams From 968e83f5181a539c54ff0688221c8069b8645af5 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 17:39:23 +0300 Subject: [PATCH 38/48] Updated readme TOC --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed5d292..cb1be6c 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ - [Getting started](#getting-started) - [Routing](#routing) - [Using React.js](#using-reactjs) - - [Styling elements](#styling-elements) - - [Events](#events) + - [Rendering to player's documents](#rendering-to-players-documents) - [Modals](#modals) - [Working with `menuBar`](#working-with-menubar) + - [Styling elements](#styling-elements) + - [Events](#events) - [Working with `DataItem`](#working-with-dataitem) - [Complete rendering module api](#complete-rendering-module-api) - [Pipelines and Streams](#pipelines-and-streams) From d78e898f7e810508a3a2ecd0a561882b876a6017 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 17:40:06 +0300 Subject: [PATCH 39/48] Better wording --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb1be6c..630c174 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - [Styling elements](#styling-elements) - [Events](#events) - [Working with `DataItem`](#working-with-dataitem) - - [Complete rendering module api](#complete-rendering-module-api) + - [Complete rendering api](#complete-rendering-api) - [Pipelines and Streams](#pipelines-and-streams) - [Streams](#streams) - [Streams' public api](#streams-public-api) @@ -617,7 +617,7 @@ function parseJson(information) { } ``` -### Complete rendering module api +### Complete rendering api - `TVDML.render(renderFactory)` — Main rendering pipeline for React.js components. Responsible for rendering new document to `navigationDocument` or update previously rendered documents passed through pipeline. From 45de6a85c7cbdd13cfda27151c42b490dbe75167 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 18:26:19 +0300 Subject: [PATCH 40/48] Fixed documents refs in "menu-button-press" event + updated readme --- README.md | 80 ++++++++++++++++++++++++++++++++++----------------- src/index.js | 14 ++++++++- src/render.js | 19 ++++++++++-- 3 files changed, 82 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 630c174..15e9a7d 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,7 @@ Everythin else should be as you expected. ```js const document = TVDML.createEmptyDocument(); - const pipeline = TVDML.renderModal(() => ( + const pipeline = TVDML.render(() => ( Hello @@ -397,7 +397,7 @@ TVDML function showTVShowDescription(tvshow) { // Creating modal document rendering pipeline. - const pipeline = TVDML.renderModal(( + const pipeline = TVDML.renderModal(() => ( {tvshow.title} @@ -411,6 +411,30 @@ function showTVShowDescription(tvshow) { } ``` +Every next invocation of `TVDML.renderModal()` will rerender active modal without closing it. + +If you need to close and then open modal again use `TVDML.dismissModal()` pipeline. + +```js +TVDML + .subscribe(TVDML.event.LAUNCH) + .pipe(TVDML.renderModal(() => ( + + + Modal #1 + + + ))) + .pipe(TVDML.dismissModal()) + .pipe(TVDML.renderModal(() => ( + + + Modal #2 + + + ))); +``` + ### Working with `menuBar` One of the trickiest things in TVML is configure and use [menu bar](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/MenuBarTemplate.html) across multiple views. @@ -865,38 +889,40 @@ TVDML With this snippet you can detect when user returned to specific screen and perform some activity like update results etc. ```js -TVDML - .createPipeline() - .pipe(TVDML.render(TVDML.createComponent({ - componentDidMount() { - const currentDocument = this._rootNode.ownerDocument; - - this.menuButtonPressStream = TVDML.subscribe('menu-button-press'); - this.menuButtonPressStream - .pipe(isMenuButtonPressNavigatedTo(currentDocument)) - .pipe(isNavigated => isNavigated && this.loadData().then(this.setState.bind(this))); - }, - - componentWillUnmount() { - this.menuButtonPressStream.unsubscribe(); - }, +function isMenuButtonPressNavigatedTo(targetDocument) { + return ({ to: { document } }) => targetDocument === document; +} - loadData() {...}, +class MyComponent extends React.PureComponent { + componentDidMount() { + const currentDocument = this.document.ownerDocument; - render() {...}, - }))); + this.menuButtonPressStream = TVDML.subscribe('menu-button-press'); + this.menuButtonPressStream + .pipe(isMenuButtonPressNavigatedTo(currentDocument)) + .pipe(isNavigated => isNavigated && this.loadData().then(this.setState.bind(this))); + } -function isMenuButtonPressNavigatedTo(targetDocument) { - return ({ to: { document } }) => { - const { menuBarDocument } = document; + componentWillUnmount() { + this.menuButtonPressStream.unsubscribe(); + } - if (menuBarDocument) { - document = menuBarDocument.getDocument(menuBarDocument.getSelectedItem()); - } + loadData() {...} - return targetDocument === document; + render() { + return ( + (this.document = node)}> + ... + + ); } } + +TVDML + .createPipeline() + .pipe(TVDML.render(() => ( + + ))); ``` ## Sample code diff --git a/src/index.js b/src/index.js index 3515749..c9f751b 100644 --- a/src/index.js +++ b/src/index.js @@ -11,9 +11,21 @@ subscribe('uncontrolled-document-dismissal').pipe((document) => { const { modal, route, - prevRouteDocument, } = document; + let { prevRouteDocument } = document; + + const prevDocumentElement = prevRouteDocument.documentElement; + const menuBar = prevDocumentElement + .getElementsByTagName('menuBar') + .item(0); + + if (menuBar) { + const menuBarDocument = menuBar.getFeature('MenuBarDocument'); + const menuItem = menuBarDocument.getSelectedItem(); + prevRouteDocument = menuBarDocument.getDocument(menuItem); + } + const { route: prevRoute, modal: prevModal, diff --git a/src/render.js b/src/render.js index 28bac17..8dbd547 100644 --- a/src/render.js +++ b/src/render.js @@ -39,11 +39,24 @@ export function renderModal(renderFactory) { if (!modalDocument) { const { route } = payload; const document = createEmptyDocument(); - const lastDocument = navigationDocument.documents.pop(); + const prevRouteDocument = navigationDocument.documents.pop(); + + let prevRouteDocumentRoute = prevRouteDocument.route; + + const prevDocumentElement = prevRouteDocument.documentElement; + const menuBar = prevDocumentElement + .getElementsByTagName('menuBar') + .item(0); + + if (menuBar) { + const menuBarDocument = menuBar.getFeature('MenuBarDocument'); + const menuItem = menuBarDocument.getSelectedItem(); + prevRouteDocumentRoute = menuBarDocument.getDocument(menuItem).route; + } document.modal = true; - document.prevRouteDocument = lastDocument; - document.route = `${route || (lastDocument || {}).route}-modal`; + document.prevRouteDocument = prevRouteDocument; + document.route = `${route || prevRouteDocumentRoute}-modal`; modalDocument = document; From 2602069b1dd88b46748904c37ee546d8108866c2 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 18:38:47 +0300 Subject: [PATCH 41/48] Small code refactoring --- .eslintrc | 2 +- src/pipelines/stream.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.eslintrc b/.eslintrc index 71dd197..cb43192 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,7 +9,7 @@ "props": false }], "no-underscore-dangle": ["error", { - "allow": ["_internalRoot", "_reactRootContainer"] + "allow": ["_sink", "_internalRoot", "_reactRootContainer"] }], "no-prototype-builtins": "off" }, diff --git a/src/pipelines/stream.js b/src/pipelines/stream.js index 3892e05..9edf104 100644 --- a/src/pipelines/stream.js +++ b/src/pipelines/stream.js @@ -1,5 +1,3 @@ -/* eslint-disable no-underscore-dangle */ - export default class Stream { constructor(options = {}) { Object.assign(this, options.extend); From 298be387fa3489a536e2c13e4c0949ecbb2d6ec9 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 19:18:39 +0300 Subject: [PATCH 42/48] Added migration guide + update highlights --- README.md | 20 +++++++++++++++++++- docs/MIGRATION_5.md | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 docs/MIGRATION_5.md diff --git a/README.md b/README.md index 15e9a7d..af2e679 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,24 @@ +## New! + +This is the new version of tvdml, `6.X`. + +### Update highlights + +- Switched old renderer to React.js (**Breaking**). +- Unified different ways to create TVML documents (**Breaking**). +- Simpler syntax to create stylesheets using ` + + + ... + + +``` + +It's important to note that inline styles are must be defined as object with props named written in camelCase as keys. + +[This styles](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#inline-styles) + +```js + + Hello world + +``` + +Transforms to: + +```js + + Hello world + +``` + +## New `TVDML.renderModal()` rerendering behavour + +Every next invocation of `TVDML.renderModal()` will rerender active modal without closing it. + +Please check `TVDML.dismissModal()` if you need old behavour. From aef252285f75e16477906631f34800f687b38778 Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Mon, 25 Dec 2017 19:46:50 +0300 Subject: [PATCH 45/48] Small updates to migration guide --- docs/MIGRATION_5.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/MIGRATION_5.md b/docs/MIGRATION_5.md index d77215f..cd98b01 100644 --- a/docs/MIGRATION_5.md +++ b/docs/MIGRATION_5.md @@ -4,7 +4,7 @@ Now every document must be React.js component. And here is how you can migrate your old components -[Rendering static document](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#rendering-static-document) translates to +[Static documents](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#rendering-static-document) translates to: ```js TVDML @@ -23,7 +23,7 @@ TVDML [Rendering document with render factory](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#rendering-custom-data-using-factory-approach) stays exactly the same. -To migrate your [interactive components](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#creating-interactive-components) use [`create-react-class`](https://www.npmjs.com/package/create-react-class) module to transform old code to React.js components. Or update your old components to React.js ES6 syntax with [this guide](https://reactjs.org/docs/react-without-es6.html) +To migrate your [interactive components](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#creating-interactive-components) use [`create-react-class`](https://www.npmjs.com/package/create-react-class) module to transform old code to React.js components. Or update your old components to React.js ES6 syntax with [this guide](https://reactjs.org/docs/react-without-es6.html). Updated example from "Load more" implementation @@ -152,7 +152,7 @@ Goes to: It's important to note that inline styles are must be defined as object with props named written in camelCase as keys. -[This styles](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#inline-styles) +[This styles](https://github.com/a-ignatov-parc/tvdml/tree/v5.1.1#inline-styles): ```js @@ -175,4 +175,4 @@ Transforms to: Every next invocation of `TVDML.renderModal()` will rerender active modal without closing it. -Please check `TVDML.dismissModal()` if you need old behavour. +Please check `TVDML.dismissModal()` if you need to keep old behavour. From 11ea64bd5ee60b113a27c4bdf7c1d6299d76fb10 Mon Sep 17 00:00:00 2001 From: Anton Ignatov <abietis@gmail.com> Date: Mon, 25 Dec 2017 20:23:31 +0300 Subject: [PATCH 46/48] Added DataItem support with updated example in Readme --- README.md | 46 ++++++++++++++++++++++++++++------------- src/react-tvml/index.js | 33 ++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 92554d1..0303b58 100644 --- a/README.md +++ b/README.md @@ -579,37 +579,55 @@ So now you may wondering how we can use this cool feature in JSX? We got you covered! Here is an updated example from "[Requesting and rendering data](#requesting-and-rendering-data)" section: ```js +const tvshows = [ + { + title: 'Arrow, Season 1', + url: 'http://is2.mzstatic.com/image/thumb/Music6/v4/e9/bb/9b/e9bb9bbb-16c0-d946-063d-15632dd78a76/source/600x600bb.jpg', + }, + { + title: 'Arrow, Season 2', + url: 'http://is1.mzstatic.com/image/thumb/Music3/v4/bb/87/84/bb8784ca-7e31-0cc1-b56d-9243624863d3/source/600x600bb.jpg', + }, + { + title: 'Arrow, Season 3', + url: 'http://is2.mzstatic.com/image/thumb/Video62/v4/ec/ca/78/ecca78a3-5bb0-0b32-954c-f7fd966582ab/source/600x600bb.jpg', + }, +]; + TVDML .handleRoute('start') - .pipe(downloadTVShows()) - .pipe(TVDML.render(payload => ( + .pipe(TVDML.render(() => ( <document> <stackTemplate> <banner> <title>TV Shows - + - - + <img + binding="@src:{url};" + width="300" + height="300" + /> + <title binding="textContent:{title};" /> </lockup> </prototypes> <section - binding="items:{tvshows}" + binding="items:{tvshows};" dataItem={{ - tvshows: tvshows.map(tvshow => { - const item = new DataItem('tvshow', tvshow.id); + tvshows: mockData.map((cover, i) => { + const item = new DataItem('tvshow', i); - item.cover = tvshow.cover; - item.title = tvshow.title; + item.url = cover.url; + item.title = cover.title; return item; }), }} /> - </grid> + </shelf> </collectionList> </stackTemplate> </document> @@ -623,10 +641,10 @@ The key difference from the example provided by Apple is `dataItem` attribute. I binding="items:{tvshows}" dataItem={{ tvshows: tvshows.map(tvshow => { - const item = new DataItem('tvshow', tvshow.id); + const item = new DataItem('tvshow', i); - item.cover = tvshow.cover; - item.title = tvshow.title; + item.url = cover.url; + item.title = cover.title; return item; }), diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index 798d6c1..d70b873 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -1,3 +1,5 @@ +/* global DataItem */ + import ReactFiberReconciler from 'react-reconciler'; import { broadcast } from '../event-bus'; @@ -12,6 +14,7 @@ const NAMESPACE = 'http://www.w3.org/1999/xhtml'; const STYLE = 'style'; const CHILDREN = 'children'; +const DATAITEM = 'dataItem'; /** * This props has special behaviour. @@ -105,6 +108,17 @@ function setInitialProperties( } else if (typeof propValue === 'number') { domElement.textContent = `${propValue}`; } + } else if (propName === DATAITEM) { + if (propValue instanceof DataItem) { + domElement.dataItem = propValue; + } else if (propValue) { + domElement.dataItem = new DataItem(); + Object + .keys(propValue) + .forEach((key) => { + domElement.dataItem.setPropertyPath(key, propValue[key]); + }); + } } else if (booleanAttributes.includes(propName)) { if (propValue) { domElement.setAttribute(propName, true); @@ -181,6 +195,10 @@ function diffProperties( if (shouldUpdate) { (updatePayload = updatePayload || []).push(propName, `${propValue}`); } + } else if (propName === DATAITEM) { + if (oldPropValue !== propValue) { + (updatePayload = updatePayload || []).push(propName, propValue); + } } else if (booleanAttributes.includes(propName)) { const oldBoolValue = !!oldPropValue; const boolValue = !!propValue; @@ -220,6 +238,19 @@ function updateProperties( } else { domElement.textContent = propValue; } + } else if (propName === DATAITEM) { + if (propValue == null) { + delete domElement.dataItem; + } else if (propValue instanceof DataItem) { + domElement.dataItem = propValue; + } else { + domElement.dataItem = new DataItem(); + Object + .keys(propValue) + .forEach((key) => { + domElement.dataItem.setPropertyPath(key, propValue[key]); + }); + } } else if (booleanAttributes.includes(propName)) { if (propValue) { domElement.setAttribute(propName, true); @@ -238,7 +269,7 @@ function updateProperties( domElement.addEventListener(eventName, propValue); } } - } else if (propValue === null || typeof propValue === 'undefined') { + } else if (propValue == null) { domElement.removeAttribute(propName); } else { let attrValue = propValue; From 8bd92f172ad679dcc77d9dc3859a8c3b01c814db Mon Sep 17 00:00:00 2001 From: Anton Ignatov <abietis@gmail.com> Date: Tue, 26 Dec 2017 10:16:36 +0300 Subject: [PATCH 47/48] Added onNeedsmore event support --- README.md | 1 + src/react-tvml/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 0303b58..502b4e6 100644 --- a/README.md +++ b/README.md @@ -561,6 +561,7 @@ List of available handlers: - `onChange` — Triggers when element change its value. `<ratingBadge />` for example. - `onHighlight` — Triggers when element becoming highlighted. - `onHoldselect` — Triggers when Touchpad is pressed with a long press. +- `onNeedsmore` — Triggers when user approaches end of the list by scrolling. ```js <button onSelect={event => console.log(event.target)}> diff --git a/src/react-tvml/index.js b/src/react-tvml/index.js index d70b873..d90954f 100644 --- a/src/react-tvml/index.js +++ b/src/react-tvml/index.js @@ -48,6 +48,7 @@ const supportedEventMapping = { onSelect: 'select', onChange: 'change', onHighlight: 'highlight', + onNeedsmore: 'needsmore', onHoldselect: 'holdselect', }; From 6004e372d11aedf459f3afb5303520ba96694a41 Mon Sep 17 00:00:00 2001 From: Anton Ignatov <abietis@gmail.com> Date: Tue, 26 Dec 2017 10:26:23 +0300 Subject: [PATCH 48/48] Added event listener in dataItem example --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 502b4e6..f99c068 100644 --- a/README.md +++ b/README.md @@ -617,6 +617,7 @@ TVDML </prototypes> <section binding="items:{tvshows};" + onSelect={event => console.log(event.target.dataItem)} dataItem={{ tvshows: mockData.map((cover, i) => { const item = new DataItem('tvshow', i);