From cfb66fc9ae68a25f669ac682a09125553e916026 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 04:01:30 +0200 Subject: [PATCH 01/34] vendor: upgrade to Ember 3.8.3 --- package.json | 2 +- yarn.lock | 1233 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 1174 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index 43c88e8e02..cb55f70fe7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "bootstrap": "3.3.1", - "ember-source": "3.7.1", + "ember-source": "3.8.3", "ember-data": "3.9.0", "ember-data-model-fragments": "4.0.0", "ember-fetch": "6.5.0", diff --git a/yarn.lock b/yarn.lock index 3bf8184dbf..c5d480775e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,6 +9,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -16,6 +23,15 @@ dependencies: "@babel/highlight" "^7.8.3" +"@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" + integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== + dependencies: + browserslist "^4.12.0" + invariant "^2.2.4" + semver "^5.5.0" + "@babel/core@7.2.2", "@babel/core@^7.0.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" @@ -36,6 +52,28 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.11.0": + version "7.11.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643" + integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.11.0" + "@babel/helper-module-transforms" "^7.11.0" + "@babel/helpers" "^7.10.4" + "@babel/parser" "^7.11.1" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.11.0" + "@babel/types" "^7.11.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@^7.3.3", "@babel/core@^7.3.4": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.3.tgz#198d6d3af4567be3989550d97e068de94503074f" @@ -88,6 +126,15 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" + integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== + dependencies: + "@babel/types" "^7.11.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/generator@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" @@ -127,6 +174,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" @@ -135,6 +189,14 @@ "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-call-delegate@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" @@ -144,6 +206,29 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-compilation-targets@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" + integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== + dependencies: + "@babel/compat-data" "^7.10.4" + browserslist "^4.12.0" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.10.4", "@babel/helper-create-class-features-plugin@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" + integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.10.5" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/helper-create-class-features-plugin@^7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz#2b01a81b3adc2b1287f9ee193688ef8dc71e718f" @@ -167,6 +252,15 @@ "@babel/helper-replace-supers" "^7.4.0" "@babel/helper-split-export-declaration" "^7.4.0" +"@babel/helper-create-regexp-features-plugin@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" + integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + regexpu-core "^4.7.0" + "@babel/helper-define-map@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" @@ -176,6 +270,15 @@ "@babel/types" "^7.0.0" lodash "^4.17.10" +"@babel/helper-define-map@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" @@ -184,6 +287,14 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c" + integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A== + dependencies: + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" @@ -193,6 +304,15 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-function-name@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" @@ -209,6 +329,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-get-function-arity@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" @@ -223,6 +350,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-hoist-variables@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" @@ -230,6 +364,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" + integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== + dependencies: + "@babel/types" "^7.11.0" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -237,6 +378,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-module-imports@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-module-transforms@^7.1.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" @@ -249,6 +397,19 @@ "@babel/types" "^7.2.2" lodash "^4.17.10" +"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" + integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/template" "^7.10.4" + "@babel/types" "^7.11.0" + lodash "^4.17.19" + "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" @@ -256,11 +417,23 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== +"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + "@babel/helper-regex@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" @@ -268,6 +441,13 @@ dependencies: lodash "^4.17.10" +"@babel/helper-regex@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== + dependencies: + lodash "^4.17.19" + "@babel/helper-remap-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" @@ -279,6 +459,17 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-remap-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5" + integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.2.3": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" @@ -289,6 +480,16 @@ "@babel/traverse" "^7.2.3" "@babel/types" "^7.0.0" +"@babel/helper-replace-supers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" + integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-replace-supers@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.0.tgz#4f56adb6aedcd449d2da9399c2dcf0545463b64c" @@ -307,6 +508,21 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-simple-access@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" + integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== + dependencies: + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" + integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== + dependencies: + "@babel/types" "^7.11.0" + "@babel/helper-split-export-declaration@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" @@ -314,6 +530,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + "@babel/helper-split-export-declaration@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz#571bfd52701f492920d63b7f735030e9a3e10b55" @@ -328,6 +551,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -338,6 +566,25 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" +"@babel/helper-wrap-function@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" + integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helpers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" + integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helpers@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21" @@ -374,6 +621,15 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/highlight@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" @@ -388,6 +644,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.2.tgz#85c5c47af6d244fab77bce6b9bd830e38c978409" integrity sha512-x5HFsW+E/nQalGMw7hu+fvPqnBeBaIr0lWJ2SG0PPL2j+Pm9lYvCrsZJGIgauPIENx0v10INIyFjmSNUD/gSqQ== +"@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.2.tgz#0882ab8a455df3065ea2dcb4c753b2460a24bead" + integrity sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw== + "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" @@ -403,6 +664,15 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== +"@babel/plugin-proposal-async-generator-functions@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" + integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -428,6 +698,14 @@ "@babel/helper-create-class-features-plugin" "^7.4.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-proposal-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-decorators@7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.3.0.tgz#637ba075fa780b1f75d08186e8fb4357d03a72a7" @@ -437,6 +715,15 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators" "^7.2.0" +"@babel/plugin-proposal-decorators@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4" + integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.10.4" + "@babel/plugin-proposal-decorators@^7.3.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.0.tgz#8e1bfd83efa54a5f662033afcc2b8e701f4bb3a9" @@ -446,6 +733,30 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators" "^7.2.0" +"@babel/plugin-proposal-dynamic-import@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" + integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-export-namespace-from@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" + integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" + integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-proposal-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" @@ -454,6 +765,39 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" +"@babel/plugin-proposal-logical-assignment-operators@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" + integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" + integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" + integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" + integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.2.0.tgz#88f5fec3e7ad019014c97f7ee3c992f0adbf7fb8" @@ -462,6 +806,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" +"@babel/plugin-proposal-optional-catch-binding@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" + integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-proposal-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" @@ -470,6 +822,31 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" +"@babel/plugin-proposal-optional-chaining@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" + integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-private-methods@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" + integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" + integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz#abe7281fe46c95ddc143a65e5358647792039520" @@ -486,6 +863,27 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" + integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-decorators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c" + integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz#c50b1b957dcc69e4b1127b65e1c33eef61570c1b" @@ -493,6 +891,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" @@ -500,6 +912,34 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" @@ -507,6 +947,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" @@ -514,6 +961,34 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" + integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-typescript@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz#2f55e770d3501e83af217d782cb7517d7bb34d25" + integrity sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-typescript@^7.2.0": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" @@ -521,6 +996,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-arrow-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" + integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" @@ -528,6 +1010,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" + integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" + "@babel/plugin-transform-async-to-generator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" @@ -537,6 +1028,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" +"@babel/plugin-transform-block-scoped-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" + integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" @@ -552,6 +1050,27 @@ "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.10" +"@babel/plugin-transform-block-scoping@^7.10.4": + version "7.11.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" + integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-classes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" + integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + globals "^11.1.0" + "@babel/plugin-transform-classes@^7.2.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz#6c90542f210ee975aa2aa8c8b5af7fa73a126953" @@ -566,6 +1085,13 @@ "@babel/helper-split-export-declaration" "^7.0.0" globals "^11.1.0" +"@babel/plugin-transform-computed-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" + integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-computed-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" @@ -573,6 +1099,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-destructuring@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" + integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-destructuring@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz#e75269b4b7889ec3a332cd0d0c8cff8fed0dc6f3" @@ -580,6 +1113,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" + integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-dotall-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49" @@ -589,6 +1130,13 @@ "@babel/helper-regex" "^7.0.0" regexpu-core "^4.1.3" +"@babel/plugin-transform-duplicate-keys@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" + integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-duplicate-keys@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3" @@ -596,6 +1144,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-exponentiation-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" + integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" @@ -604,6 +1160,13 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-for-of@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" + integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-for-of@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz#ab7468befa80f764bb03d3cb5eef8cc998e1cad9" @@ -611,6 +1174,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" + integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-function-name@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz#f7930362829ff99a3174c39f0afcc024ef59731a" @@ -619,6 +1190,13 @@ "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" + integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" @@ -626,6 +1204,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-member-expression-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" + integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6" @@ -634,6 +1219,15 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-modules-amd@^7.10.4", "@babel/plugin-transform-modules-amd@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" + integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== + dependencies: + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-commonjs@7.2.0", "@babel/plugin-transform-modules-commonjs@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404" @@ -643,6 +1237,26 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" +"@babel/plugin-transform-modules-commonjs@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" + integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== + dependencies: + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" + integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== + dependencies: + "@babel/helper-hoist-variables" "^7.10.4" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-systemjs@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068" @@ -651,6 +1265,14 @@ "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-modules-umd@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" + integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== + dependencies: + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-modules-umd@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" @@ -659,6 +1281,13 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" + integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/plugin-transform-new-target@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" @@ -666,6 +1295,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-new-target@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" + integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-object-super@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" + integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/plugin-transform-object-super@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" @@ -674,6 +1318,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" +"@babel/plugin-transform-parameters@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" + integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-parameters@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.2.0.tgz#0d5ad15dc805e2ea866df4dd6682bfe76d1408c2" @@ -683,6 +1335,13 @@ "@babel/helper-get-function-arity" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-property-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" + integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-regenerator@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" @@ -690,6 +1349,30 @@ dependencies: regenerator-transform "^0.13.3" +"@babel/plugin-transform-regenerator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" + integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" + integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-runtime@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz#e27f78eb36f19448636e05c33c90fd9ad9b8bccf" + integrity sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-runtime@^7.2.0": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz#4d6691690ecdc9f5cb8c3ab170a1576c1f556371" @@ -700,6 +1383,13 @@ resolve "^1.8.1" semver "^5.5.1" +"@babel/plugin-transform-shorthand-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" + integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -707,6 +1397,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-spread@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" + integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" + "@babel/plugin-transform-spread@^7.2.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" @@ -714,6 +1412,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-sticky-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" + integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" @@ -722,6 +1428,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" +"@babel/plugin-transform-template-literals@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" + integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-template-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" @@ -730,6 +1444,13 @@ "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-typeof-symbol@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" + integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-typeof-symbol@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" @@ -745,6 +1466,30 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript" "^7.2.0" +"@babel/plugin-transform-typescript@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz#2b4879676af37342ebb278216dd090ac67f13abb" + integrity sha512-edJsNzTtvb3MaXQwj8403B7mZoGu9ElDJQZOKjGUnvilquxBA3IQoEIOvkX/1O8xfAsnHS/oQhe2w/IXrr+w0w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-typescript" "^7.10.4" + +"@babel/plugin-transform-unicode-escapes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" + integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-unicode-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" + integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-unicode-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b" @@ -762,6 +1507,14 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" +"@babel/polyfill@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.10.4.tgz#915e5bfe61490ac0199008e35ca9d7d151a8e45a" + integrity sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + "@babel/preset-env@^7.0.0": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.2.3.tgz#948c8df4d4609c99c7e0130169f052ea6a7a8933" @@ -809,6 +1562,98 @@ js-levenshtein "^1.1.3" semver "^5.3.0" +"@babel/preset-env@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796" + integrity sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg== + dependencies: + "@babel/compat-data" "^7.11.0" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-async-generator-functions" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-dynamic-import" "^7.10.4" + "@babel/plugin-proposal-export-namespace-from" "^7.10.4" + "@babel/plugin-proposal-json-strings" "^7.10.4" + "@babel/plugin-proposal-logical-assignment-operators" "^7.11.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" + "@babel/plugin-proposal-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread" "^7.11.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" + "@babel/plugin-proposal-optional-chaining" "^7.11.0" + "@babel/plugin-proposal-private-methods" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.10.4" + "@babel/plugin-transform-arrow-functions" "^7.10.4" + "@babel/plugin-transform-async-to-generator" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions" "^7.10.4" + "@babel/plugin-transform-block-scoping" "^7.10.4" + "@babel/plugin-transform-classes" "^7.10.4" + "@babel/plugin-transform-computed-properties" "^7.10.4" + "@babel/plugin-transform-destructuring" "^7.10.4" + "@babel/plugin-transform-dotall-regex" "^7.10.4" + "@babel/plugin-transform-duplicate-keys" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator" "^7.10.4" + "@babel/plugin-transform-for-of" "^7.10.4" + "@babel/plugin-transform-function-name" "^7.10.4" + "@babel/plugin-transform-literals" "^7.10.4" + "@babel/plugin-transform-member-expression-literals" "^7.10.4" + "@babel/plugin-transform-modules-amd" "^7.10.4" + "@babel/plugin-transform-modules-commonjs" "^7.10.4" + "@babel/plugin-transform-modules-systemjs" "^7.10.4" + "@babel/plugin-transform-modules-umd" "^7.10.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" + "@babel/plugin-transform-new-target" "^7.10.4" + "@babel/plugin-transform-object-super" "^7.10.4" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-transform-property-literals" "^7.10.4" + "@babel/plugin-transform-regenerator" "^7.10.4" + "@babel/plugin-transform-reserved-words" "^7.10.4" + "@babel/plugin-transform-shorthand-properties" "^7.10.4" + "@babel/plugin-transform-spread" "^7.11.0" + "@babel/plugin-transform-sticky-regex" "^7.10.4" + "@babel/plugin-transform-template-literals" "^7.10.4" + "@babel/plugin-transform-typeof-symbol" "^7.10.4" + "@babel/plugin-transform-unicode-escapes" "^7.10.4" + "@babel/plugin-transform-unicode-regex" "^7.10.4" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.11.0" + browserslist "^4.12.0" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.11.0", "@babel/runtime@^7.8.4": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.2.0": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc" @@ -834,6 +1679,15 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" +"@babel/template@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/template@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" @@ -882,6 +1736,21 @@ globals "^11.1.0" lodash "^4.17.10" +"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" + integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.11.0" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.11.0" + "@babel/types" "^7.11.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" @@ -930,6 +1799,15 @@ lodash "^4.17.10" to-fast-properties "^2.0.0" +"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.4.4": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" + integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@babel/types@^7.2.0", "@babel/types@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" @@ -957,6 +1835,11 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@ember-data/rfc395-data@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@ember-data/rfc395-data/-/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843" + integrity sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ== + "@ember-decorators/argument@0.8.21": version "0.8.21" resolved "https://registry.yarnpkg.com/@ember-decorators/argument/-/argument-0.8.21.tgz#929789f9622ee935c3fad3332b3d179e98d05b15" @@ -1110,12 +1993,27 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/fs-extra@^5.0.5": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.1.0.tgz#2a325ef97901504a3828718c390d34b8426a10a1" + integrity sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ== + dependencies: + "@types/node" "*" + +"@types/glob@*": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" + integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/html-minifier-terser@^5.0.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== -"@types/minimatch@^3.0.3": +"@types/minimatch@*", "@types/minimatch@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== @@ -1135,6 +2033,14 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/rimraf@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.4.tgz#403887b0b53c6100a6c35d2ab24f6ccc042fec46" + integrity sha512-8gBudvllD2A/c0CcEX/BivIDorHFt5UI5m46TsNj8DjWCCTTZT74kEe4g+QsY7P/B9WdO98d82zZgXO/RQzu2Q== + dependencies: + "@types/glob" "*" + "@types/node" "*" + "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" @@ -1960,6 +2866,27 @@ babel-plugin-debug-macros@^0.3.0: dependencies: semver "^5.3.0" +babel-plugin-debug-macros@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.3.3.tgz#29c3449d663f61c7385f5b8c72d8015b069a5cb7" + integrity sha512-E+NI8TKpxJDBbVkdWkwHrKgJi696mnRL8XYrOPYw82veNHPDORM9WIQifl6TpIo8PNy2tU2skPqbfkmHXrHKQA== + dependencies: + semver "^5.3.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-ember-data-packages-polyfill@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-data-packages-polyfill/-/babel-plugin-ember-data-packages-polyfill-0.1.2.tgz#21154c095ddc703722b1fb8bb06c126c0b6d77dc" + integrity sha512-kTHnOwoOXfPXi00Z8yAgyD64+jdSXk3pknnS7NlqnCKAU6YDkXZ4Y7irl66kaZjZn0FBBt0P4YOZFZk85jYOww== + dependencies: + "@ember-data/rfc395-data" "^0.0.4" + babel-plugin-ember-modules-api-polyfill@2.6.0, babel-plugin-ember-modules-api-polyfill@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" @@ -1995,6 +2922,13 @@ babel-plugin-ember-modules-api-polyfill@^2.9.0: dependencies: ember-rfc176-data "^0.3.9" +babel-plugin-ember-modules-api-polyfill@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-3.1.1.tgz#c6e9ede43b64c4e36512f260e42e829b071d9b4f" + integrity sha512-hRTnr59fJ6cIiSiSgQLM9QRiVv/RrBAYRYggCPQDj4dvYhOWZeoX6e+1jFY1qC3tJnSDuMWu3OrDciSIi1MJ0A== + dependencies: + ember-rfc176-data "^0.3.15" + babel-plugin-feature-flags@0.3.1, babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" @@ -2573,22 +3507,6 @@ broccoli-babel-transpiler@^6.5.0: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^7.1.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.1.tgz#4202cd0653845083ee744fb4eaa4a2b50292f03f" - integrity sha512-iZE6yxDcEe4XSMEyqyyS+wtkNAsPUGJNleJoVu26Vt2Al8/GqRI5+wc7qquPb71I1W7AtqbkaqsgDFDqBoIYKw== - dependencies: - "@babel/core" "^7.0.0" - broccoli-funnel "^2.0.1" - broccoli-merge-trees "^3.0.0" - broccoli-persistent-filter "^1.4.3" - clone "^2.1.2" - hash-for-dep "^1.2.3" - heimdalljs-logger "^0.1.9" - json-stable-stringify "^1.0.1" - rsvp "^4.8.3" - workerpool "^2.3.1" - broccoli-babel-transpiler@^7.1.2: version "7.2.0" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.2.0.tgz#5c0d694c4055106abb385e2d3d88936d35b7cb18" @@ -2606,6 +3524,24 @@ broccoli-babel-transpiler@^7.1.2: rsvp "^4.8.4" workerpool "^3.1.1" +broccoli-babel-transpiler@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.7.0.tgz#271d401e713bfd338d5ef0435d3c4c68f6eddd2a" + integrity sha512-U8Cmnv0/AcQKehiIVi6UDzqq3jqhAEbY9CvOW5vdeNRmYhFpK6bXPmVczS/nUz5g4KsPc/FdnC3zbU6yVf4e7w== + dependencies: + "@babel/core" "^7.11.0" + "@babel/polyfill" "^7.10.4" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + broccoli-persistent-filter "^2.2.1" + clone "^2.1.2" + hash-for-dep "^1.4.7" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.9" + json-stable-stringify "^1.0.1" + rsvp "^4.8.4" + workerpool "^3.1.1" + broccoli-concat@^3.2.2: version "3.7.3" resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" @@ -2967,6 +3903,16 @@ browserslist@^4.0.0, browserslist@^4.3.4: electron-to-chromium "^1.3.295" node-releases "^1.1.38" +browserslist@^4.12.0, browserslist@^4.8.5: + version "4.13.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.13.0.tgz#42556cba011e1b0a2775b611cba6a8eca18e940d" + integrity sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ== + dependencies: + caniuse-lite "^1.0.30001093" + electron-to-chromium "^1.3.488" + escalade "^3.0.1" + node-releases "^1.1.58" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -3130,6 +4076,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000844, can resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001054.tgz#7e82fc42d927980b0ce1426c4813df12381e1a75" integrity sha512-jiKlTI6Ur8Kjfj8z0muGrV6FscpRvefcQVPSuMuXnvRCfExU7zlVLNjmOz1TnurWgUrAY7MMmjyy+uTgIl1XHw== +caniuse-lite@^1.0.30001093: + version "1.0.30001111" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001111.tgz#dd0ce822c70eb6c7c068e4a55c22e19ec1501298" + integrity sha512-xnDje2wchd/8mlJu8sXvWxOGvMgv+uT3iZ3bkIAynKOzToCssWCmkz/ZIkQBs/2pUB4uwnJKVORWQ31UkbVjOg== + capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" @@ -3475,6 +4426,14 @@ copy-webpack-plugin@5.1.1: serialize-javascript "^2.1.2" webpack-log "^2.0.0" +core-js-compat@^3.6.2: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== + dependencies: + browserslist "^4.8.5" + semver "7.0.0" + core-js@^2.4.0, core-js@^2.5.0: version "2.5.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" @@ -3485,6 +4444,11 @@ core-js@^2.5.7: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg== +core-js@^2.6.5: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -4073,6 +5037,11 @@ electron-to-chromium@^1.3.295, electron-to-chromium@^1.3.30, electron-to-chromiu resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz#e8265301d053d5f74e36cb876486830261fbe946" integrity sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A== +electron-to-chromium@^1.3.488: + version "1.3.523" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.523.tgz#494080b318ba929614eebd04405b94c359ea9333" + integrity sha512-D4/3l5DpciddD92IDRtpLearQSGzly8FwBJv+nITvLH8YJrFabpDFe4yuiOJh2MS4/EsXqyQTXyw1toeYPtshQ== + elliptic@^6.0.0: version "6.5.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" @@ -4156,26 +5125,36 @@ ember-cli-babel@^6.16.0, ember-cli-babel@^6.17.0, ember-cli-babel@^6.3.0, ember- ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.2.0.tgz#5c5bd877fb73f6fb198c878d3127ba9e18e9b8a0" - integrity sha512-vwx/AgPD7P4ebgTFJMqFovbrSNCA02UMuItlR/Il16njYjgN9ZzjUqgYxaylN7k8RF88wdJq3jrtqyMS/oOq8A== - dependencies: - "@babel/core" "^7.0.0" - "@babel/plugin-transform-modules-amd" "^7.0.0" - "@babel/polyfill" "^7.0.0" - "@babel/preset-env" "^7.0.0" +ember-cli-babel@^7.2.0: + version "7.22.1" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.22.1.tgz#cad28b89cf0e184c93b863d09bc5ba4ce1d2e453" + integrity sha512-kCT8WbC1AYFtyOpU23ESm22a+gL6fWv8Nzwe8QFQ5u0piJzM9MEudfbjADEaoyKTrjMQTDsrWwEf3yjggDsOng== + dependencies: + "@babel/core" "^7.11.0" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-decorators" "^7.10.5" + "@babel/plugin-transform-modules-amd" "^7.10.5" + "@babel/plugin-transform-runtime" "^7.11.0" + "@babel/plugin-transform-typescript" "^7.11.0" + "@babel/polyfill" "^7.10.4" + "@babel/preset-env" "^7.11.0" + "@babel/runtime" "^7.11.0" amd-name-resolver "^1.2.1" - babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.6.0" + babel-plugin-debug-macros "^0.3.3" + babel-plugin-ember-data-packages-polyfill "^0.1.2" + babel-plugin-ember-modules-api-polyfill "^3.1.1" babel-plugin-module-resolver "^3.1.1" - broccoli-babel-transpiler "^7.1.0" + broccoli-babel-transpiler "^7.7.0" broccoli-debug "^0.6.4" broccoli-funnel "^2.0.1" broccoli-source "^1.1.0" clone "^2.1.2" - ember-cli-version-checker "^2.1.2" + ember-cli-babel-plugin-helpers "^1.1.0" + ember-cli-version-checker "^4.1.0" ensure-posix-path "^1.0.2" + fixturify-project "^1.10.0" + rimraf "^3.0.1" semver "^5.5.0" ember-cli-babel@^7.5.0: @@ -4318,6 +5297,15 @@ ember-cli-version-checker@^3.1.3: resolve-package-path "^1.2.6" semver "^5.6.0" +ember-cli-version-checker@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-4.1.1.tgz#27b938228306cb0dbc4f74e95c536cdd6448e499" + integrity sha512-bzEWsTMXUGEJfxcAGWPe6kI7oHEGD3jaxUWDYPTqzqGhNkgPwXTBgoWs9zG1RaSMaOPFnloWuxRcoHi4TrYS3Q== + dependencies: + resolve-package-path "^2.0.0" + semver "^6.3.0" + silent-error "^1.1.1" + ember-compatibility-helpers@1.0.2, ember-compatibility-helpers@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" @@ -4494,6 +5482,11 @@ ember-rfc176-data@^0.3.0: resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.2.tgz#bde5538939529b263c142b53a47402f8127f8dce" integrity sha512-NKpr+dkKFoszdq2Sf5bE7xCsTayJN5CoDhi8wjjqD29Umk4DeRjgYtyhQa0wZ6rj9n97ZCp1BqnBAHOlXeDuGw== +ember-rfc176-data@^0.3.15: + version "0.3.15" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.15.tgz#af3f1da5a0339b6feda380edc2f7190e0f416c2d" + integrity sha512-GPKa7zRDBblRy0orxTXt5yrpp/Pf5CkuRFSIR8qMFDww0CqCKjCRwdZnWYzCM4kAEfZnXRIDDefe1tBaFw7v7w== + ember-rfc176-data@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977" @@ -4529,15 +5522,15 @@ ember-runtime-enumerable-includes-polyfill@^2.1.0: ember-cli-babel "^6.9.0" ember-cli-version-checker "^2.1.0" -ember-source@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.7.1.tgz#c6e8fb26ff25d9754add3e87e3f292da2feeeb31" - integrity sha512-xwebK659JP/VEqTPMQ5WtTnae/eSx1KAbp6YrBZ7ypMiL4EmJDLpE4xUbEn91mipdKN1DQgHVOwF6yOHDTTXtA== +ember-source@3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.8.3.tgz#831a4e792f06d1ff292595fad817eed8f2be9d0c" + integrity sha512-QPeBgszpL9N5TL8Dbq4fIpJyG9uiMP7+tST01/y86ToUHmYuCrEuGeHDWLM3qTG+eKczuqx1b5K18gyM9K5JeA== dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^3.0.2" chalk "^2.3.0" - ember-cli-babel "^7.1.3" + ember-cli-babel "^7.2.0" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" @@ -4547,7 +5540,7 @@ ember-source@3.7.1: ember-router-generator "^1.2.3" inflection "^1.12.0" jquery "^3.3.1" - resolve "^1.6.0" + resolve "^1.9.0" emoji-regex@^7.0.1: version "7.0.3" @@ -4662,6 +5655,11 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +escalade@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" + integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -5164,6 +6162,25 @@ fined@^1.0.1: object.pick "^1.2.0" parse-filepath "^1.0.1" +fixturify-project@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/fixturify-project/-/fixturify-project-1.10.0.tgz#091c452a9bb15f09b6b9cc7cf5c0ad559f1d9aad" + integrity sha512-L1k9uiBQuN0Yr8tA9Noy2VSQ0dfg0B8qMdvT7Wb5WQKc7f3dn3bzCbSrqlb+etLW+KDV4cBC7R1OvcMg3kcxmA== + dependencies: + fixturify "^1.2.0" + tmp "^0.0.33" + +fixturify@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-1.3.0.tgz#163c468093c7c4d90b70cde39fd6325f6528b25d" + integrity sha512-tL0svlOy56pIMMUQ4bU1xRe6NZbFSa/ABTWMxW2mH38lFGc9TrNAKWcMBQ7eIjo3wqSS8f2ICabFaatFyFmrVQ== + dependencies: + "@types/fs-extra" "^5.0.5" + "@types/minimatch" "^3.0.3" + "@types/rimraf" "^2.0.2" + fs-extra "^7.0.1" + matcher-collection "^2.0.0" + flag-icon-css@2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/flag-icon-css/-/flag-icon-css-2.8.0.tgz#ec10c20fe417ade787a095200630069ca436a569" @@ -5290,7 +6307,7 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^7.0.0: +fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -6108,7 +7125,7 @@ interpret@~1.1.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -6615,6 +7632,13 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -6718,6 +7742,18 @@ less@3.0.2: request "^2.83.0" source-map "^0.5.3" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -7005,6 +8041,14 @@ matcher-collection@^1.1.1: dependencies: minimatch "^3.0.2" +matcher-collection@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" + integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ== + dependencies: + "@types/minimatch" "^3.0.3" + minimatch "^3.0.2" + md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -7439,6 +8483,11 @@ node-releases@^1.1.38: dependencies: semver "^6.3.0" +node-releases@^1.1.58: + version "1.1.60" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" + integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== + nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -7587,7 +8636,7 @@ object-hash@^2.0.1: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea" integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg== -object-keys@^1.0.12: +object-keys@^1.0.11, object-keys@^1.0.12: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -7604,6 +8653,16 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + object.defaults@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" @@ -8636,6 +9695,13 @@ regenerate-unicode-properties@^7.0.0: dependencies: regenerate "^1.4.0" +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -8666,6 +9732,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -8682,6 +9753,13 @@ regenerator-transform@^0.13.3: dependencies: private "^0.1.6" +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -8716,6 +9794,18 @@ regexpu-core@^4.1.3, regexpu-core@^4.2.0: unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.0.2" +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" @@ -8726,6 +9816,11 @@ regjsgen@^0.5.0: resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" @@ -8740,6 +9835,13 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" @@ -8852,6 +9954,14 @@ resolve-package-path@^1.0.11, resolve-package-path@^1.2.6: path-root "^0.1.1" resolve "^1.10.0" +resolve-package-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-2.0.0.tgz#7f258ab86ff074fff4ff8027a28f94d17d6fb1df" + integrity sha512-/CLuzodHO2wyyHTzls5Qr+EFeG6RcW4u6//gjYvUfcfyuplIX1SSccU+A5A9A78Gmezkl3NBkFAMxLbzTY9TJA== + dependencies: + path-root "^0.1.1" + resolve "^1.13.1" + resolve-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" @@ -8885,6 +9995,13 @@ resolve@^1.10.0, resolve@^1.5.0, resolve@^1.8.1: dependencies: path-parse "^1.0.6" +resolve@^1.13.1, resolve@^1.9.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + resolve@^1.3.2: version "1.9.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" @@ -8899,13 +10016,6 @@ resolve@^1.3.3, resolve@^1.4.0: dependencies: path-parse "^1.0.5" -resolve@^1.6.0: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== - dependencies: - path-parse "^1.0.5" - resolve@~1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -8955,18 +10065,18 @@ rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= - -rimraf@~3.0.2: +rimraf@^3.0.1, rimraf@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -9010,7 +10120,7 @@ rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.3.3, rsvp@^3.5.0: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== -rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4: +rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.4: version "4.8.4" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" integrity sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA== @@ -9122,6 +10232,11 @@ semver@5.5.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + semver@^5.5.1, semver@^5.6.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" @@ -9916,6 +11031,11 @@ unicode-match-property-value-ecmascript@^1.0.2: resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" integrity sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ== +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + unicode-property-aliases-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" @@ -10257,13 +11377,6 @@ workerpool@^2.3.0: dependencies: object-assign "4.1.1" -workerpool@^2.3.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" - integrity sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA== - dependencies: - object-assign "4.1.1" - workerpool@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-3.1.2.tgz#b34e79243647decb174b7481ab5b351dc565c426" From 0158a1d255805ec9b705ddd159a20445acb519a8 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 04:15:26 +0200 Subject: [PATCH 02/34] vendor: upgrade to Ember 3.9.1 --- package.json | 2 +- yarn.lock | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index cb55f70fe7..31b43a0855 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "bootstrap": "3.3.1", - "ember-source": "3.8.3", + "ember-source": "3.9.1", "ember-data": "3.9.0", "ember-data-model-fragments": "4.0.0", "ember-fetch": "6.5.0", diff --git a/yarn.lock b/yarn.lock index c5d480775e..c357585dae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4104,7 +4104,7 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== @@ -5125,7 +5125,7 @@ ember-cli-babel@^6.16.0, ember-cli-babel@^6.17.0, ember-cli-babel@^6.3.0, ember- ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.2.0: +ember-cli-babel@^7.4.2: version "7.22.1" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.22.1.tgz#cad28b89cf0e184c93b863d09bc5ba4ce1d2e453" integrity sha512-kCT8WbC1AYFtyOpU23ESm22a+gL6fWv8Nzwe8QFQ5u0piJzM9MEudfbjADEaoyKTrjMQTDsrWwEf3yjggDsOng== @@ -5289,7 +5289,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^3.1.3: +ember-cli-version-checker@^3.0.1, ember-cli-version-checker@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.3.tgz#7c9b4f5ff30fdebcd480b1c06c4de43bb51c522c" integrity sha512-PZNSvpzwWgv68hcXxyjREpj3WWb81A7rtYNQq1lLEgrWIchF8ApKJjWP3NBpHjaatwILkZAV8klair5WFlXAKg== @@ -5522,25 +5522,25 @@ ember-runtime-enumerable-includes-polyfill@^2.1.0: ember-cli-babel "^6.9.0" ember-cli-version-checker "^2.1.0" -ember-source@3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.8.3.tgz#831a4e792f06d1ff292595fad817eed8f2be9d0c" - integrity sha512-QPeBgszpL9N5TL8Dbq4fIpJyG9uiMP7+tST01/y86ToUHmYuCrEuGeHDWLM3qTG+eKczuqx1b5K18gyM9K5JeA== +ember-source@3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.9.1.tgz#e6c7b08f823f9a55e448af1cc439266cabc3e65e" + integrity sha512-0rfP1m3KbfylKNnxk4ZWy0jqwqIWGm5rb7ZZFn4zazVJFI6gEmratWadXfzwEgqG2ukRcW9F8frEk0utuaAnMg== dependencies: - broccoli-funnel "^2.0.1" + broccoli-funnel "^2.0.2" broccoli-merge-trees "^3.0.2" - chalk "^2.3.0" - ember-cli-babel "^7.2.0" + chalk "^2.4.2" + ember-cli-babel "^7.4.2" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" ember-cli-string-utils "^1.1.0" - ember-cli-version-checker "^2.1.0" + ember-cli-version-checker "^3.0.1" ember-router-generator "^1.2.3" inflection "^1.12.0" jquery "^3.3.1" - resolve "^1.9.0" + resolve "^1.10.0" emoji-regex@^7.0.1: version "7.0.3" @@ -9995,7 +9995,7 @@ resolve@^1.10.0, resolve@^1.5.0, resolve@^1.8.1: dependencies: path-parse "^1.0.6" -resolve@^1.13.1, resolve@^1.9.0: +resolve@^1.13.1: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== From 9082530cd61f5e9dca9783b3762556dbf03b37ad Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 04:23:17 +0200 Subject: [PATCH 03/34] chore: fix volatile comp-prop deprecation --- src/app/data/models/stream/model.js | 4 +- src/app/data/models/twitch/image/model.js | 66 ++++++++++--------- .../quick/quick-bar-homepage/component.js | 26 +++----- .../tests/ui/routes/-mixins/routes/refresh.js | 7 +- 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/app/data/models/stream/model.js b/src/app/data/models/stream/model.js index d692cb0450..a6a27b2afa 100644 --- a/src/app/data/models/stream/model.js +++ b/src/app/data/models/stream/model.js @@ -117,12 +117,12 @@ export default Model.extend({ }), - customParameters: computed(function() { + get customParameters() { const provider = get( this, "settings.streaming.provider" ); const providers = get( this, "settings.streaming.providers" ); return get( providers, `${provider}.params` ) || ""; - }).volatile(), + }, kill() { diff --git a/src/app/data/models/twitch/image/model.js b/src/app/data/models/twitch/image/model.js index 5f07bce9a0..7206a1ad30 100644 --- a/src/app/data/models/twitch/image/model.js +++ b/src/app/data/models/twitch/image/model.js @@ -1,4 +1,3 @@ -import { get, computed } from "@ember/object"; import attr from "ember-data/attr"; import Model from "ember-data/model"; import { vars } from "config"; @@ -14,42 +13,37 @@ function getURL( url, time ) { /** * Return the image URL with an already set expiration time. * Or create a new expiration time if it hasn't been set yet. - * @param {String} attr - * @returns {Ember.ComputedProperty} Volatile computed property + * @param {string} attr + * @returns {string} */ function buffered( attr ) { - return computed(function() { - let exp = this[ `expiration_${attr}` ]; + const exp = this[ `expiration_${attr}` ]; - return exp - ? getURL( get( this, `image_${attr}` ), exp ) - : get( this, `${attr}Latest` ); - }).volatile(); + return exp + ? getURL( this[ `image_${attr}` ], exp ) + : this[ `${attr}Latest` ]; } /** * Return the image URL with an expiration parameter, so the latest version will be requested. * Update the expiration timer only once every X seconds. - * @param {String} attr - * @returns {Ember.ComputedProperty} Volatile computed property + * @param {string} attr + * @returns {string} */ function latest( attr ) { - // use a volatile property - return computed(function() { - const url = get( this, `image_${attr}` ); + const url = this[ `image_${attr}` ]; - // use the same timestamp for `time` seconds - const key = `expiration_${attr}`; - const now = Date.now(); - let exp = this[ key ]; + // use the same timestamp for `time` seconds + const key = `expiration_${attr}`; + const now = Date.now(); + let exp = this[ key ]; - if ( !exp || exp <= now ) { - exp = now + time; - this[ key ] = exp; - } + if ( !exp || exp <= now ) { + exp = now + time; + this[ key ] = exp; + } - return getURL( url, exp ); - }).volatile(); + return getURL( url, exp ); } @@ -66,13 +60,25 @@ export default Model.extend({ // "request latest image version, but only every X seconds" // should be used by a route's model hook - largeLatest: latest( "large" ), - mediumLatest: latest( "medium" ), - smallLatest: latest( "small" ), + get largeLatest() { + return latest.call( this, "large" ); + }, + get mediumLatest() { + return latest.call( this, "medium" ); + }, + get smallLatest() { + return latest.call( this, "small" ); + }, // "use the previous expiration parameter" // should be used by all image src attributes in the DOM - large: buffered( "large" ), - medium: buffered( "medium" ), - small: buffered( "small" ) + get large() { + return buffered.call( this, "large" ); + }, + get medium() { + return buffered.call( this, "medium" ); + }, + get small() { + return buffered.call( this, "small" ); + } }); diff --git a/src/app/ui/components/quick/quick-bar-homepage/component.js b/src/app/ui/components/quick/quick-bar-homepage/component.js index 5d71fd947c..712f346f8f 100644 --- a/src/app/ui/components/quick/quick-bar-homepage/component.js +++ b/src/app/ui/components/quick/quick-bar-homepage/component.js @@ -1,5 +1,5 @@ -import { getOwner } from "@ember/application"; -import { get, set, computed } from "@ember/object"; +import { set } from "@ember/object"; +import { equal } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import { translationMacro as t } from "ember-i18n/addon"; import FormButtonComponent from "ui/components/button/form-button/component"; @@ -7,6 +7,7 @@ import FormButtonComponent from "ui/components/button/form-button/component"; export default FormButtonComponent.extend({ i18n: service(), + router: service(), settings: service(), classNames: "btn-neutral", @@ -17,26 +18,15 @@ export default FormButtonComponent.extend({ icon: "fa-home", iconanim: true, - url: computed(function() { - let router = getOwner( this ).lookup( "router:main" ); - let location = get( router, "location" ); - - return location.getURL(); - }).volatile(), - - isHomepage: computed( "url", "settings.gui.homepage", function() { - return get( this, "url" ) === get( this, "settings.gui.homepage" ); - }), + isHomepage: equal( "router.currentURL", "settings.content.gui.homepage" ), action() { - let settings = get( this, "settings.content" ); - let value = get( this, "url" ); - if ( !settings || !value ) { - return Promise.reject(); - } - + /** @type {Settings} */ + const settings = this.settings.content; + const value = this.router.currentURL; set( settings, "gui.homepage", value ); + return settings.save(); } }); diff --git a/src/test/tests/ui/routes/-mixins/routes/refresh.js b/src/test/tests/ui/routes/-mixins/routes/refresh.js index 35ccce9a3a..fabf39ceb2 100644 --- a/src/test/tests/ui/routes/-mixins/routes/refresh.js +++ b/src/test/tests/ui/routes/-mixins/routes/refresh.js @@ -1,6 +1,6 @@ import { module, test } from "qunit"; import { runDestroy, buildOwner } from "test-utils"; -import { default as EmberObject, set, computed } from "@ember/object"; +import { default as EmberObject, set } from "@ember/object"; import { sendEvent } from "@ember/object/events"; import Service from "@ember/service"; import { EventEmitter } from "events"; @@ -39,12 +39,15 @@ module( "ui/routes/-mixins/routes/refresh", { this.PROP_DEFER = PROP_DEFER; this.TIME_DEBOUNCE = TIME_DEBOUNCE; + const testContext = this; const ModalService = Service.extend({ isModalOpened: false }); const SettingsService = Service.extend({ gui: EmberObject.extend({ - focusrefresh: computed( () => this.threshold ).volatile() + get focusrefresh() { + return testContext.threshold; + } }).create() }); const Route = EmberObject.extend( RefreshMixin ); From a9c2e4f59e9ac71a9a21233df3084f6af8f1cf1e Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 04:59:48 +0200 Subject: [PATCH 04/34] chore: fix clobbering in placeholder comp-prop --- .../form/drop-down-selection/component.js | 10 ++++++- .../components/form/file-select/component.js | 26 ++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/app/ui/components/form/drop-down-selection/component.js b/src/app/ui/components/form/drop-down-selection/component.js index d6c8650ae5..639ab0dad9 100644 --- a/src/app/ui/components/form/drop-down-selection/component.js +++ b/src/app/ui/components/form/drop-down-selection/component.js @@ -14,7 +14,15 @@ export default Component.extend({ classNames: [ "drop-down-selection-component" ], classNameBindings: [ "class" ], - placeholder: t( "components.drop-down-selection.placeholder" ), + _defaultPlaceholder: t( "components.drop-down-selection.placeholder" ), + _placeholder: null, + + get placeholder() { + return this._placeholder || this._defaultPlaceholder; + }, + set placeholder( value ) { + this._placeholder = value; + }, click() { get( this, "action" )(); diff --git a/src/app/ui/components/form/file-select/component.js b/src/app/ui/components/form/file-select/component.js index e42273ffa9..5d493b0e94 100644 --- a/src/app/ui/components/form/file-select/component.js +++ b/src/app/ui/components/form/file-select/component.js @@ -1,7 +1,8 @@ import Component from "@ember/component"; -import { get, set, computed } from "@ember/object"; +import { set } from "@ember/object"; import { on } from "@ember/object/evented"; import { inject as service } from "@ember/service"; +import { translationMacro as t } from "ember-i18n/addon"; import { platform } from "utils/node/platform"; import layout from "./template.hbs"; @@ -21,23 +22,24 @@ export default Component.extend({ value: "", disabled: false, - placeholder: computed({ - set( key, value ) { - if ( typeof value === "string" ) { - return value; - } + _defaultPlaceholder: t( "components.file-select.placeholder" ), + _placeholder: null, - if ( typeof value !== "object" || !hasOwnProperty.call( value, platform ) ) { - return get( this, "i18n" ).t( "components.file-select.placeholder" ).toString(); - } + get placeholder() { + return this._placeholder || this._defaultPlaceholder; + }, + set placeholder( value ) { + if ( typeof value === "string" ) { + this._placeholder = value; + } else if ( typeof value === "object" && hasOwnProperty.call( value, platform ) ) { value = value[ platform ]; - return isArray( value ) + this._placeholder = isArray( value ) ? value[ 0 ] : value; } - }), + }, _createInput: on( "didInsertElement", function() { const input = this.element.ownerDocument.createElement( "input" ); @@ -54,7 +56,7 @@ export default Component.extend({ actions: { selectfile() { - if ( !get( this, "disabled" ) ) { + if ( !this.disabled ) { this._input.dispatchEvent( new MouseEvent( "click", { bubbles: true } ) ); } } From ca3754c2301d4eb424271bca3954a24679d85b5e Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 05:00:30 +0200 Subject: [PATCH 05/34] chore: fix clobbering in StreamItemComponent --- .../components/list/stream-item/component.js | 6 ++ .../routes/user/followed-streams/template.hbs | 2 +- .../tests/ui/components/list/stream-item.js | 59 +++++++++++-------- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/app/ui/components/list/stream-item/component.js b/src/app/ui/components/list/stream-item/component.js index 7993ea8231..fa1228db74 100644 --- a/src/app/ui/components/list/stream-item/component.js +++ b/src/app/ui/components/list/stream-item/component.js @@ -32,6 +32,7 @@ export default ListItemComponent.extend({ expanded: false, locked : false, timer : null, + ignoreLanguageFading: false, showGame: notEmpty( "channel.game" ), @@ -44,11 +45,16 @@ export default ListItemComponent.extend({ fadedVodcast: and( "content.isVodcast", "settings.content.streams.filter_vodcast" ), faded: computed( + "ignoreLanguageFading", "settings.content.streams.filter_languages", "settings.content.streams.language", "channel.language", "channel.broadcaster_language", function() { + if ( this.ignoreLanguageFading ) { + return false; + } + const { filter_languages, language } = this.settings.content.streams; if ( filter_languages !== ATTR_FILTER_LANGUAGES_FADE ) { diff --git a/src/app/ui/routes/user/followed-streams/template.hbs b/src/app/ui/routes/user/followed-streams/template.hbs index ce5c8e3f9d..ad9bb75902 100644 --- a/src/app/ui/routes/user/followed-streams/template.hbs +++ b/src/app/ui/routes/user/followed-streams/template.hbs @@ -8,7 +8,7 @@ {{/quick-bar}} {{#content-list model as |item isNewItem isDuplicateItem|}} -{{stream-item content=item isNewItem=isNewItem isDuplicateItem=isDuplicateItem faded=false}} +{{stream-item content=item isNewItem=isNewItem isDuplicateItem=isDuplicateItem ignoreLanguageFading=true}} {{else}}

{{t "routes.user.followedStreams.empty.text"}}

    diff --git a/src/test/tests/ui/components/list/stream-item.js b/src/test/tests/ui/components/list/stream-item.js index 1068cadcbd..c1e76cd01f 100644 --- a/src/test/tests/ui/components/list/stream-item.js +++ b/src/test/tests/ui/components/list/stream-item.js @@ -5,6 +5,7 @@ import { render } from "@ember/test-helpers"; import hbs from "htmlbars-inline-precompile"; import { set } from "@ember/object"; +import { run } from "@ember/runloop"; import Service from "@ember/service"; import StreamItemComponent from "ui/components/list/stream-item/component"; @@ -69,6 +70,12 @@ module( "ui/components/list/stream-item", function( hooks ) { set( subject, "settings.content.streams.filter_languages", ATTR_FILTER_LANGUAGES_NOOP ); assert.notOk( subject.faded, "Not faded if fading is disabled" ); + + set( subject, "settings.content.streams.filter_languages", ATTR_FILTER_LANGUAGES_FADE ); + assert.ok( subject.faded, "Faded again if fading is enabled" ); + + set( subject, "ignoreLanguageFading", true ); + assert.notOk( subject.faded, "Not faded anymore if ignoreLanguageFading is true" ); }); @@ -94,44 +101,46 @@ module( "ui/components/list/stream-item", function( hooks ) { test( "isFaded element class", async function( assert ) { + const SettingsService = this.owner.lookup( "service:settings" ); this.setProperties({ - faded: false, - fadedVodcast: false + ignoreLanguageFading: false, + content: { + isVodcast: false, + channel: { + language: "en" + } + } }); - await render( hbs`{{stream-item faded=faded fadedVodcast=fadedVodcast}}` ); + await render( hbs` + {{stream-item content=content ignoreLanguageFading=ignoreLanguageFading}} + ` ); const elem = this.element.querySelector( ".stream-item-component" ); assert.notOk( elem.classList.contains( "faded" ), - "Not faded if faded and fadedVodcast are falsy" + "Not faded if faded and fadedVodcast are false" ); - this.setProperties({ - faded: true, - fadedVodcast: false + run( () => { + set( this, "content.isVodcast", true ); + set( SettingsService, "content.streams.filter_vodcast", true ); }); - assert.ok( - elem.classList.contains( "faded" ), - "Faded if faded or fadedVodcast are truthy" - ); + assert.ok( elem.classList.contains( "faded" ), "Faded if fadedVodcast is true" ); - this.setProperties({ - faded: false, - fadedVodcast: true + run( () => { + set( this, "content.channel.language", "other" ); }); - assert.ok( - elem.classList.contains( "faded" ), - "Faded if faded or fadedVodcast are truthy" - ); + assert.ok( elem.classList.contains( "faded" ), "Faded if faded and fadedVodcast are true" ); - this.setProperties({ - faded: true, - fadedVodcast: true + run( () => { + set( this, "content.isVodcast", false ); }); - assert.ok( - elem.classList.contains( "faded" ), - "Faded if faded or fadedVodcast are truthy" - ); + assert.ok( elem.classList.contains( "faded" ), "Faded if faded is true" ); + + run( () => { + set( this, "ignoreLanguageFading", true ); + }); + assert.notOk( elem.classList.contains( "faded" ), "Not faded if ignoreLanguageFading" ); }); }); From e4fc1b8f5964dd58d7b897e9159c0a1256dc6d11 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 16 Apr 2019 05:13:09 +0200 Subject: [PATCH 06/34] chore: fix clobbering in SettingsSubmitComponent --- .../components/settings-submit/component.js | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/app/ui/components/settings-submit/component.js b/src/app/ui/components/settings-submit/component.js index 7409279943..5edb2e621d 100644 --- a/src/app/ui/components/settings-submit/component.js +++ b/src/app/ui/components/settings-submit/component.js @@ -1,5 +1,5 @@ import Component from "@ember/component"; -import { get, set, computed, observer } from "@ember/object"; +import { set, observer } from "@ember/object"; import { on } from "@ember/object/evented"; import { cancel, later } from "@ember/runloop"; import layout from "./template.hbs"; @@ -17,19 +17,21 @@ export default Component.extend({ delay: 1000, + _enabled: false, + apply() {}, discard() {}, - _enabled: computed(function() { - return get( this, "isDirty" ) - && !get( this, "disabled" ); - }), + init() { + this._super( ...arguments ); + set( this, "_enabled", this.isDirty && !this.disabled ); + }, // immediately set enabled when disabled property changes _disabledObserver: observer( "disabled", function() { - let enabled = get( this, "disabled" ) + const enabled = this.disabled ? false - : get( this, "isDirty" ); + : this.isDirty; set( this, "_enabled", enabled ); }), @@ -37,18 +39,17 @@ export default Component.extend({ // isDirty === false: wait and then set to false _timeout: null, _isDirtyObserver: observer( "isDirty", function() { - if ( get( this, "disabled" ) ) { return; } + if ( this.disabled ) { return; } this._clearTimeout(); - if ( get( this, "isDirty" ) ) { + if ( this.isDirty ) { set( this, "_enabled", true ); } else { - let delay = get( this, "delay" ); this._timeout = later( () => { set( this, "_enabled", false ); this._timeout = null; - }, delay ); + }, this.delay ); } }), From 7072c1f240d8ab95260cf6ed2118d5a76873e10e Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Fri, 19 Apr 2019 07:34:12 +0200 Subject: [PATCH 07/34] build: update/fix decorators build config - upgrade to latest ember-decorators - use native ember decorators polyfill (until 3.10) - update ember modules API babel plugin - add transform runtime babel plugin --- .../webpack/configurators/ember/decorators.js | 5 +- .../webpack/configurators/ember/source.js | 20 +- package.json | 7 +- src/web_modules/ember.js | 3 + yarn.lock | 230 +++++++----------- 5 files changed, 115 insertions(+), 150 deletions(-) diff --git a/build/tasks/webpack/configurators/ember/decorators.js b/build/tasks/webpack/configurators/ember/decorators.js index aff63a68e4..5a1425f439 100644 --- a/build/tasks/webpack/configurators/ember/decorators.js +++ b/build/tasks/webpack/configurators/ember/decorators.js @@ -8,7 +8,10 @@ const webpack = require( "webpack" ); module.exports = function( config, grunt, isProd ) { config.module.rules.push({ test: /\.js$/, - include: r( pDependencies, "@ember-decorators" ), + include: [ + r( pDependencies, "@ember-decorators" ), + r( pDependencies, "ember-decorators-polyfill" ) + ], loader: "babel-loader", options: buildBabelConfig({ plugins: [ diff --git a/build/tasks/webpack/configurators/ember/source.js b/build/tasks/webpack/configurators/ember/source.js index 9c93702e70..2b2c5366f5 100644 --- a/build/tasks/webpack/configurators/ember/source.js +++ b/build/tasks/webpack/configurators/ember/source.js @@ -33,13 +33,29 @@ module.exports = function( config, grunt, isProd ) { loader: "babel-loader", options: buildBabelConfig({ plugins: [ + [ "@babel/plugin-transform-runtime", { + corejs: false, + helpers: true, + regenerator: false, + useESModules: true, + // https://github.com/babel/babel/issues/9454#issuecomment-460425922 + version: "7.2.2" + } ], // translate @ember imports (requires imports to be ignored in webpack - see below) "babel-plugin-ember-modules-api-polyfill", // transform decorators [ "@babel/plugin-proposal-decorators", { - decoratorsBeforeExport: true + // https://emberjs.github.io/rfcs/0440-decorator-support.html + // https://github.com/babel/ember-cli-babel/blob/v7.7.3/index.js#L341 + // Move forward with the Decorators RFC via stage 1 decorators, + // and await a stable future decorators proposal. + legacy: true } ], - "@babel/plugin-proposal-class-properties" + [ "@babel/plugin-proposal-class-properties", { + // https://babeljs.io/docs/en/babel-plugin-proposal-decorators + // When using the legacy mode, class-properties must be used in loose mode + loose: true + } ] ] }) }); diff --git a/package.json b/package.json index 31b43a0855..9c921b403c 100644 --- a/package.json +++ b/package.json @@ -37,14 +37,14 @@ "@babel/plugin-proposal-decorators": "7.3.0", "@babel/plugin-transform-block-scoping": "7.2.0", "@babel/plugin-transform-modules-commonjs": "7.2.0", + "@babel/plugin-transform-runtime": "7.4.3", "@babel/plugin-transform-typescript": "7.4.0", "@ember/test-helpers": "0.7.27", - "@ember-decorators/argument": "0.8.21", "@glimmer/syntax": "0.47.4", "babel-eslint": "10.0.1", "babel-loader": "8.0.5", "babel-plugin-debug-macros": "0.2.0", - "babel-plugin-ember-modules-api-polyfill": "2.6.0", + "babel-plugin-ember-modules-api-polyfill": "2.9.0", "babel-plugin-feature-flags": "0.3.1", "babel-plugin-filter-imports": "2.0.4", "babel-plugin-istanbul": "6.0.0", @@ -54,7 +54,8 @@ "copy-webpack-plugin": "5.1.1", "css-loader": "2.1.1", "ember-compatibility-helpers": "1.0.2", - "ember-decorators": "2.5.1", + "ember-decorators": "6.1.1", + "ember-decorators-polyfill": "1.0.5", "ember-qunit": "3.5.1", "eslint": "5.16.0", "eslint-loader": "3.0.3", diff --git a/src/web_modules/ember.js b/src/web_modules/ember.js index e94c848774..b0fb2badb5 100644 --- a/src/web_modules/ember.js +++ b/src/web_modules/ember.js @@ -14,5 +14,8 @@ window.requirejs = { }; window.requireModule = Ember.__loader.require; +// polyfill Ember's native decorators +require( "ember-decorators-polyfill/vendor/ember-decorators-polyfill" ); + export default Ember; diff --git a/yarn.lock b/yarn.lock index c357585dae..af2d77cea8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,6 +1363,16 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-runtime@7.4.3", "@babel/plugin-transform-runtime@^7.2.0": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz#4d6691690ecdc9f5cb8c3ab170a1576c1f556371" + integrity sha512-7Q61bU+uEI7bCUFReT1NKn7/X6sDQsZ7wL1sJ9IYMAO7cI+eg6x9re1cEw2fCRMbbTVyoeUKWSV1M6azEfKCfg== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-runtime@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz#e27f78eb36f19448636e05c33c90fd9ad9b8bccf" @@ -1373,16 +1383,6 @@ resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-runtime@^7.2.0": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz#4d6691690ecdc9f5cb8c3ab170a1576c1f556371" - integrity sha512-7Q61bU+uEI7bCUFReT1NKn7/X6sDQsZ7wL1sJ9IYMAO7cI+eg6x9re1cEw2fCRMbbTVyoeUKWSV1M6azEfKCfg== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - resolve "^1.8.1" - semver "^5.5.1" - "@babel/plugin-transform-shorthand-properties@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" @@ -1840,67 +1840,28 @@ resolved "https://registry.yarnpkg.com/@ember-data/rfc395-data/-/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843" integrity sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ== -"@ember-decorators/argument@0.8.21": - version "0.8.21" - resolved "https://registry.yarnpkg.com/@ember-decorators/argument/-/argument-0.8.21.tgz#929789f9622ee935c3fad3332b3d179e98d05b15" - integrity sha512-WsNQMzlEEl7puxwC3yE6VUmRvAHdIbGOQJ+tYA4DXbZOAfagjCDxhz2Gxl0JVG7Sc87e6a2YAVZQr8CLDW8zJg== - dependencies: - babel-plugin-filter-imports "^1.1.1" - broccoli-funnel "^2.0.1" - ember-cli-babel "^6.17.0" - ember-cli-version-checker "^2.0.0" - ember-compatibility-helpers "^1.0.2" - ember-get-config "^0.2.3" - -"@ember-decorators/component@^2.5.1": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-2.5.2.tgz#54ceb0edbf8cc089b25174897639c5704532274f" - integrity sha512-2h795jBe25mycsskdxASO5CgYmwWJ1Nme1ZF2tB4FHJI/fCz5OCntJEe/fQjmvGMLaKZm7ipjEVCYomO6s7YrQ== - dependencies: - "@ember-decorators/utils" "^2.5.2" - ember-cli-babel "^6.6.0" - -"@ember-decorators/controller@^2.5.1": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-2.5.2.tgz#f74a537ba79d966b5bb1402f6407692c849ef9db" - integrity sha512-p2IeUZT9SEMYbvSnJO+wW74VNRwG7MCpOWqYfAbFOsAiIv3EYfUYQKIY1Ku4k603syfHvMqpHEkbYx8sZm23Fg== - dependencies: - "@ember-decorators/utils" "^2.5.2" - ember-cli-babel "^6.6.0" - -"@ember-decorators/data@^2.5.1": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-2.5.2.tgz#11411ccf2b94437ab3a6a23077cd39bd990ab334" - integrity sha512-eh1wcRfvejrTfN+McSB8NRmLFP2B19cSmNd51BqbmRwIhRHClO13Fd7tyBOWUtLRhDV/VigqyfDBaxWGTdSbcw== - dependencies: - "@ember-decorators/utils" "^2.5.2" - ember-cli-babel "^6.6.0" - -"@ember-decorators/object@^2.5.1": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-2.5.2.tgz#3f0d238212da13bda94a129964b47387ed90054c" - integrity sha512-9jV1a5D6gJ2eMQY9RP94YGWE+/zOA4+Sw8q49hlE5UIpyguSVHLhsdVvbWK+4WhRImKTr/tFwGU1cIJdVVJ5CQ== +"@ember-decorators/component@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-6.1.1.tgz#b360dc4fa8e576ee1c840879399ef1745fd96e06" + integrity sha512-Cj8tY/c0MC/rsipqsiWLh3YVN72DK92edPYamD/HzvftwzC6oDwawWk8RmStiBnG9PG/vntAt41l3S7HSSA+1Q== dependencies: - "@ember-decorators/utils" "^2.5.2" - ember-cli-babel "^6.6.0" - ember-compatibility-helpers "^1.0.0" + "@ember-decorators/utils" "^6.1.1" + ember-cli-babel "^7.1.3" -"@ember-decorators/service@^2.5.1": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-2.5.2.tgz#0ec93ca10f5e8baa8d93364c794de23a526e8493" - integrity sha512-Eb5xw5eYRewXfHUA6mc5ktWDQ0PVAs3rYffm/Q6KnV+mr92VWDm1GUlpm9C80TCxCeb22GJyRH9CSebkG/uB+g== +"@ember-decorators/object@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-6.1.1.tgz#50c922f5ac9af3ddd381cb6a43a031dfd9a70c7a" + integrity sha512-cb4CNR9sRoA31J3FCOFLDuR9ztM4wO9w1WlS4JeNRS7Z69SlB/XSXB/vplA3i9OOaXEy/zKWbu5ndZrHz0gvLw== dependencies: - "@ember-decorators/utils" "^2.5.2" - ember-cli-babel "^6.6.0" + "@ember-decorators/utils" "^6.1.1" + ember-cli-babel "^7.1.3" -"@ember-decorators/utils@^2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-2.5.2.tgz#656f30f099de597a8ccdd4cece390728930d37d3" - integrity sha512-pCn7epjk4kwJQ+d6m4ekIs9QxJKRShCFA7YDpyteNWW/I49ubIhuV8g95jz5I01/Q1j2KasSnCe7xt3mwHsMlA== +"@ember-decorators/utils@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-6.1.1.tgz#6b619814942b4fb3747cfa9f540c9f05283d7c5e" + integrity sha512-0KqnoeoLKb6AyoSU65TRF5T85wmS4uDn06oARddwNPxxf/lt5jQlh41uX3W7V/fWL9tPu8x1L1Vvpc80MN1+YA== dependencies: - babel-plugin-debug-macros "^0.1.11" - ember-cli-babel "^6.6.0" - ember-compatibility-helpers "^1.0.0" + ember-cli-babel "^7.1.3" "@ember/ordered-set@^2.0.3": version "2.0.3" @@ -2887,12 +2848,12 @@ babel-plugin-ember-data-packages-polyfill@^0.1.2: dependencies: "@ember-data/rfc395-data" "^0.0.4" -babel-plugin-ember-modules-api-polyfill@2.6.0, babel-plugin-ember-modules-api-polyfill@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" - integrity sha512-BSbLv3+ju1mcUUoPe7vPJgnGawrNxp6LfFBRHlNOKeMlQlml9Wo2MRRUrbpNDlmVc761xSKj8+cde7R0Lwpq7g== +babel-plugin-ember-modules-api-polyfill@2.9.0, babel-plugin-ember-modules-api-polyfill@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.9.0.tgz#8503e7b4192aeb336b00265e6235258ff6b754aa" + integrity sha512-c03h50291phJ2gQxo/aIOvFQE2c6glql1A7uagE3XbPXpKVAJOUxtVDjvWG6UAB6BC5ynsJfMWvY0w4TPRKIHQ== dependencies: - ember-rfc176-data "^0.3.6" + ember-rfc176-data "^0.3.9" babel-plugin-ember-modules-api-polyfill@^2.3.0: version "2.3.0" @@ -2908,6 +2869,13 @@ babel-plugin-ember-modules-api-polyfill@^2.5.0: dependencies: ember-rfc176-data "^0.3.5" +babel-plugin-ember-modules-api-polyfill@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" + integrity sha512-BSbLv3+ju1mcUUoPe7vPJgnGawrNxp6LfFBRHlNOKeMlQlml9Wo2MRRUrbpNDlmVc761xSKj8+cde7R0Lwpq7g== + dependencies: + ember-rfc176-data "^0.3.6" + babel-plugin-ember-modules-api-polyfill@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.8.0.tgz#70244800f750bf1c9f380910c1b2eed1db80ab4a" @@ -2915,13 +2883,6 @@ babel-plugin-ember-modules-api-polyfill@^2.8.0: dependencies: ember-rfc176-data "^0.3.8" -babel-plugin-ember-modules-api-polyfill@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.9.0.tgz#8503e7b4192aeb336b00265e6235258ff6b754aa" - integrity sha512-c03h50291phJ2gQxo/aIOvFQE2c6glql1A7uagE3XbPXpKVAJOUxtVDjvWG6UAB6BC5ynsJfMWvY0w4TPRKIHQ== - dependencies: - ember-rfc176-data "^0.3.9" - babel-plugin-ember-modules-api-polyfill@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-3.1.1.tgz#c6e9ede43b64c4e36512f260e42e829b071d9b4f" @@ -2942,14 +2903,6 @@ babel-plugin-filter-imports@2.0.4, babel-plugin-filter-imports@^2.0.4: "@babel/types" "^7.1.5" lodash "^4.17.11" -babel-plugin-filter-imports@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-1.1.2.tgz#c6e1f2685253bbda91b1dc5a6652ce825f771264" - integrity sha512-BpXJV3fndKEP1D9Yhwpz4NIjM/d1FYpdx4E4KmUPnTIFUxXNj0QEAY18MXVzEyYi2EWEVhoOG2CmclDfdMj5ew== - dependencies: - babel-types "^6.26.0" - lodash "^4.17.10" - babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" @@ -3584,14 +3537,6 @@ broccoli-debug@^0.6.5: symlink-or-copy "^1.1.8" tree-sync "^1.2.2" -broccoli-file-creator@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" - integrity sha512-l9zthHg6bAtnOfRr/ieZ1srRQEsufMZID7xGYRW3aBDv3u/3Eux+Iawl10tAGYE5pL9YB4n5X4vxkp6iNOoZ9g== - dependencies: - broccoli-plugin "^1.1.0" - mkdirp "^0.5.1" - broccoli-file-creator@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" @@ -5068,25 +5013,6 @@ ember-cli-babel-plugin-helpers@^1.0.0, ember-cli-babel-plugin-helpers@^1.1.0: resolved "https://registry.yarnpkg.com/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.1.0.tgz#de3baedd093163b6c2461f95964888c1676325ac" integrity sha512-Zr4my8Xn+CzO0gIuFNXji0eTRml5AxZUTDQz/wsNJ5AJAtyFWCY4QtKdoELNNbiCVGt1lq5yLiwTm4scGKu6xA== -ember-cli-babel@^6.0.0, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: - version "6.17.2" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.17.2.tgz#f0d53d2fb95e70c15d8db84760d045f88f458f69" - integrity sha512-9KcCvF1PcelEFTSiJ/Ld20tfuW9acMkwHC/xINLsmwqJVDbm3oEqWtiFDZ5ebaC278O5I0GqNJWJLYNoWMNZ8g== - dependencies: - amd-name-resolver "1.2.0" - babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.5.0" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.26.0" - babel-preset-env "^1.7.0" - broccoli-babel-transpiler "^6.5.0" - broccoli-debug "^0.6.4" - broccoli-funnel "^2.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.1.2" - semver "^5.5.0" - ember-cli-babel@^6.11.0: version "6.12.0" resolved "http://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" @@ -5106,7 +5032,26 @@ ember-cli-babel@^6.11.0: ember-cli-version-checker "^2.1.0" semver "^5.4.1" -ember-cli-babel@^6.16.0, ember-cli-babel@^6.17.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.9.0: +ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: + version "6.17.2" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.17.2.tgz#f0d53d2fb95e70c15d8db84760d045f88f458f69" + integrity sha512-9KcCvF1PcelEFTSiJ/Ld20tfuW9acMkwHC/xINLsmwqJVDbm3oEqWtiFDZ5ebaC278O5I0GqNJWJLYNoWMNZ8g== + dependencies: + amd-name-resolver "1.2.0" + babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-ember-modules-api-polyfill "^2.5.0" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.7.0" + broccoli-babel-transpiler "^6.5.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.2" + semver "^5.5.0" + +ember-cli-babel@^6.16.0, ember-cli-babel@^6.9.0: version "6.18.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" integrity sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA== @@ -5125,7 +5070,7 @@ ember-cli-babel@^6.16.0, ember-cli-babel@^6.17.0, ember-cli-babel@^6.3.0, ember- ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.4.2: +ember-cli-babel@^7.1.2, ember-cli-babel@^7.1.3, ember-cli-babel@^7.4.2: version "7.22.1" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.22.1.tgz#cad28b89cf0e184c93b863d09bc5ba4ce1d2e453" integrity sha512-kCT8WbC1AYFtyOpU23ESm22a+gL6fWv8Nzwe8QFQ5u0piJzM9MEudfbjADEaoyKTrjMQTDsrWwEf3yjggDsOng== @@ -5306,7 +5251,7 @@ ember-cli-version-checker@^4.1.0: semver "^6.3.0" silent-error "^1.1.1" -ember-compatibility-helpers@1.0.2, ember-compatibility-helpers@^1.0.0: +ember-compatibility-helpers@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" integrity sha512-pN1ezLiAM+uIKI4/BMp2hIBi6LQKxOedxKcu2mHDK+HEYuhlwki8Y2YwFSwb1w3c2YhesbkwaAJx/dvNHQGq5g== @@ -5315,19 +5260,19 @@ ember-compatibility-helpers@1.0.2, ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" - integrity sha512-yN163MzERpotO8M0b+q+kXs4i3Nx6aIriiZHWv+yXQzr2TAtYlVwg9V7/3+jcurOa3oDEYDpN7y9UZ6q3mnoTg== +ember-compatibility-helpers@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0.tgz#feee16c5e9ef1b1f1e53903b241740ad4b01097e" + integrity sha512-pUW4MzJdcaQtwGsErYmitFRs0rlCYBAnunVzlFFUBr4xhjlCjgHJo0b53gFnhTgenNM3d3/NqLarzRhDTjXRTg== dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0.tgz#feee16c5e9ef1b1f1e53903b241740ad4b01097e" - integrity sha512-pUW4MzJdcaQtwGsErYmitFRs0rlCYBAnunVzlFFUBr4xhjlCjgHJo0b53gFnhTgenNM3d3/NqLarzRhDTjXRTg== +ember-compatibility-helpers@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.1.tgz#87c92c4303f990ff455c28ca39fb3ee11441aa16" + integrity sha512-6wzYvnhg1ihQUT5yGqnLtleq3Nv5KNv79WhrEuNU9SwR4uIxCO+KpyC7r3d5VI0EM7/Nmv9Nd0yTkzmTMdVG1A== dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-version-checker "^2.1.1" @@ -5386,18 +5331,23 @@ ember-data@3.9.0: resolve "^1.8.1" silent-error "^1.1.1" -ember-decorators@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-2.5.1.tgz#a7057d46d210fb71ead71c2a83a21e14214ecb71" - integrity sha512-qKqGnkjZLX4UYQszEKocMAzoA/mP84lE6fRdvAvk28suKqvTPgbBQAtusbngXNbz448c3X2yXs0TJiwAZnSwIg== - dependencies: - "@ember-decorators/component" "^2.5.1" - "@ember-decorators/controller" "^2.5.1" - "@ember-decorators/data" "^2.5.1" - "@ember-decorators/object" "^2.5.1" - "@ember-decorators/service" "^2.5.1" - ember-cli-babel "^6.0.0" - semver "^5.5.0" +ember-decorators-polyfill@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/ember-decorators-polyfill/-/ember-decorators-polyfill-1.0.5.tgz#f42f6aea872a4f146536e9cad753b80bdae54db4" + integrity sha512-5fR+PIp52EwuhWHN3sosEX/GKuDx2UBaRh/pNZm7mUNHAvbIiUug/wl4EGTNK6316Wc+DTiFk2lnM2mn0Q1Msw== + dependencies: + ember-cli-babel "^7.1.2" + ember-cli-version-checker "^3.1.3" + ember-compatibility-helpers "^1.2.0" + +ember-decorators@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-6.1.1.tgz#6d770f8999cf5a413a1ee459afd520838c0fc470" + integrity sha512-63vZPntPn1aqMyeNRLoYjJD+8A8obd+c2iZkJflswpDRNVIsp2m7aQdSCtPt4G0U/TEq2251g+N10maHX3rnJQ== + dependencies: + "@ember-decorators/component" "^6.1.1" + "@ember-decorators/object" "^6.1.1" + ember-cli-babel "^7.7.3" ember-factory-for-polyfill@^1.3.1: version "1.3.1" @@ -5424,14 +5374,6 @@ ember-fetch@6.5.0, ember-fetch@^6.5.0: node-fetch "^2.3.0" whatwg-fetch "^3.0.0" -ember-get-config@^0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/ember-get-config/-/ember-get-config-0.2.4.tgz#118492a2a03d73e46004ed777928942021fe1ecd" - integrity sha1-EYSSoqA9c+RgBO13eSiUICH+Hs0= - dependencies: - broccoli-file-creator "^1.1.1" - ember-cli-babel "^6.3.0" - ember-getowner-polyfill@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ember-getowner-polyfill/-/ember-getowner-polyfill-2.2.0.tgz#38e7dccbcac69d5ec694000329ec0b2be651d2b2" From ef104aeb62bfeac79bdef149b13a66473f60bbe1 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Fri, 19 Apr 2019 09:32:20 +0200 Subject: [PATCH 08/34] refactor: fix custom ember-i18n `t` decorator --- src/web_modules/ember-i18n/decorator.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/web_modules/ember-i18n/decorator.js b/src/web_modules/ember-i18n/decorator.js index c137e6d6cf..a8d43d8ce7 100644 --- a/src/web_modules/ember-i18n/decorator.js +++ b/src/web_modules/ember-i18n/decorator.js @@ -1,5 +1,4 @@ import { get, computed } from "@ember/object"; -import { macro } from "@ember-decorators/object/computed"; function mapPropertiesByHash( object, hash ) { @@ -11,11 +10,13 @@ function mapPropertiesByHash( object, hash ) { } -export const t = macro( ( key, interpolations = {} ) => { - return computed( "i18n.locale", ...Object.values( interpolations ), function() { +export const t = function( key, interpolations = {} ) { + const values = Object.values( interpolations ); + + return computed( "i18n.locale", ...values, function() { /** @type {I18nService} */ const i18n = this.i18n; return i18n.t( key, mapPropertiesByHash( this, interpolations ) ); }); -}); +}; From 91fd5482aca69bc3eaf8f7b9d68568b244fc6791 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Fri, 19 Apr 2019 09:33:36 +0200 Subject: [PATCH 09/34] native classes: form components --- .../components/form/-input-btn/component.js | 42 ++++--- .../components/form/-selectable/component.js | 84 +++++++------ .../ui/components/form/check-box/component.js | 11 +- .../form/drop-down-list/component.js | 64 +++++----- .../form/drop-down-selection/component.js | 34 +++--- .../ui/components/form/drop-down/component.js | 59 +++++---- .../components/form/file-select/component.js | 58 +++++---- .../components/form/number-field/component.js | 113 +++++++++--------- .../form/radio-buttons-item/component.js | 13 +- .../form/radio-buttons/component.js | 26 ++-- .../components/form/text-field/component.js | 23 ++-- 11 files changed, 274 insertions(+), 253 deletions(-) diff --git a/src/app/ui/components/form/-input-btn/component.js b/src/app/ui/components/form/-input-btn/component.js index ba4d01958a..fc1609d993 100644 --- a/src/app/ui/components/form/-input-btn/component.js +++ b/src/app/ui/components/form/-input-btn/component.js @@ -2,21 +2,35 @@ import Component from "@ember/component"; import { set, computed } from "@ember/object"; import { or } from "@ember/object/computed"; import { scheduleOnce } from "@ember/runloop"; +import { attribute, className, classNames, layout, tagName } from "@ember-decorators/component"; import isFocused from "utils/is-focused"; -import layout from "./template.hbs"; +import template from "./template.hbs"; import "./styles.less"; -export default Component.extend({ - layout, +@layout( template ) +@tagName( "label" ) +@classNames( "input-btn-component" ) +export default class InputBtnComponent extends Component { + static positionalParams = [ "label" ]; - tagName: "label", - classNames: [ "input-btn-component" ], - classNameBindings: [ "checked", "disabled", "_blockOrLabel::no-label" ], - attributeBindings: [ "tabindex", "title" ], - tabindex: 0, + label; - _blockOrLabel: or( "hasBlock", "label" ), + @attribute + tabindex = 0; + + @attribute + title; + + @className + checked = false; + + @className + disabled = false; + + @or( "hasBlock", "label" ) + @className( "", "no-label" ) + _blockOrLabel; /** * Super dirty hack!!! @@ -25,11 +39,12 @@ export default Component.extend({ * use this computed property which (lazily) sets a (different) hasBlock property here * this computed property will be called in the template's hasBlock block */ - _setHasBlock: computed(function() { + @computed(function() { scheduleOnce( "afterRender", () => { set( this, "hasBlock", true ); }); - }), + }) + _setHasBlock; /** * @param {KeyboardEvent} event @@ -51,7 +66,4 @@ export default Component.extend({ return; } } - -}).reopenClass({ - positionalParams: [ "label" ] -}); +} diff --git a/src/app/ui/components/form/-selectable/component.js b/src/app/ui/components/form/-selectable/component.js index 6ed79850e5..60f87a0aa0 100644 --- a/src/app/ui/components/form/-selectable/component.js +++ b/src/app/ui/components/form/-selectable/component.js @@ -1,41 +1,43 @@ import Component from "@ember/component"; -import { get, set, observer } from "@ember/object"; +import { set } from "@ember/object"; import { addObserver, removeObserver } from "@ember/object/observers"; +import { observes, on } from "@ember-decorators/object"; -export default Component.extend({ - content: null, - selection: null, - value: null, - optionValuePath: "id", - optionLabelPath: "label", +const { hasOwnProperty } = {}; - _ignoreNextValueChange: false, - _selection: null, - _selectionValuePath: null, - _selectionValueObserver: null, - /** - * Find initial selection by the given value attribute - */ - init() { - this._super( ...arguments ); - this._setSelectionByValue(); - }, +export default class SelectableComponent extends Component { + /** @type {Object[]} */ + content = null; + /** @type {Object} */ + selection = null; + value = null; + optionValuePath = "id"; + optionLabelPath = "label"; + + _ignoreNextValueChange = false; + _selection = null; + _selectionValuePath = null; + /** @type {Function} */ + _selectionValueObserver = null; + /** * Clean up observers and caches on destruction + * Can't use an @on decorator here */ willDestroy() { - this._super( ...arguments ); + super.willDestroy( ...arguments ); this._removeSelectionValueObserver(); - }, + } /** * Watch value attribute and try to find a new selection */ - _valueObserver: observer( "value", function() { + @observes( "value" ) + _valueObserver() { // don't find a new selection if disabled if ( this._ignoreNextValueChange ) { this._ignoreNextValueChange = false; @@ -43,24 +45,25 @@ export default Component.extend({ } this._setSelectionByValue(); - }), + } /** * Reset selection value observer if a new selection has been set */ - _selectionObserver: observer( "selection", function() { + @observes( "selection" ) + _selectionObserver() { this._removeSelectionValueObserver(); this._addSelectionValueObserver(); - }), + } /** * Watch changes being made to the content: * - Try to find a selection if there currently is none * - Unset the selection and value attributes if the selection has been removed from the content */ - _contentObserver: observer( "content.[]", function() { - const content = get( this, "content" ); - const selection = get( this, "selection" ); + @observes( "content.[]" ) + _contentObserver() { + const selection = this.selection; if ( !selection ) { // no selection: check for matching value (in case a new item has been added) @@ -68,29 +71,32 @@ export default Component.extend({ } else { // has the current selection been removed from the content list? - if ( !content.includes( selection ) ) { + if ( !this.content.includes( selection ) ) { set( this, "selection", null ); this._ignoreNextValueChange = true; set( this, "value", null ); } } - }), + } /** * Find selection by value and update selection attribute * Will trigger the selection observer if a new selection has been found */ + @on( "init" ) _setSelectionByValue() { - const content = get( this, "content" ); - const value = get( this, "value" ); - const optionValuePath = get( this, "optionValuePath" ); - const selection = content.findBy( optionValuePath, value ); + const value = this.value; + const optionValuePath = this.optionValuePath; + const selection = this.content.find( item => + hasOwnProperty.call( item, optionValuePath ) + && item[ optionValuePath ] === value + ); if ( selection !== undefined ) { set( this, "selection", selection ); } - }, + } /** * Remove old selection value observer @@ -105,18 +111,18 @@ export default Component.extend({ this._selectionValueObserver ); this._selection = this._selectionValuePath = this._selectionValueObserver = null; - }, + } /** * Add new selection value observer and execute it to update value attribute */ _addSelectionValueObserver() { - const selection = get( this, "selection" ); + const selection = this.selection; if ( !selection ) { return; } - const optionValuePath = get( this, "optionValuePath" ); + const { optionValuePath } = this; const selectionValueObserver = () => { - const value = get( selection, optionValuePath ); + const value = selection[ optionValuePath ]; set( this, "value", value ); }; @@ -133,4 +139,4 @@ export default Component.extend({ this._selectionValueObserver(); } -}); +} diff --git a/src/app/ui/components/form/check-box/component.js b/src/app/ui/components/form/check-box/component.js index eddad89a30..ef523dcda4 100644 --- a/src/app/ui/components/form/check-box/component.js +++ b/src/app/ui/components/form/check-box/component.js @@ -1,12 +1,11 @@ -import { get } from "@ember/object"; +import { classNames } from "@ember-decorators/component"; import InputBtnComponent from "../-input-btn/component"; -export default InputBtnComponent.extend({ - classNames: [ "check-box-component" ], - +@classNames( "check-box-component" ) +export default class CheckBoxComponent extends InputBtnComponent { click() { - if ( get( this, "disabled" ) ) { return; } + if ( this.disabled ) { return; } this.toggleProperty( "checked" ); } -}); +} diff --git a/src/app/ui/components/form/drop-down-list/component.js b/src/app/ui/components/form/drop-down-list/component.js index 61fb5f2856..04eaac393b 100644 --- a/src/app/ui/components/form/drop-down-list/component.js +++ b/src/app/ui/components/form/drop-down-list/component.js @@ -1,35 +1,29 @@ import Component from "@ember/component"; -import { get, set, setProperties, observer } from "@ember/object"; +import { set, setProperties, action } from "@ember/object"; import { scheduleOnce } from "@ember/runloop"; -import layout from "./template.hbs"; +import { className, classNames, layout, tagName } from "@ember-decorators/component"; +import { observes, on } from "@ember-decorators/object"; +import template from "./template.hbs"; -export default Component.extend({ - layout, +@layout( template ) +@tagName( "ui" ) +@classNames( "drop-down-list-component" ) +export default class DropDownListComponent extends Component { + @className + class = ""; + @className + expanded = false; + @className( "expanded-upwards" ) + upwards = false; - tagName: "ul", - classNames: [ "drop-down-list-component" ], - classNameBindings: [ - "expanded:expanded", - "upwards:expanded-upwards", - "class" - ], - expanded: false, - upwards: false, - - - willDestroyElement() { - this._removeClickListener(); - this._super( ...arguments ); - }, - - - _expandedObserver: observer( "expanded", function() { + @observes( "expanded" ) + _expandedObserver() { // always remove click listener this._removeClickListener(); - if ( !get( this, "expanded" ) ) { + if ( !this.expanded ) { return; } @@ -47,15 +41,16 @@ export default Component.extend({ } }; this.element.ownerDocument.body.addEventListener( "click", this._clickListener ); - }), + } + @on( "willDestroyElement" ) _removeClickListener() { // unregister click event listener if ( this._clickListener ) { this.element.ownerDocument.body.removeEventListener( "click", this._clickListener ); this._clickListener = null; } - }, + } _calcExpansionDirection() { const element = this.element; @@ -66,16 +61,15 @@ export default Component.extend({ const listHeight = element.offsetHeight + parseInt( marginTop ) + parseInt( marginBottom ); const isOverflowing = parentHeight - positionTop < listHeight; set( this, "upwards", isOverflowing ); - }, + } - actions: { - change( item ) { - if ( get( this, "disabled" ) ) { return; } - setProperties( this, { - expanded: false, - selection: item - }); - } + @action + change( item ) { + if ( this.disabled ) { return; } + setProperties( this, { + expanded: false, + selection: item + }); } -}); +} diff --git a/src/app/ui/components/form/drop-down-selection/component.js b/src/app/ui/components/form/drop-down-selection/component.js index 639ab0dad9..7b56d3e422 100644 --- a/src/app/ui/components/form/drop-down-selection/component.js +++ b/src/app/ui/components/form/drop-down-selection/component.js @@ -1,31 +1,35 @@ import Component from "@ember/component"; -import { get } from "@ember/object"; import { inject as service } from "@ember/service"; -import { translationMacro as t } from "ember-i18n/addon"; -import layout from "./template.hbs"; +import { className, classNames, layout, tagName } from "@ember-decorators/component"; +import { t } from "ember-i18n/decorator"; +import template from "./template.hbs"; -export default Component.extend({ - i18n: service(), +@layout( template ) +@tagName( "div" ) +@classNames( "drop-down-selection-component" ) +export default class DropDownSelectionComponent extends Component { + /** @type {I18nService} */ + @service i18n; - layout, + @className + class = ""; - tagName: "div", - classNames: [ "drop-down-selection-component" ], - classNameBindings: [ "class" ], + @t( "components.drop-down-selection.placeholder" ) + _defaultPlaceholder; - _defaultPlaceholder: t( "components.drop-down-selection.placeholder" ), - _placeholder: null, + _placeholder = null; get placeholder() { return this._placeholder || this._defaultPlaceholder; - }, + } set placeholder( value ) { this._placeholder = value; - }, + } click() { - get( this, "action" )(); + this.action(); + return false; } -}); +} diff --git a/src/app/ui/components/form/drop-down/component.js b/src/app/ui/components/form/drop-down/component.js index 87e50b1ca7..3948abe8be 100644 --- a/src/app/ui/components/form/drop-down/component.js +++ b/src/app/ui/components/form/drop-down/component.js @@ -1,25 +1,24 @@ -import { get, set } from "@ember/object"; -import Selectable from "../-selectable/component"; +import { set, action } from "@ember/object"; +import { attribute, className, classNames, layout, tagName } from "@ember-decorators/component"; +import SelectableComponent from "../-selectable/component"; import isFocused from "utils/is-focused"; -import layout from "./template.hbs"; +import template from "./template.hbs"; import "./styles.less"; -export default Selectable.extend({ - layout, +@layout( template ) +@tagName( "div" ) +@classNames( "drop-down-component" ) +export default class DropDownComponent extends SelectableComponent { + @className + class = ""; + @className + disabled = false; - tagName: "div", - classNames: [ "drop-down-component" ], - classNameBindings: [ - "disabled:disabled", - "class" - ], - attributeBindings: [ "tabindex" ], - tabindex: 0, - - disabled: false, - expanded: false, + @attribute + tabindex = 0; + expanded = false; /** * @param {KeyboardEvent} event @@ -28,7 +27,7 @@ export default Selectable.extend({ switch ( event.key ) { case "Escape": case "Backspace": - if ( get( this, "expanded" ) ) { + if ( this.expanded ) { set( this, "expanded", false ); return false; } @@ -51,16 +50,15 @@ export default Selectable.extend({ case "ArrowDown": return this._switchSelectionOnArrowKey( 1 ); } - }, + } _switchSelectionOnArrowKey( change ) { - if ( !get( this, "expanded" ) || !isFocused( this.element ) ) { + if ( !this.expanded || !isFocused( this.element ) ) { return; } - const content = get( this, "content" ); - const selection = get( this, "selection" ); - const selIndex = content.indexOf( selection ); + const content = this.content; + const selIndex = content.indexOf( this.selection ); if ( selIndex === -1 ) { return; } @@ -70,16 +68,15 @@ export default Selectable.extend({ set( this, "selection", newSelection ); return false; - }, + } - actions: { - toggle() { - if ( get( this, "disabled" ) ) { - set( this, "expanded", false ); - } else { - this.toggleProperty( "expanded" ); - } + @action + toggle() { + if ( this.disabled ) { + set( this, "expanded", false ); + } else { + this.toggleProperty( "expanded" ); } } -}); +} diff --git a/src/app/ui/components/form/file-select/component.js b/src/app/ui/components/form/file-select/component.js index 5d493b0e94..244f107952 100644 --- a/src/app/ui/components/form/file-select/component.js +++ b/src/app/ui/components/form/file-select/component.js @@ -1,33 +1,38 @@ import Component from "@ember/component"; -import { set } from "@ember/object"; -import { on } from "@ember/object/evented"; +import { set, action } from "@ember/object"; import { inject as service } from "@ember/service"; -import { translationMacro as t } from "ember-i18n/addon"; +import { classNames, layout, tagName } from "@ember-decorators/component"; +import { on } from "@ember-decorators/object"; +import { t } from "ember-i18n/decorator"; import { platform } from "utils/node/platform"; -import layout from "./template.hbs"; +import template from "./template.hbs"; const { hasOwnProperty } = {}; const { isArray } = Array; -export default Component.extend({ - i18n: service(), +@layout( template ) +@tagName( "div" ) +@classNames( "file-select-component", "input-group" ) +export default class FileSelectComponent extends Component { + /** {I18nService} */ + @service i18n; - layout, + value = ""; + disabled = false; - tagName: "div", - classNames: [ "input-group" ], + /** @type {HTMLInputElement} */ + _input = null; - value: "", - disabled: false, + @t( "components.file-select.placeholder" ) + _defaultPlaceholder; - _defaultPlaceholder: t( "components.file-select.placeholder" ), - _placeholder: null, + _placeholder = null; get placeholder() { return this._placeholder || this._defaultPlaceholder; - }, + } set placeholder( value ) { if ( typeof value === "string" ) { this._placeholder = value; @@ -39,9 +44,11 @@ export default Component.extend({ ? value[ 0 ] : value; } - }, + } - _createInput: on( "didInsertElement", function() { + + @on( "didInsertElement" ) + _createInputElement() { const input = this.element.ownerDocument.createElement( "input" ); input.classList.add( "hidden" ); input.setAttribute( "type", "file" ); @@ -52,13 +59,18 @@ export default Component.extend({ input.files.clear(); }); this._input = input; - }), + } + + @on( "willDestroyElement" ) + _destroyInputElement() { + this._input = null; + } + - actions: { - selectfile() { - if ( !this.disabled ) { - this._input.dispatchEvent( new MouseEvent( "click", { bubbles: true } ) ); - } + @action + selectfile() { + if ( !this.disabled ) { + this._input.dispatchEvent( new MouseEvent( "click", { bubbles: true } ) ); } } -}); +} diff --git a/src/app/ui/components/form/number-field/component.js b/src/app/ui/components/form/number-field/component.js index d8b3459a12..8351cd02e8 100644 --- a/src/app/ui/components/form/number-field/component.js +++ b/src/app/ui/components/form/number-field/component.js @@ -1,7 +1,8 @@ import Component from "@ember/component"; -import { get, set } from "@ember/object"; -import { on } from "@ember/object/evented"; -import layout from "./template.hbs"; +import { set, action } from "@ember/object"; +import { classNames, layout, tagName } from "@ember-decorators/component"; +import { on } from "@ember-decorators/object"; +import template from "./template.hbs"; import "./styles.less"; @@ -9,33 +10,34 @@ const { min, max } = Math; const { isNaN, isInteger, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER } = Number; -export default Component.extend({ - layout, +@layout( template ) +@tagName( "div" ) +@classNames( "number-field-component" ) +export default class NumberFieldComponent extends Component { + /** @type {number|null} */ + value = null; + /** @type {number|null} */ + defaultValue = null; + disabled = false; + min = MIN_SAFE_INTEGER; + max = MAX_SAFE_INTEGER; - tagName: "div", - classNames: [ "number-field-component" ], + _prevValue = null; + _value = null; - value: null, - defaultValue: null, - disabled: false, - min: MIN_SAFE_INTEGER, - max: MAX_SAFE_INTEGER, - _prevValue: null, - _value: null, - - _update: on( "init", "didReceiveAttrs", function() { - this._super( ...arguments ); - const value = get( this, "value" ); + @on( "init", "didReceiveAttrs" ) + _update() { + const value = this.value; const parsedValue = this._parse( value ); this._prevValue = value; set( this, "_value", String( parsedValue ) ); - }), + } - didInsertElement() { - this._super( ...arguments ); + @on( "didInsertElement" ) + _getInputElement() { this._input = this.element.querySelector( "input" ); - }, + } _parse( value ) { let numValue = Number( value ); @@ -43,19 +45,18 @@ export default Component.extend({ // is the new value not a number? if ( isNaN( numValue ) ) { // use previous value if it exists - const prevValue = this._prevValue; + const { _prevValue: prevValue } = this; if ( prevValue !== null && !isNaN( Number( prevValue ) ) ) { return prevValue; } // otherwise, get the default value - const defaultValue = get( this, "defaultValue" ); + const { defaultValue } = this; if ( defaultValue !== null && !isNaN( Number( defaultValue ) ) ) { return defaultValue; } - const min = get( this, "min" ); - const max = get( this, "max" ); + const { min, max } = this; // or the average of min and max values if no default value exists either return ( ( min / 2 ) + ( max / 2 ) ) >> 0; @@ -66,41 +67,37 @@ export default Component.extend({ numValue = numValue >> 0; } - const min = get( this, "min" ); - const max = get( this, "max" ); + const { min, max } = this; // maximum and minimum return numValue <= max ? numValue >= min - ? numValue - : min + ? numValue + : min : max; - }, - - - actions: { - increase() { - if ( get( this, "disabled" ) ) { return; } - const maxValue = get( this, "max" ); - const currentValue = get( this, "value" ); - const value = min( currentValue + 1, maxValue ); - this.attrs.value.update( value ); - }, - - decrease() { - if ( get( this, "disabled" ) ) { return; } - const minValue = get( this, "min" ); - const currentValue = get( this, "value" ); - const value = max( currentValue - 1, minValue ); - this.attrs.value.update( value ); - }, - - blur() { - if ( get( this, "disabled" ) ) { return; } - const inputValue = this._input.value; - const value = this._parse( inputValue ); - this._input.value = String( value ); - this.attrs.value.update( value ); - } } -}); + + + @action + increase() { + if ( this.disabled ) { return; } + const newValue = min( this.value + 1, this.max ); + set( this, "value", newValue ); + } + + @action + decrease() { + if ( this.disabled ) { return; } + const newValue = max( this.value - 1, this.min ); + set( this, "value", newValue ); + } + + @action + blur() { + if ( this.disabled ) { return; } + const inputValue = this._input.value; + const newValue = this._parse( inputValue ); + this._input.value = String( newValue ); + set( this, "value", newValue ); + } +} diff --git a/src/app/ui/components/form/radio-buttons-item/component.js b/src/app/ui/components/form/radio-buttons-item/component.js index 6eb83d104e..5588fa27b4 100644 --- a/src/app/ui/components/form/radio-buttons-item/component.js +++ b/src/app/ui/components/form/radio-buttons-item/component.js @@ -1,12 +1,11 @@ -import { get } from "@ember/object"; +import { classNames } from "@ember-decorators/component"; import InputBtnComponent from "../-input-btn/component"; -export default InputBtnComponent.extend({ - classNames: [ "radio-buttons-item-component" ], - +@classNames( "radio-buttons-item-component" ) +export default class RadioButtonsItemComponent extends InputBtnComponent { click() { - if ( get( this, "disabled" ) ) { return; } - get( this, "action" )(); + if ( this.disabled ) { return; } + this.action(); } -}); +} diff --git a/src/app/ui/components/form/radio-buttons/component.js b/src/app/ui/components/form/radio-buttons/component.js index a2ba75cab8..bdbd1a687a 100644 --- a/src/app/ui/components/form/radio-buttons/component.js +++ b/src/app/ui/components/form/radio-buttons/component.js @@ -1,18 +1,16 @@ -import { set } from "@ember/object"; -import Selectable from "../-selectable/component"; -import layout from "./template.hbs"; +import { set, action } from "@ember/object"; +import { classNames, layout, tagName } from "@ember-decorators/component"; +import SelectableComponent from "../-selectable/component"; +import template from "./template.hbs"; import "./styles.less"; -export default Selectable.extend({ - layout, - - tagName: "div", - classNames: [ "radio-buttons-component" ], - - actions: { - change( item ) { - set( this, "selection", item ); - } +@layout( template ) +@tagName( "div" ) +@classNames( "radio-buttons-component" ) +export default class RadioButtonsComponent extends SelectableComponent { + @action + change( item ) { + set( this, "selection", item ); } -}); +} diff --git a/src/app/ui/components/form/text-field/component.js b/src/app/ui/components/form/text-field/component.js index 8709e8a4f7..8280373e82 100644 --- a/src/app/ui/components/form/text-field/component.js +++ b/src/app/ui/components/form/text-field/component.js @@ -1,18 +1,21 @@ import TextField from "@ember/component/text-field"; import { inject as service } from "@ember/service"; +import { attribute } from "@ember-decorators/component"; import t from "translation-key"; -export default TextField.extend({ +export default class TextFieldComponent extends TextField { /** @type {NwjsService} */ - nwjs: service(), + @service nwjs; - attributeBindings: [ "autoselect:data-selectable" ], + @attribute( "data-selectable" ) + autoselect = false; - autoselect: false, + autofocus = false; + noContextmenu = false; contextMenu( event ) { - if ( this.attrs.noContextmenu ) { return; } + if ( this.noContextmenu ) { return; } const element = this.element; const start = element.selectionStart; @@ -42,13 +45,13 @@ export default TextField.extend({ } } ]); - }, + } focusIn() { - if ( !this.attrs.autofocus || !this.attrs.autoselect ) { return; } + if ( !this.autofocus || !this.autoselect ) { return; } this.element.setSelectionRange( 0, this.element.value.length ); - }, + } /** * @param {KeyboardEvent} event @@ -59,6 +62,6 @@ export default TextField.extend({ return; } - return this._super( ...arguments ); + return super.keyDown( ...arguments ); } -}); +} From 7aec98fd711ad5511c98a461013cce3cdc685584 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 02:27:26 +0200 Subject: [PATCH 10/34] native classes: PolymorphicFragmentSerializer --- .../polymorphic-fragment-serializer.js | 10 +++++----- .../models/settings/chat/provider/serializer.js | 13 +++++++------ .../models/settings/hotkeys/namespace/serializer.js | 13 +++++++------ .../models/settings/streaming/player/serializer.js | 13 +++++++------ 4 files changed, 26 insertions(+), 23 deletions(-) rename src/app/data/models/{-mixins => -serializers}/polymorphic-fragment-serializer.js (80%) diff --git a/src/app/data/models/-mixins/polymorphic-fragment-serializer.js b/src/app/data/models/-serializers/polymorphic-fragment-serializer.js similarity index 80% rename from src/app/data/models/-mixins/polymorphic-fragment-serializer.js rename to src/app/data/models/-serializers/polymorphic-fragment-serializer.js index fc521aa877..03d3b08efb 100644 --- a/src/app/data/models/-mixins/polymorphic-fragment-serializer.js +++ b/src/app/data/models/-serializers/polymorphic-fragment-serializer.js @@ -4,14 +4,14 @@ import JSONSerializer from "ember-data/serializers/json"; const { hasOwnProperty } = {}; -export default JSONSerializer.extend({ +export default class PolymorphicFragmentSerializer extends JSONSerializer { /** * @param {Snapshot} snapshot * @param {Model} snapshot.record * @returns {Object} */ serialize({ record }) { - const json = this._super( ...arguments ); + const json = super.serialize( ...arguments ); const { models, modelBaseName, typeKey } = this; for ( const [ type, model ] of models ) { @@ -22,7 +22,7 @@ export default JSONSerializer.extend({ } return json; - }, + } /** * Fix removal of the `typeKey` property @@ -32,11 +32,11 @@ export default JSONSerializer.extend({ */ extractAttributes( modelClass, data ) { const { typeKey } = this; - const attributes = this._super( ...arguments ); + const attributes = super.extractAttributes( ...arguments ); if ( data && hasOwnProperty.call( data, typeKey ) ) { attributes[ typeKey ] = data[ typeKey ]; } return attributes; } -}); +} diff --git a/src/app/data/models/settings/chat/provider/serializer.js b/src/app/data/models/settings/chat/provider/serializer.js index 742c835d66..67e0d6870e 100644 --- a/src/app/data/models/settings/chat/provider/serializer.js +++ b/src/app/data/models/settings/chat/provider/serializer.js @@ -1,9 +1,10 @@ -import PolymorphicFragmentSerializer from "data/models/-mixins/polymorphic-fragment-serializer"; +import PolymorphicFragmentSerializer + from "data/models/-serializers/polymorphic-fragment-serializer"; import { providers, typeKey } from "./fragment"; -export default PolymorphicFragmentSerializer.extend({ - models: providers, - modelBaseName: "settings-chat-provider", - typeKey -}); +export default class SettingsChatProviderSerializer extends PolymorphicFragmentSerializer { + models = providers; + modelBaseName = "settings-chat-provider"; + typeKey = typeKey; +} diff --git a/src/app/data/models/settings/hotkeys/namespace/serializer.js b/src/app/data/models/settings/hotkeys/namespace/serializer.js index 8ec46fa45a..9c67ef3e6a 100644 --- a/src/app/data/models/settings/hotkeys/namespace/serializer.js +++ b/src/app/data/models/settings/hotkeys/namespace/serializer.js @@ -1,9 +1,10 @@ -import PolymorphicFragmentSerializer from "data/models/-mixins/polymorphic-fragment-serializer"; +import PolymorphicFragmentSerializer + from "data/models/-serializers/polymorphic-fragment-serializer"; import { namespaces, typeKey } from "./fragment"; -export default PolymorphicFragmentSerializer.extend({ - models: namespaces, - modelBaseName: "settings-hotkeys-namespace", - typeKey -}); +export default class SettingsHotkeysNamespaceSerializer extends PolymorphicFragmentSerializer { + models = namespaces; + modelBaseName = "settings-hotkeys-namespace"; + typeKey = typeKey; +} diff --git a/src/app/data/models/settings/streaming/player/serializer.js b/src/app/data/models/settings/streaming/player/serializer.js index fc29a93369..3f09bce641 100644 --- a/src/app/data/models/settings/streaming/player/serializer.js +++ b/src/app/data/models/settings/streaming/player/serializer.js @@ -1,9 +1,10 @@ -import PolymorphicFragmentSerializer from "data/models/-mixins/polymorphic-fragment-serializer"; +import PolymorphicFragmentSerializer + from "data/models/-serializers/polymorphic-fragment-serializer"; import { players, typeKey } from "./fragment"; -export default PolymorphicFragmentSerializer.extend({ - models: players, - modelBaseName: "settings-streaming-player", - typeKey -}); +export default class SettingsStreamingPlayerSerializer extends PolymorphicFragmentSerializer { + models = players; + modelBaseName = "settings-streaming-player"; + typeKey = typeKey; +} From 077721f405384107185b3731c8f8eba5f4db6e97 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:01:32 +0200 Subject: [PATCH 11/34] native classes: CustomRESTAdapter - turn AdapterMixin into CustomRESTAdapter that extends from RESTAdapter - make TwitchAdapter extend from that class - make the adapter's urlFragments and headers objects static - add custom decorators for property descriptors and urlFragments --- .../adapter.js => -adapters/custom-rest.js} | 147 +++--- .../data/models/github/releases/adapter.js | 13 +- src/app/data/models/twitch/adapter.js | 95 ++-- src/app/data/models/twitch/stream/adapter.js | 8 +- src/app/data/models/twitch/team/adapter.js | 8 +- src/app/data/models/twitch/user/adapter.js | 16 +- src/app/utils/decorators.js | 11 + src/test/tests/data/models/twitch/adapter.js | 483 ++++++++---------- src/test/tests/services/auth.js | 25 +- .../tests/services/notification/follow.js | 6 +- 10 files changed, 379 insertions(+), 433 deletions(-) rename src/app/data/models/{-mixins/adapter.js => -adapters/custom-rest.js} (67%) create mode 100644 src/app/utils/decorators.js diff --git a/src/app/data/models/-mixins/adapter.js b/src/app/data/models/-adapters/custom-rest.js similarity index 67% rename from src/app/data/models/-mixins/adapter.js rename to src/app/data/models/-adapters/custom-rest.js index 05e0f420aa..8a6b439ec6 100644 --- a/src/app/data/models/-mixins/adapter.js +++ b/src/app/data/models/-adapters/custom-rest.js @@ -1,118 +1,115 @@ -import { get } from "@ember/object"; import Evented from "@ember/object/evented"; -import Mixin from "@ember/object/mixin"; -import { isNone } from "@ember/utils"; +import RESTAdapter from "ember-data/adapters/rest"; import { AdapterError, InvalidError, TimeoutError } from "ember-data/adapters/errors"; import fetch from "fetch"; +import { descriptor, urlFragments } from "utils/decorators"; const reURL = /^[a-z]+:\/\/([\w.]+)\/(.+)$/i; const reURLFragment = /^:(\w+)$/; +const { hasOwnProperty } = {}; + +@urlFragments({ + id( type, id ) { + if ( id === null || id === undefined ) { + throw new Error( "Unknown ID" ); + } + + return id; + } +}) /** - * Adapter mixin for using static model names + * Adapter for using static model names * instead of using type.modelName as name + * TODO: Change this and get the URL from the model's adapter instead of the model's toString(). + * EmberData has added a more dynamic system for configuring request URLs a long time ago... */ -export default Mixin.create( Evented, { - mergedProperties: [ "urlFragments" ], +export default class CustomRESTAdapter extends RESTAdapter.extend( Evented ) { + @descriptor({ value: true }) + useFetch; - useFetch: true, - - urlFragments: { - id( type, id ) { - if ( isNone( id ) ) { - throw new Error( "Unknown ID" ); - } - - return id; - } - }, findRecord( store, type, id, snapshot ) { const url = this.buildURL( type, id, snapshot, "findRecord" ); return this.ajax( url, "GET" ); - }, + } findAll( store, type, sinceToken ) { const url = this.buildURL( type, null, null, "findAll" ); const query = sinceToken ? { since: sinceToken } : undefined; return this.ajax( url, "GET", { data: query } ); - }, + } query( store, type, query ) { const url = this.buildURL( type, null, null, "query", query ); query = this.sortQueryParams ? this.sortQueryParams( query ) : query; return this.ajax( url, "GET", { data: query } ); - }, + } queryRecord( store, type, query ) { const url = this.buildURL( type, null, null, "queryRecord", query ); query = this.sortQueryParams ? this.sortQueryParams( query ) : query; return this.ajax( url, "GET", { data: query } ); - }, + } - createRecordMethod: "POST", - createRecord( store, type, snapshot ) { + createRecordMethod = "POST"; + async createRecord( store, type, snapshot ) { const url = this.buildURL( type, null, snapshot, "createRecord" ); - const method = get( this, "createRecordMethod" ); const data = this.createRecordData( store, type, snapshot ); - return this.ajax( url, method, data ) - .then( data => { - this.trigger( "createRecord", store, type, snapshot ); - return data; - }); - }, + const payload = await this.ajax( url, this.createRecordMethod, data ); + this.trigger( "createRecord", store, type, snapshot ); + + return payload; + } createRecordData( store, type, snapshot ) { const data = {}; const serializer = store.serializerFor( type.modelName ); serializer.serializeIntoHash( data, type, snapshot, { includeId: true } ); return { data: data }; - }, + } - updateRecordMethod: "PUT", - updateRecord( store, type, snapshot ) { + updateRecordMethod = "PUT"; + async updateRecord( store, type, snapshot ) { const url = this.buildURL( type, snapshot.id, snapshot, "updateRecord" ); - const method = get( this, "updateRecordMethod" ); const data = this.updateRecordData( store, type, snapshot ); - return this.ajax( url, method, data ) - .then( data => { - this.trigger( "updateRecord", store, type, snapshot ); - return data; - }); - }, + const payload = await this.ajax( url, this.updateRecordMethod, data ); + this.trigger( "updateRecord", store, type, snapshot ); + + return payload; + } updateRecordData( store, type, snapshot ) { const data = {}; const serializer = store.serializerFor( type.modelName ); serializer.serializeIntoHash( data, type, snapshot ); return { data: data }; - }, + } - deleteRecord( store, type, snapshot ) { + async deleteRecord( store, type, snapshot ) { const url = this.buildURL( type, snapshot.id, snapshot, "deleteRecord" ); - return this.ajax( url, "DELETE" ) - .then( data => { - this.trigger( "deleteRecord", store, type, snapshot ); - return data; - }); - }, + const payload = await this.ajax( url, "DELETE" ); + this.trigger( "deleteRecord", store, type, snapshot ); + + return payload; + } urlForCreateRecord( modelName, snapshot ) { // Why does Ember-Data do this? // the id is missing on BuildURLMixin.urlForCreateRecord return this._buildURL( modelName, snapshot.id ); - }, + } /** * Custom buildURL method with type instead of modelName @@ -122,17 +119,16 @@ export default Mixin.create( Evented, { * @returns {String} */ _buildURL( type, id, data ) { - const host = get( this, "host" ); - const ns = get( this, "namespace" ); + const { host, namespace } = this; const url = [ host ]; // append the adapter specific namespace - if ( ns ) { url.push( ns ); } + if ( namespace ) { url.push( namespace ); } // append the type fragments (and process the dynamic ones) url.push( ...this.buildURLFragments( type, id, data ) ); return url.join( "/" ); - }, + } /** * Dynamic URL fragments @@ -142,7 +138,7 @@ export default Mixin.create( Evented, { * @returns {String[]} */ buildURLFragments( type, id, data ) { - const urlFragments = get( this, "urlFragments" ); + const urlFragments = this.constructor.urlFragments; let idFound = false; const url = String( type ) @@ -152,7 +148,7 @@ export default Mixin.create( Evented, { idFound = true; } - if ( urlFragments.hasOwnProperty( key ) ) { + if ( hasOwnProperty.call( urlFragments, key ) ) { return urlFragments[ key ].call( this, type, id, data ); } @@ -161,33 +157,35 @@ export default Mixin.create( Evented, { }) ); // append ID if no :id fragment was defined and ID exists - if ( !idFound && !isNone( id ) ) { + if ( !idFound && id !== null && id !== undefined ) { url.push( id ); } return url; - }, + } - ajax( url ) { - return this._super( ...arguments ) - .catch( err => { - if ( err instanceof AdapterError ) { - const _url = reURL.exec( url ); - err.host = _url && _url[1] || get( this, "host" ); - err.path = _url && _url[2] || get( this, "namespace" ); - } + async ajax( url ) { + try { + return await super.ajax( ...arguments ); - return Promise.reject( err ); - }); - }, + } catch ( err ) { + if ( err instanceof AdapterError ) { + const _url = reURL.exec( url ); + err.host = _url && _url[1] || this.host; + err.path = _url && _url[2] || this.namespace; + } + + throw err; + } + } ajaxOptions() { - const options = this._super( ...arguments ); + const options = super.ajaxOptions( ...arguments ); options.cache = "no-cache"; return options; - }, + } _fetchRequest( options ) { return new Promise( ( resolve, reject ) => { @@ -199,12 +197,12 @@ export default Mixin.create( Evented, { .finally( () => clearTimeout( timeout ) ) .then( resolve, reject ); }); - }, + } isSuccess( status, headers, payload ) { - return this._super( ...arguments ) + return super.isSuccess( ...arguments ) && ( payload ? !payload.error : true ); - }, + } handleResponse( status, headers, payload ) { if ( this.isSuccess( status, headers, payload ) ) { @@ -220,5 +218,4 @@ export default Mixin.create( Evented, { status }]); } - -}); +} diff --git a/src/app/data/models/github/releases/adapter.js b/src/app/data/models/github/releases/adapter.js index 3d0584d5be..4db2c68158 100644 --- a/src/app/data/models/github/releases/adapter.js +++ b/src/app/data/models/github/releases/adapter.js @@ -1,22 +1,21 @@ -import RESTAdapter from "ember-data/adapters/rest"; import { update as updateConfig } from "config"; -import AdapterMixin from "data/models/-mixins/adapter"; +import CustomRESTAdapter from "data/models/-adapters/custom-rest"; const { githubreleases: { host, namespace } } = updateConfig; -export default RESTAdapter.extend( AdapterMixin, { - host, - namespace, +export default class GithubReleasesAdapter extends CustomRESTAdapter { + host = host; + namespace = namespace; queryRecord( store, type, query ) { const url = this.buildURL( type, null, null, "queryRecord", query ); return this.ajax( url, "GET", { data: {} } ); - }, + } urlForQueryRecord( query, modelName ) { return this._buildURL( modelName, query ); } -}); +} diff --git a/src/app/data/models/twitch/adapter.js b/src/app/data/models/twitch/adapter.js index b5cd5ae4f6..7302560f87 100644 --- a/src/app/data/models/twitch/adapter.js +++ b/src/app/data/models/twitch/adapter.js @@ -1,73 +1,78 @@ -import { get, observer } from "@ember/object"; +import { alias } from "@ember/object/computed"; import { inject as service } from "@ember/service"; -import RESTAdapter from "ember-data/adapters/rest"; import { twitch } from "config"; -import AdapterMixin from "data/models/-mixins/adapter"; +import CustomRESTAdapter from "data/models/-adapters/custom-rest"; +import { urlFragments } from "utils/decorators"; const { oauth: { "client-id": clientId } } = twitch; -export default RESTAdapter.extend( AdapterMixin, { - auth: service(), +@urlFragments({ + /** @this {TwitchAdapter} */ + user_id() { + const user_id = this.auth.session.user_id; + if ( !user_id ) { + throw new Error( "Unknown user_id" ); + } - host: "https://api.twitch.tv", - namespace: "", - headers: { - "Accept": "application/vnd.twitchtv.v5+json", - "Client-ID": clientId + return user_id; }, + /** @this {TwitchAdapter} */ + user_name() { + const user_name = this.auth.session.user_name; + if ( !user_name ) { + throw new Error( "Unknown user_name" ); + } - defaultSerializer: "twitch", + return user_name; + } +}) +export default class TwitchAdapter extends CustomRESTAdapter { + /** @type {AuthService} */ + @service auth; + defaultSerializer = "twitch"; - urlFragments: { - user_id() { - let user_id = get( this, "auth.session.user_id" ); - if ( !user_id ) { - throw new Error( "Unknown user_id" ); - } + host = "https://api.twitch.tv"; + namespace = ""; - return user_id; - }, - user_name() { - let user_name = get( this, "auth.session.user_name" ); - if ( !user_name ) { - throw new Error( "Unknown user_name" ); - } - return user_name; - } - }, + static headers = { + "Accept": "application/vnd.twitchtv.v5+json", + "Client-ID": clientId + }; + static set access_token( value ) { + if ( value === null ) { + delete this.headers[ "Authorization" ]; + } else { + this.headers[ "Authorization" ] = `OAuth ${value}`; + } + } - coalesceFindRequests: false, + @alias( "constructor.access_token" ) + access_token; + @alias( "constructor.headers" ) + headers; - findManyIdString: null, - findManyIdSeparator: ",", + coalesceFindRequests = false; - access_token: null, - tokenObserver: observer( "access_token", function() { - const token = get( this, "access_token" ); - if ( token === null ) { - delete this.headers[ "Authorization" ]; - } else { - this.headers[ "Authorization" ] = `OAuth ${token}`; - } - }), + findManyIdString = null; + findManyIdSeparator = ","; - createRecordMethod: "PUT", + createRecordMethod = "PUT"; createRecordData() { // we don't need to send any data with the request (yet?) return {}; - }, + } updateRecordData() { // we don't need to send any data with the request (yet?) return {}; - }, + } findMany( store, type, ids, snapshots ) { const url = this.buildURL( type, null, snapshots, "findMany" ); @@ -76,7 +81,7 @@ export default RESTAdapter.extend( AdapterMixin, { }; return this.ajax( url, "GET", { data } ); - }, + } groupRecordsForFindMany( store, snapshots ) { @@ -105,7 +110,7 @@ export default RESTAdapter.extend( AdapterMixin, { let length = baseLength; snapshotGroup.forEach( snapshot => { - const id = get( snapshot, "record.id" ); + const id = snapshot.record.id; const idLength = String( id ).length; const separatorLength = group.length === 0 ? 0 : findManyIdSeparatorLength; const newLength = length + separatorLength + idLength; @@ -127,4 +132,4 @@ export default RESTAdapter.extend( AdapterMixin, { return groups; } -}); +} diff --git a/src/app/data/models/twitch/stream/adapter.js b/src/app/data/models/twitch/stream/adapter.js index b08b6ac38a..10890285bb 100644 --- a/src/app/data/models/twitch/stream/adapter.js +++ b/src/app/data/models/twitch/stream/adapter.js @@ -1,7 +1,7 @@ import TwitchAdapter from "data/models/twitch/adapter"; -export default TwitchAdapter.extend({ - coalesceFindRequests: true, - findManyIdString: "channel" -}); +export default class TwitchStreamAdapter extends TwitchAdapter { + coalesceFindRequests = true; + findManyIdString = "channel"; +} diff --git a/src/app/data/models/twitch/team/adapter.js b/src/app/data/models/twitch/team/adapter.js index cf52a49ad9..c1077fe2be 100644 --- a/src/app/data/models/twitch/team/adapter.js +++ b/src/app/data/models/twitch/team/adapter.js @@ -1,14 +1,14 @@ import TwitchAdapter from "data/models/twitch/adapter"; -export default TwitchAdapter.extend({ +export default class TwitchTeamAdapter extends TwitchAdapter { query( store, type, query ) { const url = this.buildURL( type, null, null, "query", query ); delete query.channel; query = this.sortQueryParams ? this.sortQueryParams( query ) : query; return this.ajax( url, "GET", { data: query } ); - }, + } urlForQuery( query ) { // use this approach until EmberData ships the new ds-improved-ajax feature @@ -17,6 +17,6 @@ export default TwitchAdapter.extend({ return this._buildURL( `kraken/channels/${query.channel}/teams` ); } - return this._super( ...arguments ); + return super.urlForQuery( ...arguments ); } -}); +} diff --git a/src/app/data/models/twitch/user/adapter.js b/src/app/data/models/twitch/user/adapter.js index 73a0464b48..6fabff10f7 100644 --- a/src/app/data/models/twitch/user/adapter.js +++ b/src/app/data/models/twitch/user/adapter.js @@ -1,11 +1,11 @@ import TwitchAdapter from "data/models/twitch/adapter"; -export default TwitchAdapter.extend({ +export default class TwitchUserAdapter extends TwitchAdapter { // automatically turns multiple findRecord calls into a single findMany call - coalesceFindRequests: true, + coalesceFindRequests = true; // and uses "login" as query string parameter for the IDs, as defined by the TwitchAdapter - findManyIdString: "login", + findManyIdString = "login"; /** * @param {DS.Store} store @@ -20,8 +20,8 @@ export default TwitchAdapter.extend({ login: id }; - return this.ajax( url, "GET", { data: data } ); - }, + return this.ajax( url, "GET", { data } ); + } /** * @param {string} id @@ -30,7 +30,7 @@ export default TwitchAdapter.extend({ */ urlForFindRecord( id, type ) { return this._buildURL( type ); - }, + } /** * @param {DS.Store} store @@ -46,7 +46,7 @@ export default TwitchAdapter.extend({ const url = this.buildURL( type, null, null, "queryRecord", query ); return this.ajax( url, "GET", { data: query } ); - }, + } /** * @param {Object} query @@ -56,4 +56,4 @@ export default TwitchAdapter.extend({ urlForQueryRecord( query, type ) { return this._buildURL( type ); } -}); +} diff --git a/src/app/utils/decorators.js b/src/app/utils/decorators.js new file mode 100644 index 0000000000..b211970048 --- /dev/null +++ b/src/app/utils/decorators.js @@ -0,0 +1,11 @@ +export function descriptor( descriptor ) { + return () => descriptor; +} + +export function urlFragments( fragments ) { + return cls => { + const parentClass = Object.getPrototypeOf( cls ); + const parentFragments = parentClass.urlFragments || {}; + cls.urlFragments = Object.assign( {}, parentFragments, fragments ); + }; +} diff --git a/src/test/tests/data/models/twitch/adapter.js b/src/test/tests/data/models/twitch/adapter.js index 18f1efd7da..e56dece4de 100644 --- a/src/test/tests/data/models/twitch/adapter.js +++ b/src/test/tests/data/models/twitch/adapter.js @@ -1,296 +1,231 @@ import { module, test } from "qunit"; -import { buildOwner, runDestroy } from "test-utils"; +import { setupTest } from "ember-qunit"; +import { buildResolver } from "test-utils"; import { setupStore, adapterRequest } from "store-utils"; import { FakeI18nService } from "i18n-utils"; +import sinon from "sinon"; + import Service from "@ember/service"; import TwitchAdapter from "data/models/twitch/adapter"; -import Stream from "data/models/twitch/stream/model"; -import StreamAdapter from "data/models/twitch/stream/adapter"; -import StreamSerializer from "data/models/twitch/stream/serializer"; -import Channel from "data/models/twitch/channel/model"; -import ChannelSerializer from "data/models/twitch/channel/serializer"; -import imageInjector from "inject-loader?config!data/models/twitch/image/model"; -import ImageSerializer from "data/models/twitch/image/serializer"; -import User from "data/models/twitch/user/model"; -import UserAdapter from "data/models/twitch/user/adapter"; -import UserSerializer from "data/models/twitch/user/serializer"; +import TwitchStream from "data/models/twitch/stream/model"; +import TwitchStreamAdapter from "data/models/twitch/stream/adapter"; +import TwitchStreamSerializer from "data/models/twitch/stream/serializer"; +import TwitchChannel from "data/models/twitch/channel/model"; +import TwitchChannelSerializer from "data/models/twitch/channel/serializer"; +import twitchImageInjector from "inject-loader?config!data/models/twitch/image/model"; +import TwitchImageSerializer from "data/models/twitch/image/serializer"; +import TwitchUser from "data/models/twitch/user/model"; +import TwitchUserAdapter from "data/models/twitch/user/adapter"; +import TwitchUserSerializer from "data/models/twitch/user/serializer"; import TwitchAdapterFixtures from "fixtures/data/models/twitch/adapter.json"; -const TwitchImage = imageInjector({ - config: { - vars: {} - } -})[ "default" ]; - - -let owner, env; - - -module( "data/models/twitch/adapter", { - beforeEach() { - owner = buildOwner(); - - owner.register( "service:auth", Service.extend() ); - owner.register( "service:i18n", FakeI18nService ); - owner.register( "service:settings", Service.extend() ); - owner.register( "model:twitch-stream", Stream ); - owner.register( "adapter:twitch-stream", StreamAdapter ); - owner.register( "serializer:twitch-stream", StreamSerializer ); - owner.register( "model:twitch-channel", Channel ); - owner.register( "serializer:twitch-channel", ChannelSerializer ); - owner.register( "model:twitch-image", TwitchImage ); - owner.register( "serializer:twitch-image", ImageSerializer ); - owner.register( "model:twitch-user", User ); - owner.register( "adapter:twitch-user", UserAdapter ); - owner.register( "serializer:twitch-user", UserSerializer ); - - env = setupStore( owner, { adapter: TwitchAdapter } ); - }, - - afterEach() { - runDestroy( owner ); - owner = env = null; - } -}); - - -test( "Coalesced single request with single type", assert => { - - let requests = 0; - - env.store.adapterFor( "twitchStream" ).ajax = ( url, method, query ) => { - ++requests; - - return adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-stream-single" ], - url, - method, - query - ); - }; - - return Promise.all([ - env.store.findRecord( "twitchStream", 2 ), - env.store.findRecord( "twitchStream", 4 ) - ]) - .then( () => { - assert.ok( - env.store.hasRecordForId( "twitchStream", 2 ) - && env.store.hasRecordForId( "twitchStream", 4 ), - "Has all Stream records registered in the data store" - ); - - assert.ok( - env.store.hasRecordForId( "twitchChannel", 2 ) - && env.store.hasRecordForId( "twitchChannel", 4 ), - "Has all Channel records registered in the data store" - ); - - assert.ok( - env.store.hasRecordForId( "twitchImage", "stream/preview/2" ) - && env.store.hasRecordForId( "twitchImage", "stream/preview/4" ), - "Has all Image records registered in the data store" - ); +module( "data/models/twitch/adapter", function( hooks ) { + const { default: TwitchImage } = twitchImageInjector({ + config: { + vars: {} + } + }); + + setupTest( hooks, { + resolver: buildResolver({ + AuthService: class extends Service {}, + I18nService: FakeI18nService, + SettingsService: class extends Service {}, + TwitchStream, + TwitchStreamAdapter, + TwitchStreamSerializer, + TwitchChannel, + TwitchChannelSerializer, + TwitchImage, + TwitchImageSerializer, + TwitchUser, + TwitchUserAdapter, + TwitchUserSerializer }) - .then( () => { - assert.strictEqual( - requests, - 1, - "Has made one request" - ); - }); + }); -}); + hooks.beforeEach(function() { + setupStore( this.owner, { adapter: TwitchAdapter } ); + }); -test( "Coalesced multiple requests with single type", assert => { + test( "Coalesced single request with single type", async function( assert ) { + /** @type {DS.Store} */ + const store = this.owner.lookup( "service:store" ); + const adapter = store.adapterFor( "twitch-stream" ); - const adapter = env.store.adapterFor( "twitchStream" ); - let requests = 0; - - // baseLength = 45 (space for two 10 char ids plus separator) - adapter.maxURLLength = 66; - adapter.ajax = ( url, method, query ) => - adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-stream-multiple" ][ requests++ ], - url, - method, - query + const adapterStub = sinon.stub( adapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( assert, TwitchAdapterFixtures[ "coalesce-stream-single" ], ...args ) ); - const ids = [ - "1234567890", - "1234567891", - "1234567892", - "1234567893" - ]; - - return Promise.all( - ids.map( id => env.store.findRecord( "twitchStream", id ) ) - ) - .then( () => { - assert.strictEqual( - requests, - 2, - "Has made two requests" - ); - }); - -}); - - -test( "Coalesced single request with multiple types", assert => { - - let requests = 0; - - env.store.adapterFor( "twitchStream" ).ajax = ( url, method, query ) => { - ++requests; - - return adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-various-single" ][ "stream" ], - url, - method, - query + await Promise.all([ + store.findRecord( "twitch-stream", 2 ), + store.findRecord( "twitch-stream", 4 ) + ]); + assert.ok( + store.hasRecordForId( "twitch-stream", 2 ) + && store.hasRecordForId( "twitch-stream", 4 ), + "Has all Stream records registered in the data store" ); - }; - - env.store.adapterFor( "twitchUser" ).ajax = ( url, method, query ) => { - ++requests; - - return adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-various-single" ][ "user" ], - url, - method, - query + assert.ok( + store.hasRecordForId( "twitch-channel", 2 ) + && store.hasRecordForId( "twitch-channel", 4 ), + "Has all Channel records registered in the data store" ); - }; - - return Promise.all([ - env.store.findRecord( "twitchStream", 2 ), - env.store.findRecord( "twitchStream", 4 ), - env.store.findRecord( "twitchUser", "foo" ), - env.store.findRecord( "twitchUser", "bar" ) - ]) - .then( () => { - assert.ok( - env.store.hasRecordForId( "twitchStream", 2 ) - && env.store.hasRecordForId( "twitchStream", 4 ), - "Has all Stream records registered in the data store" - ); - - assert.ok( - env.store.hasRecordForId( "twitchChannel", 2 ) - && env.store.hasRecordForId( "twitchChannel", 4 ), - "Has all Channel records registered in the data store" - ); - - assert.ok( - env.store.hasRecordForId( "twitchImage", "stream/preview/2" ) - && env.store.hasRecordForId( "twitchImage", "stream/preview/4" ), - "Has all Image records registered in the data store" - ); - - assert.ok( - env.store.hasRecordForId( "twitchUser", "foo" ) - && env.store.hasRecordForId( "twitchUser", "bar" ), - "Has all Stream records registered in the data store" - ); - }) - .then( () => { - assert.strictEqual( - requests, - 2, - "Has made two requests" - ); - }); - -}); - - -test( "Coalesced multiple requests with multiple types", assert => { - - const streamAdapter = env.store.adapterFor( "twitchStream" ); - const userAdapter = env.store.adapterFor( "twitchUser" ); - let streamRequests = 0; - let userRequests = 0; - - // baseLength = 45 (space for two 10 char ids plus separator) - streamAdapter.maxURLLength = 66; - streamAdapter.ajax = ( url, method, query ) => - adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-various-multiple" ][ "stream" ][ streamRequests++ ], - url, - method, - query + assert.ok( + store.hasRecordForId( "twitch-image", "stream/preview/2" ) + && store.hasRecordForId( "twitch-image", "stream/preview/4" ), + "Has all Image records registered in the data store" ); - - const streamIds = [ - "1234567890", - "1234567891", - "1234567892", - "1234567893" - ]; - - // baseLength = 41 (space for two 3 char ids plus separator) - userAdapter.maxURLLength = 48; - userAdapter.ajax = ( url, method, query ) => - adapterRequest( - assert, - TwitchAdapterFixtures[ "coalesce-various-multiple" ][ "user" ][ userRequests++ ], - url, - method, - query + assert.ok( adapterStub.calledOnce, "Has made only one request" ); + }); + + test( "Coalesced multiple requests with single type", async function( assert ) { + /** @type {DS.Store} */ + const store = this.owner.lookup( "service:store" ); + const adapter = store.adapterFor( "twitch-stream" ); + + // baseLength = 45 (space for two 10 char ids plus separator) + adapter.maxURLLength = 66; + + let req = 0; + const adapterStub = sinon.stub( adapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( + assert, + TwitchAdapterFixtures[ "coalesce-stream-multiple" ][ req++ ], + ...args + ) ); + + const ids = [ + "1234567890", + "1234567891", + "1234567892", + "1234567893" + ]; + await Promise.all( ids.map( id => store.findRecord( "twitch-stream", id ) ) ); + + assert.ok( adapterStub.calledTwice, "Has made exactly two requests" ); + }); + + test( "Coalesced single request with multiple types", async function( assert ) { + /** @type {DS.Store} */ + const store = this.owner.lookup( "service:store" ); + const streamAdapter = store.adapterFor( "twitch-stream" ); + const userAdapter = store.adapterFor( "twitch-user" ); + + const streamAdapterStub = sinon.stub( streamAdapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( + assert, + TwitchAdapterFixtures[ "coalesce-various-single" ][ "stream" ], + ...args + ) + ); + const userAdapterStub = sinon.stub( userAdapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( + assert, + TwitchAdapterFixtures[ "coalesce-various-single" ][ "user" ], + ...args + ) ); - const userIds = [ - "foo", - "bar", - "baz", - "qux" - ]; - - return Promise.all([ - ...streamIds.map( id => env.store.findRecord( "twitchStream", id ) ), - ...userIds.map( id => env.store.findRecord( "twitchUser", id ) ) - ]) - .then( () => { - assert.deepEqual( - env.store.peekAll( "twitchStream" ).mapBy( "id" ), - streamIds, - "Has all Stream records registered in the data store" - ); - - assert.deepEqual( - env.store.peekAll( "twitchChannel" ).mapBy( "id" ), - streamIds, - "Has all Channel records registered in the data store" - ); - - assert.deepEqual( - env.store.peekAll( "twitchImage" ).mapBy( "id" ), - streamIds.map( id => `stream/preview/${id}` ), - "Has all Image records registered in the data store" - ); - - assert.deepEqual( - env.store.peekAll( "twitchUser" ).mapBy( "id" ), - userIds, - "Has all Stream records registered in the data store" - ); - }) - .then( () => { - assert.strictEqual( - streamRequests + userRequests, - 4, - "Has made four requests" - ); - }); - + await Promise.all([ + store.findRecord( "twitch-stream", 2 ), + store.findRecord( "twitch-stream", 4 ), + store.findRecord( "twitch-user", "foo" ), + store.findRecord( "twitch-user", "bar" ) + ]); + assert.ok( + store.hasRecordForId( "twitch-stream", 2 ) + && store.hasRecordForId( "twitch-stream", 4 ), + "Has all Stream records registered in the data store" + ); + assert.ok( + store.hasRecordForId( "twitch-channel", 2 ) + && store.hasRecordForId( "twitch-channel", 4 ), + "Has all Channel records registered in the data store" + ); + assert.ok( + store.hasRecordForId( "twitch-image", "stream/preview/2" ) + && store.hasRecordForId( "twitch-image", "stream/preview/4" ), + "Has all Image records registered in the data store" + ); + assert.ok( + store.hasRecordForId( "twitch-user", "foo" ) + && store.hasRecordForId( "twitch-user", "bar" ), + "Has all Stream records registered in the data store" + ); + assert.ok( streamAdapterStub.calledOnce, "Has made only one request for stream" ); + assert.ok( userAdapterStub.calledOnce, "Has made only one request for user" ); + }); + + test( "Coalesced multiple requests with multiple types", async function( assert ) { + /** @type {DS.Store} */ + const store = this.owner.lookup( "service:store" ); + const streamAdapter = store.adapterFor( "twitch-stream" ); + const userAdapter = store.adapterFor( "twitch-user" ); + + // baseLength = 45 (space for two 10 char ids plus separator) + streamAdapter.maxURLLength = 66; + // baseLength = 41 (space for two 3 char ids plus separator) + userAdapter.maxURLLength = 48; + + let reqStream = 0; + let reqUser = 0; + + const streamAdapterStub = sinon.stub( streamAdapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( + assert, + TwitchAdapterFixtures[ "coalesce-various-multiple" ][ "stream" ][ reqStream++ ], + ...args + ) ); + const userAdapterStub = sinon.stub( userAdapter, "ajax" ).callsFake( ( ...args ) => + adapterRequest( + assert, + TwitchAdapterFixtures[ "coalesce-various-multiple" ][ "user" ][ reqUser++ ], + ...args + ) ); + + const streamIds = [ + "1234567890", + "1234567891", + "1234567892", + "1234567893" + ]; + const userIds = [ + "foo", + "bar", + "baz", + "qux" + ]; + + await Promise.all( [ + ...streamIds.map( id => store.findRecord( "twitch-stream", id ) ), + ...userIds.map( id => store.findRecord( "twitch-user", id ) ) + ]); + + assert.propEqual( + store.peekAll( "twitch-stream" ).mapBy( "id" ), + streamIds, + "Has all Stream records registered in the data store" + ); + assert.propEqual( + store.peekAll( "twitch-channel" ).mapBy( "id" ), + streamIds, + "Has all Channel records registered in the data store" + ); + assert.propEqual( + store.peekAll( "twitch-image" ).mapBy( "id" ), + streamIds.map( id => `stream/preview/${id}` ), + "Has all Image records registered in the data store" + ); + assert.propEqual( + store.peekAll( "twitchUser" ).mapBy( "id" ), + userIds, + "Has all Stream records registered in the data store" + ); + assert.ok( streamAdapterStub.calledTwice, "Has made two requests for stream" ); + assert.ok( userAdapterStub.calledTwice, "Has made two requests for user" ); + }); }); diff --git a/src/test/tests/services/auth.js b/src/test/tests/services/auth.js index c1a03f7709..aa4b3773e3 100644 --- a/src/test/tests/services/auth.js +++ b/src/test/tests/services/auth.js @@ -4,7 +4,6 @@ import { buildResolver } from "test-utils"; import { setupStore, adapterRequest } from "store-utils"; import sinon from "sinon"; -import { observer } from "@ember/object"; import { on } from "@ember/object/evented"; import Service from "@ember/service"; import Adapter from "ember-data/adapter"; @@ -90,17 +89,17 @@ module( "services/auth", function( hooks ) { this.sessionFindAllStub = sinon.stub().resolves( [] ); this.sessionCreateStub = sinon.stub().resolves(); this.sessionSaveStub = sinon.stub().resolves(); - this.owner.register( "adapter:auth", Adapter.extend({ - findAll: context.sessionFindAllStub, - createRecord: context.sessionCreateStub, - updateRecord: context.sessionSaveStub - }) ); - this.owner.register( "adapter:twitch", TwitchAdapter.extend({ - tokenObserver: observer( "access_token", function() { - context.setAccessTokenSpy.call( this, this.access_token ); - }) - }) ); - this.owner.register( "adapter:twitch-root", TwitchAdapter.extend({ + this.owner.register( "adapter:auth", class extends Adapter { + findAll = context.sessionFindAllStub; + createRecord = context.sessionCreateStub; + updateRecord = context.sessionSaveStub; + }); + this.owner.register( "adapter:twitch", class extends TwitchAdapter { + static set access_token( value ) { + context.setAccessTokenSpy.call( this, value ); + } + }); + this.owner.register( "adapter:twitch-root", class extends TwitchAdapter { async ajax( ...args ) { return adapterRequest( assert, @@ -108,7 +107,7 @@ module( "services/auth", function( hooks ) { ...args ); } - }) ); + }); // HttpServer this.fakeHttpServer = null; diff --git a/src/test/tests/services/notification/follow.js b/src/test/tests/services/notification/follow.js index a5466e3564..17a5b62910 100644 --- a/src/test/tests/services/notification/follow.js +++ b/src/test/tests/services/notification/follow.js @@ -1,14 +1,14 @@ import { module, test } from "qunit"; import { buildOwner, runDestroy } from "test-utils"; import { setupStore } from "store-utils"; + import { set } from "@ember/object"; import Service from "@ember/service"; -import RESTAdapter from "ember-data/adapters/rest"; import Model from "ember-data/model"; import RESTSerializer from "ember-data/serializers/rest"; import notificationFollowMixinInjector from "inject-loader?./cache!services/notification/follow"; -import AdapterMixin from "data/models/-mixins/adapter"; +import CustomRESTAdapter from "data/models/-adapters/custom-rest"; let owner, env; @@ -23,7 +23,7 @@ module( "services/notification/follow", { owner.register( "model:twitch-stream", Model.extend() ); owner.register( "serializer:twitch-stream", RESTSerializer.extend() ); - env = setupStore( owner, { adapter: RESTAdapter.extend( AdapterMixin ) } ); + env = setupStore( owner, { adapter: CustomRESTAdapter } ); }, afterEach() { From ad3ea0c0682b59d33be4142533c35e18e5e827a1 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:15:43 +0200 Subject: [PATCH 12/34] native classes: Settings model and fragments --- src/app/data/models/settings/adapter.js | 6 +- src/app/data/models/settings/chat/fragment.js | 13 ++- .../models/settings/chat/provider/fragment.js | 9 +- .../settings/chat/providers/fragment.js | 11 ++- src/app/data/models/settings/gui/fragment.js | 72 ++++++++------ .../settings/hotkeys/action/fragment.js | 12 ++- .../data/models/settings/hotkeys/fragment.js | 21 ++-- .../settings/hotkeys/hotkey/fragment.js | 22 +++-- .../settings/hotkeys/namespace/fragment.js | 17 ++-- src/app/data/models/settings/model.js | 40 ++++---- .../models/settings/notification/fragment.js | 51 +++++----- .../models/settings/streaming/fragment.js | 95 +++++++++++-------- .../settings/streaming/player/fragment.js | 20 ++-- .../settings/streaming/players/fragment.js | 17 +++- .../settings/streaming/provider/fragment.js | 13 ++- .../settings/streaming/providers/fragment.js | 9 +- .../settings/streaming/qualities/fragment.js | 9 +- .../settings/streaming/quality/fragment.js | 10 +- .../data/models/settings/streams/fragment.js | 88 +++++++++-------- src/app/utils/decorators.js | 17 ++++ 20 files changed, 338 insertions(+), 214 deletions(-) diff --git a/src/app/data/models/settings/adapter.js b/src/app/data/models/settings/adapter.js index f3bee52877..9e5478cf6c 100644 --- a/src/app/data/models/settings/adapter.js +++ b/src/app/data/models/settings/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "settings" -}); +export default class SettingsAdapter extends LocalStorageAdapter { + namespace = "settings"; +} diff --git a/src/app/data/models/settings/chat/fragment.js b/src/app/data/models/settings/chat/fragment.js index 7c33982243..f02e761270 100644 --- a/src/app/data/models/settings/chat/fragment.js +++ b/src/app/data/models/settings/chat/fragment.js @@ -1,13 +1,16 @@ import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; -import { fragment } from "ember-data-model-fragments/attributes"; import chatProviders from "services/chat/providers"; +import { fragment } from "utils/decorators"; const defaultProvider = Object.keys( chatProviders )[0] || "browser"; -export default Fragment.extend({ - provider: attr( "string", { defaultValue: defaultProvider } ), - providers: fragment( "settingsChatProviders", { defaultValue: {} } ) -}); +export default class SettingsChat extends Fragment { + @attr( "string", { defaultValue: defaultProvider } ) + provider; + /** @type {SettingsChatProviders} */ + @fragment( "settings-chat-providers" ) + providers; +} diff --git a/src/app/data/models/settings/chat/provider/fragment.js b/src/app/data/models/settings/chat/provider/fragment.js index 5d6849c25a..44c68c8925 100644 --- a/src/app/data/models/settings/chat/provider/fragment.js +++ b/src/app/data/models/settings/chat/provider/fragment.js @@ -1,3 +1,4 @@ +import { defineProperty } from "@ember/object"; import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; import { chat as chatConfig } from "config"; @@ -9,7 +10,7 @@ const providers = new Map(); // chat providers don't share common attributes -const SettingsChatProvider = Fragment.extend(); +class SettingsChatProvider extends Fragment {} const { hasOwnProperty } = {}; @@ -19,7 +20,7 @@ for ( const [ id ] of Object.entries( chatProviders ) ) { // a chat provider needs to have a config object (at least a label is required) if ( !hasOwnProperty.call( chatConfig, id ) ) { continue; } - const providerAttributes = {}; + const provider = class extends SettingsChatProvider {}; // dynamic fragment attributes defined in the chat config file const { attributes } = chatConfig[ id ]; @@ -28,11 +29,11 @@ for ( const [ id ] of Object.entries( chatProviders ) ) { const { name, type } = param; // set the whole config object as attribute options object // this will be used in the SettingsChatRoute template via attribute.options.property - providerAttributes[ name ] = attr( type, param ); + const prop = attr( type, param ); + defineProperty( provider.prototype, name, prop ); } } - const provider = SettingsChatProvider.extend( providerAttributes ); providers.set( id, provider ); } diff --git a/src/app/data/models/settings/chat/providers/fragment.js b/src/app/data/models/settings/chat/providers/fragment.js index 79ba231d81..c9e586dfb5 100644 --- a/src/app/data/models/settings/chat/providers/fragment.js +++ b/src/app/data/models/settings/chat/providers/fragment.js @@ -1,19 +1,22 @@ +import { defineProperty } from "@ember/object"; import Fragment from "ember-data-model-fragments/fragment"; import { fragment } from "ember-data-model-fragments/attributes"; -import { typeKey } from "../provider/fragment"; import chatProviders from "services/chat/providers"; +import { typeKey } from "../provider/fragment"; + +class SettingsChatProviders extends Fragment {} -const attributes = {}; for ( const [ type ] of Object.entries( chatProviders ) ) { - attributes[ type ] = fragment( "settings-chat-provider", { + const prop = fragment( "settings-chat-provider", { defaultValue: { [ typeKey ]: `settings-chat-provider-${type}` }, polymorphic: true, typeKey }); + defineProperty( SettingsChatProviders.prototype, type, prop ); } -export default Fragment.extend( attributes ); +export default SettingsChatProviders; diff --git a/src/app/data/models/settings/gui/fragment.js b/src/app/data/models/settings/gui/fragment.js index ccbab0cf9a..b8bad9a8b1 100644 --- a/src/app/data/models/settings/gui/fragment.js +++ b/src/app/data/models/settings/gui/fragment.js @@ -1,4 +1,4 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; @@ -17,45 +17,55 @@ export const ATTR_GUI_FOCUSREFRESH_TWO = 120000; export const ATTR_GUI_FOCUSREFRESH_FIVE = 300000; -export default Fragment.extend({ - externalcommands: attr( "boolean", { defaultValue: false } ), - focusrefresh: attr( "number", { defaultValue: ATTR_GUI_FOCUSREFRESH_NONE } ), - hidebuttons: attr( "boolean", { defaultValue: false } ), - homepage: attr( "string", { defaultValue: "/featured" } ), - integration: attr( "number", { defaultValue: ATTR_GUI_INTEGRATION_BOTH } ), - language: attr( "string", { defaultValue: "auto" } ), - minimize: attr( "number", { defaultValue: ATTR_GUI_MINIMIZE_NOOP } ), - minimizetotray: attr( "boolean", { defaultValue: false } ), - smoothscroll: attr( "boolean", { defaultValue: true } ), - theme: attr( "string", { defaultValue: "system" } ), - - - isVisibleInTaskbar: computed( "integration", function() { - return ( get( this, "integration" ) & ATTR_GUI_INTEGRATION_TASKBAR ) > 0; - }), - - isVisibleInTray: computed( "integration", function() { - return ( get( this, "integration" ) & ATTR_GUI_INTEGRATION_TRAY ) > 0; - }) - -}).reopenClass({ - - integration: [ +export default class SettingsGui extends Fragment { + static integration = [ { id: ATTR_GUI_INTEGRATION_BOTH, label: "both" }, { id: ATTR_GUI_INTEGRATION_TASKBAR, label: "taskbar" }, { id: ATTR_GUI_INTEGRATION_TRAY, label: "tray" } - ], + ]; - minimize: [ + static minimize = [ { id: ATTR_GUI_MINIMIZE_NOOP, label: "noop", disabled: false }, { id: ATTR_GUI_MINIMIZE_MINIMIZE, label: "minimize", disabled: false }, { id: ATTR_GUI_MINIMIZE_TRAY, label: "tray", disabled: false } - ], + ]; - focusrefresh: [ + static focusrefresh = [ { id: ATTR_GUI_FOCUSREFRESH_NONE, label: "none" }, { id: ATTR_GUI_FOCUSREFRESH_ONE, label: "one" }, { id: ATTR_GUI_FOCUSREFRESH_TWO, label: "two" }, { id: ATTR_GUI_FOCUSREFRESH_FIVE, label: "five" } - ] -}); + ]; + + @attr( "boolean", { defaultValue: false } ) + externalcommands; + @attr( "number", { defaultValue: ATTR_GUI_FOCUSREFRESH_NONE } ) + focusrefresh; + @attr( "boolean", { defaultValue: false } ) + hidebuttons; + @attr( "string", { defaultValue: "/featured" } ) + homepage; + @attr( "number", { defaultValue: ATTR_GUI_INTEGRATION_BOTH } ) + integration; + @attr( "string", { defaultValue: "auto" } ) + language; + @attr( "number", { defaultValue: ATTR_GUI_MINIMIZE_NOOP } ) + minimize; + @attr( "boolean", { defaultValue: false } ) + minimizetotray; + @attr( "boolean", { defaultValue: true } ) + smoothscroll; + @attr( "string", { defaultValue: "system" } ) + theme; + + + @computed( "integration" ) + get isVisibleInTaskbar() { + return ( this.integration & ATTR_GUI_INTEGRATION_TASKBAR ) > 0; + } + + @computed( "integration" ) + get isVisibleInTray() { + return ( this.integration & ATTR_GUI_INTEGRATION_TRAY ) > 0; + } +} diff --git a/src/app/data/models/settings/hotkeys/action/fragment.js b/src/app/data/models/settings/hotkeys/action/fragment.js index 76f97f430b..0672ab8567 100644 --- a/src/app/data/models/settings/hotkeys/action/fragment.js +++ b/src/app/data/models/settings/hotkeys/action/fragment.js @@ -1,8 +1,10 @@ import Fragment from "ember-data-model-fragments/fragment"; -import { fragment } from "ember-data-model-fragments/attributes"; +import { fragment } from "utils/decorators"; -export default Fragment.extend({ - primary: fragment( "settings-hotkeys-hotkey", { defaultValue: {} } ), - secondary: fragment( "settings-hotkeys-hotkey", { defaultValue: {} } ) -}); +export default class SettingsHotkeysAction extends Fragment { + @fragment( "settings-hotkeys-hotkey" ) + primary; + @fragment( "settings-hotkeys-hotkey" ) + secondary; +} diff --git a/src/app/data/models/settings/hotkeys/fragment.js b/src/app/data/models/settings/hotkeys/fragment.js index 338ebbc2f3..2755357f13 100644 --- a/src/app/data/models/settings/hotkeys/fragment.js +++ b/src/app/data/models/settings/hotkeys/fragment.js @@ -1,11 +1,14 @@ +import { defineProperty } from "@ember/object"; import Fragment from "ember-data-model-fragments/fragment"; import { fragment } from "ember-data-model-fragments/attributes"; import { hotkeys as hotkeysConfig } from "config"; import { typeKey } from "./namespace/fragment"; -const attributes = {}; -for ( const [ namespaceName, { actions } ] of Object.entries( hotkeysConfig ) ) { +class SettingsHotkeys extends Fragment {} + +for ( const [ type, { actions } ] of Object.entries( hotkeysConfig ) ) { + let hasActions = false; const defaultValue = {}; for ( const [ action, hotkey ] of Object.entries( actions ) ) { if ( typeof hotkey === "string" ) { continue; } @@ -13,16 +16,20 @@ for ( const [ namespaceName, { actions } ] of Object.entries( hotkeysConfig ) ) primary: {}, secondary: {} }; + hasActions = true; } // namespaces without actions should not exist - if ( !Object.keys( defaultValue ).length ) { continue; } - defaultValue[ typeKey ] = `settings-hotkeys-namespace-${namespaceName}`; - attributes[ namespaceName ] = fragment( "settings-hotkeys-namespace", { - defaultValue, + if ( !hasActions ) { continue; } + + const prop = fragment( "settings-hotkeys-namespace", { + defaultValue: Object.assign( defaultValue, { + [ typeKey ]: `settings-hotkeys-namespace-${type}` + }), polymorphic: true, typeKey }); + defineProperty( SettingsHotkeys.prototype, type, prop ); } -export default Fragment.extend( attributes ); +export default SettingsHotkeys; diff --git a/src/app/data/models/settings/hotkeys/hotkey/fragment.js b/src/app/data/models/settings/hotkeys/hotkey/fragment.js index ea5ea014fa..af3e64ceaf 100644 --- a/src/app/data/models/settings/hotkeys/hotkey/fragment.js +++ b/src/app/data/models/settings/hotkeys/hotkey/fragment.js @@ -2,11 +2,17 @@ import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; -export default Fragment.extend({ - disabled: attr( "boolean", { defaultValue: false } ), - code: attr( "string", { defaultValue: null } ), - altKey: attr( "boolean", { defaultValue: false } ), - ctrlKey: attr( "boolean", { defaultValue: false } ), - metaKey: attr( "boolean", { defaultValue: false } ), - shiftKey: attr( "boolean", { defaultValue: false } ) -}); +export default class SettingsHotkeysHotkey extends Fragment { + @attr( "boolean", { defaultValue: false } ) + disabled; + @attr( "string", { defaultValue: null } ) + code; + @attr( "boolean", { defaultValue: false } ) + altKey; + @attr( "boolean", { defaultValue: false } ) + ctrlKey; + @attr( "boolean", { defaultValue: false } ) + metaKey; + @attr( "boolean", { defaultValue: false } ) + shiftKey; +} diff --git a/src/app/data/models/settings/hotkeys/namespace/fragment.js b/src/app/data/models/settings/hotkeys/namespace/fragment.js index 7ec8456956..db0b3b304a 100644 --- a/src/app/data/models/settings/hotkeys/namespace/fragment.js +++ b/src/app/data/models/settings/hotkeys/namespace/fragment.js @@ -1,5 +1,6 @@ -import Fragment from "ember-data-model-fragments/fragment"; +import { defineProperty } from "@ember/object"; import { fragment } from "ember-data-model-fragments/attributes"; +import Fragment from "ember-data-model-fragments/fragment"; import { hotkeys as hotkeysConfig } from "config"; @@ -7,18 +8,22 @@ const typeKey = "type"; const namespaces = new Map(); -const SettingsHotkeysNamespace = Fragment.extend(); +class SettingsHotkeysNamespace extends Fragment {} for ( const [ namespaceName, { actions } ] of Object.entries( hotkeysConfig ) ) { - const attributes = {}; + const namespace = class extends SettingsHotkeysNamespace {}; + + let hasActions = false; for ( const [ action, hotkeys ] of Object.entries( actions ) ) { if ( typeof hotkeys === "string" ) { continue; } - attributes[ action ] = fragment( "settings-hotkeys-action", { defaultValue: {} } ); + const prop = fragment( "settings-hotkeys-action" ); + defineProperty( namespace.prototype, action, prop ); + hasActions = true; } // namespaces without actions should not exist - if ( !Object.keys( attributes ).length ) { continue; } - const namespace = SettingsHotkeysNamespace.extend( attributes ); + if ( !hasActions ) { continue; } + namespaces.set( namespaceName, namespace ); } diff --git a/src/app/data/models/settings/model.js b/src/app/data/models/settings/model.js index 8e3e81336f..b866b87a5a 100644 --- a/src/app/data/models/settings/model.js +++ b/src/app/data/models/settings/model.js @@ -1,20 +1,28 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; -import { fragment } from "ember-data-model-fragments/attributes"; +import { fragment, name } from "utils/decorators"; -/** - * @class Settings - */ -export default Model.extend({ - advanced: attr( "boolean", { defaultValue: false } ), - gui: fragment( "settingsGui", { defaultValue: {} } ), - streaming: fragment( "settingsStreaming", { defaultValue: {} } ), - streams: fragment( "settingsStreams", { defaultValue: {} } ), - chat: fragment( "settingsChat", { defaultValue: {} } ), - notification: fragment( "settingsNotification", { defaultValue: {} } ), - hotkeys: fragment( "settingsHotkeys", { defaultValue: {} } ) - -}).reopenClass({ - toString() { return "Settings"; } -}); +@name( "Settings" ) +export default class Settings extends Model { + @attr( "boolean", { defaultValue: false } ) + advanced; + /** @type {SettingsGui} */ + @fragment( "settings-gui" ) + gui; + /** @type {SettingsStreaming} */ + @fragment( "settings-streaming" ) + streaming; + /** @type {SettingsStreams} */ + @fragment( "settings-streams" ) + streams; + /** @type {SettingsChat} */ + @fragment( "settings-chat" ) + chat; + /** @type {SettingsNotification} */ + @fragment( "settings-notification" ) + notification; + /** @type {SettingsHotkeys} */ + @fragment( "settings-hotkeys" ) + hotkeys; +} diff --git a/src/app/data/models/settings/notification/fragment.js b/src/app/data/models/settings/notification/fragment.js index b94b06bcb5..6d3bcd90e7 100644 --- a/src/app/data/models/settings/notification/fragment.js +++ b/src/app/data/models/settings/notification/fragment.js @@ -8,43 +8,50 @@ export const ATTR_NOTIFY_CLICK_STREAM = 2; export const ATTR_NOTIFY_CLICK_STREAMANDCHAT = 3; -export default Fragment.extend({ - enabled: attr( "boolean", { defaultValue: true } ), - provider: attr( "string", { defaultValue: "auto" } ), - filter: attr( "boolean", { defaultValue: true } ), - filter_vodcasts: attr( "boolean", { defaultValue: true } ), - grouping: attr( "boolean", { defaultValue: true } ), - click: attr( "number", { defaultValue: 1 } ), - click_group: attr( "number", { defaultValue: 1 } ), - click_restore: attr( "boolean", { defaultValue: true } ), - badgelabel: attr( "boolean", { defaultValue: true } ) - -}).reopenClass({ - - providers: [ +export default class SettingsNotification extends Fragment { + static providers = [ { id: "auto" }, { id: "native" }, { id: "snoretoast" }, { id: "growl" }, { id: "rich" } - ], + ]; - filter: [ + static filter = [ { id: true, label: "blacklist" }, { id: false, label: "whitelist" } - ], + ]; - click: [ + static click = [ { id: ATTR_NOTIFY_CLICK_NOOP, label: "noop" }, { id: ATTR_NOTIFY_CLICK_FOLLOWED, label: "followed" }, { id: ATTR_NOTIFY_CLICK_STREAM, label: "stream" }, { id: ATTR_NOTIFY_CLICK_STREAMANDCHAT, label: "stream-and-chat" } - ], + ]; - clickGroup: [ + static clickGroup = [ { id: ATTR_NOTIFY_CLICK_NOOP, label: "noop" }, { id: ATTR_NOTIFY_CLICK_FOLLOWED, label: "followed" }, { id: ATTR_NOTIFY_CLICK_STREAM, label: "stream" }, { id: ATTR_NOTIFY_CLICK_STREAMANDCHAT, label: "stream-and-chat" } - ] -}); + ]; + + @attr( "boolean", { defaultValue: true } ) + enabled; + @attr( "string", { defaultValue: "auto" } ) + provider; + @attr( "boolean", { defaultValue: true } ) + filter; + @attr( "boolean", { defaultValue: true } ) + filter_vodcasts; + @attr( "boolean", { defaultValue: true } ) + grouping; + @attr( "number", { defaultValue: 1 } ) + click; + @attr( "number", { defaultValue: 1 } ) + click_group; + @attr( "boolean", { defaultValue: true } ) + click_restore; + @attr( "boolean", { defaultValue: true } ) + badgelabel; +} diff --git a/src/app/data/models/settings/streaming/fragment.js b/src/app/data/models/settings/streaming/fragment.js index 7f7ac3a2b5..72fd1f82f5 100644 --- a/src/app/data/models/settings/streaming/fragment.js +++ b/src/app/data/models/settings/streaming/fragment.js @@ -1,11 +1,11 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; +import { equal } from "@ember/object/computed"; import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; -import { fragment } from "ember-data-model-fragments/attributes"; import { streaming as streamingConfig } from "config"; +import { fragment } from "utils/decorators"; -const { equal } = computed; const { providers, "default-provider": defaultProvider } = streamingConfig; const { MAX_SAFE_INTEGER: MAX } = Number; @@ -16,40 +16,8 @@ export const ATTR_STREAMING_PLAYER_INPUT_HTTP = "http"; export const ATTR_STREAMING_PLAYER_INPUT_PASSTHROUGH = "passthrough"; -export default Fragment.extend({ - provider: attr( "string", { defaultValue: defaultProvider } ), - providers: fragment( "settingsStreamingProviders", { defaultValue: {} } ), - - quality: attr( "string", { defaultValue: "source" } ), - qualities: fragment( "settingsStreamingQualities", { defaultValue: {} } ), - - player: attr( "string", { defaultValue: "default" } ), - players: fragment( "settingsStreamingPlayers", { defaultValue: {} } ), - - low_latency: attr( "boolean", { defaultValue: false } ), - disable_ads: attr( "boolean", { defaultValue: false } ), - player_input: attr( "string", { defaultValue: ATTR_STREAMING_PLAYER_INPUT_STDIN } ), - player_no_close: attr( "boolean", { defaultValue: false } ), - hls_live_edge: attr( "number", { defaultValue: 3, min: 1, max: 10 } ), - hls_segment_threads: attr( "number", { defaultValue: 1, min: 1, max: 10 } ), - retry_open: attr( "number", { defaultValue: 1, min: 1, max: MAX } ), - retry_streams: attr( "number", { defaultValue: 1, min: 0, max: MAX } ), - - providerName: computed( "provider", function() { - const provider = get( this, "provider" ); - return providers[ provider ][ "name" ]; - }), - - providerType: computed( "provider", function() { - const provider = get( this, "provider" ); - return providers[ provider ][ "type" ]; - }), - - isStreamlink: equal( "providerType", "streamlink" ) - -}).reopenClass({ - - playerInput: [ +export default class SettingsStreaming extends Fragment { + static playerInput = [ { id: ATTR_STREAMING_PLAYER_INPUT_STDIN, documentation: null @@ -66,5 +34,54 @@ export default Fragment.extend({ id: ATTR_STREAMING_PLAYER_INPUT_PASSTHROUGH, documentation: "--player-passthrough" } - ] -}); + ]; + + @attr( "string", { defaultValue: defaultProvider } ) + provider; + /** @type {SettingsStreamingProviders} */ + @fragment( "settings-streaming-providers" ) + providers; + + @attr( "string", { defaultValue: "source" } ) + quality; + /** @type {SettingsStreamingQualities} */ + @fragment( "settings-streaming-qualities" ) + qualities; + + @attr( "string", { defaultValue: "default" } ) + player; + /** @type {SettingsStreamingPlayers} */ + @fragment( "settings-streaming-players" ) + players; + + @attr( "boolean", { defaultValue: false } ) + low_latency; + @attr( "boolean", { defaultValue: false } ) + disable_ads; + @attr( "string", { defaultValue: ATTR_STREAMING_PLAYER_INPUT_STDIN } ) + player_input; + @attr( "boolean", { defaultValue: false } ) + player_no_close; + @attr( "number", { defaultValue: 3, min: 1, max: 10 } ) + hls_live_edge; + @attr( "number", { defaultValue: 1, min: 1, max: 10 } ) + hls_segment_threads; + @attr( "number", { defaultValue: 1, min: 1, max: MAX } ) + retry_open; + @attr( "number", { defaultValue: 1, min: 0, max: MAX } ) + retry_streams; + + + @computed( "provider" ) + get providerName() { + return providers[ this.provider ][ "name" ]; + } + + @computed( "provider" ) + get providerType() { + return providers[ this.provider ][ "type" ]; + } + + @equal( "providerType", "streamlink" ) + isStreamlink; +} diff --git a/src/app/data/models/settings/streaming/player/fragment.js b/src/app/data/models/settings/streaming/player/fragment.js index b501b5df26..a72835941b 100644 --- a/src/app/data/models/settings/streaming/player/fragment.js +++ b/src/app/data/models/settings/streaming/player/fragment.js @@ -1,3 +1,4 @@ +import { defineProperty } from "@ember/object"; import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; import { players as playersConfig } from "config"; @@ -7,18 +8,23 @@ const typeKey = "type"; const players = new Map(); -const SettingsStreamingPlayer = Fragment.extend({ - exec: attr( "string" ), - args: attr( "string" ) -}); +// the players share a few common attributes +class SettingsStreamingPlayer extends Fragment { + @attr( "string" ) + exec; + @attr( "string" ) + args; +} for ( const [ id, { params } ] of Object.entries( playersConfig ) ) { - const attributes = {}; + const player = class extends SettingsStreamingPlayer {}; + for ( const { name, type, default: defaultValue } of params ) { - attributes[ name ] = attr( type, { defaultValue } ); + const prop = attr( type, { defaultValue } ); + defineProperty( player.prototype, name, prop ); } - const player = SettingsStreamingPlayer.extend( attributes ); + players.set( id, player ); } diff --git a/src/app/data/models/settings/streaming/players/fragment.js b/src/app/data/models/settings/streaming/players/fragment.js index fd33ab2ada..443bf1ba90 100644 --- a/src/app/data/models/settings/streaming/players/fragment.js +++ b/src/app/data/models/settings/streaming/players/fragment.js @@ -1,21 +1,28 @@ +import { defineProperty } from "@ember/object"; import Fragment from "ember-data-model-fragments/fragment"; import { fragment } from "ember-data-model-fragments/attributes"; import { players as playersConfig } from "config"; import { typeKey } from "../player/fragment"; -const attributes = { - "default": fragment( "settings-streaming-player", { defaultValue: {} } ) -}; +class SettingsStreamingPlayers extends Fragment {} + +defineProperty( + SettingsStreamingPlayers.prototype, + "default", + fragment( "settings-streaming-player", { defaultValue: {} } ) +); + for ( const [ type ] of Object.entries( playersConfig ) ) { - attributes[ type ] = fragment( "settings-streaming-player", { + const prop = fragment( "settings-streaming-player", { defaultValue: { [ typeKey ]: `settings-streaming-player-${type}` }, polymorphic: true, typeKey }); + defineProperty( SettingsStreamingPlayers.prototype, type, prop ); } -export default Fragment.extend( attributes ); +export default SettingsStreamingPlayers; diff --git a/src/app/data/models/settings/streaming/provider/fragment.js b/src/app/data/models/settings/streaming/provider/fragment.js index c5a74c8704..08edb10103 100644 --- a/src/app/data/models/settings/streaming/provider/fragment.js +++ b/src/app/data/models/settings/streaming/provider/fragment.js @@ -2,8 +2,11 @@ import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; -export default Fragment.extend({ - exec: attr( "string" ), - params: attr( "string" ), - pythonscript: attr( "string" ) -}); +export default class SettingsStreamingProvider extends Fragment { + @attr( "string" ) + exec; + @attr( "string" ) + params; + @attr( "string" ) + pythonscript; +} diff --git a/src/app/data/models/settings/streaming/providers/fragment.js b/src/app/data/models/settings/streaming/providers/fragment.js index ec14128989..990dae443f 100644 --- a/src/app/data/models/settings/streaming/providers/fragment.js +++ b/src/app/data/models/settings/streaming/providers/fragment.js @@ -1,3 +1,4 @@ +import { defineProperty } from "@ember/object"; import Fragment from "ember-data-model-fragments/fragment"; import { fragment } from "ember-data-model-fragments/attributes"; import { streaming as streamingConfig } from "config"; @@ -5,10 +6,12 @@ import { streaming as streamingConfig } from "config"; const { providers } = streamingConfig; -const attributes = {}; +class SettingsStreamingProviders extends Fragment {} + for ( const [ provider ] of Object.entries( providers ) ) { - attributes[ provider ] = fragment( "settingsStreamingProvider", { defaultValue: {} } ); + const prop = fragment( "settings-streaming-provider", { defaultValue: {} } ); + defineProperty( SettingsStreamingProviders.prototype, provider, prop ); } -export default Fragment.extend( attributes ); +export default SettingsStreamingProviders; diff --git a/src/app/data/models/settings/streaming/qualities/fragment.js b/src/app/data/models/settings/streaming/qualities/fragment.js index d25f379fee..e76d15bdf0 100644 --- a/src/app/data/models/settings/streaming/qualities/fragment.js +++ b/src/app/data/models/settings/streaming/qualities/fragment.js @@ -1,12 +1,15 @@ +import { defineProperty } from "@ember/object"; import Fragment from "ember-data-model-fragments/fragment"; import { fragment } from "ember-data-model-fragments/attributes"; import { qualities } from "data/models/stream/model"; -const attributes = {}; +class SettingsStreamingQualities extends Fragment {} + for ( const { id } of qualities ) { - attributes[ id ] = fragment( "settingsStreamingQuality", { defaultValue: {} } ); + const prop = fragment( "settings-streaming-quality", { defaultValue: {} } ); + defineProperty( SettingsStreamingQualities.prototype, id, prop ); } -export default Fragment.extend( attributes ); +export default SettingsStreamingQualities; diff --git a/src/app/data/models/settings/streaming/quality/fragment.js b/src/app/data/models/settings/streaming/quality/fragment.js index 0e58c3f68e..429af8c05f 100644 --- a/src/app/data/models/settings/streaming/quality/fragment.js +++ b/src/app/data/models/settings/streaming/quality/fragment.js @@ -2,7 +2,9 @@ import attr from "ember-data/attr"; import Fragment from "ember-data-model-fragments/fragment"; -export default Fragment.extend({ - quality: attr( "string" ), - exclude: attr( "string" ) -}); +export default class SettingsStreamingQuality extends Fragment { + @attr( "string" ) + quality; + @attr( "string" ) + exclude; +} diff --git a/src/app/data/models/settings/streams/fragment.js b/src/app/data/models/settings/streams/fragment.js index 6926575911..567e249a88 100644 --- a/src/app/data/models/settings/streams/fragment.js +++ b/src/app/data/models/settings/streams/fragment.js @@ -19,58 +19,72 @@ export const ATTR_FILTER_LANGUAGES_NOOP = 0; export const ATTR_FILTER_LANGUAGES_FADE = 1; export const ATTR_FILTER_LANGUAGES_FILTER = 2; -// eslint-disable-next-line max-len -export const DEFAULT_VODCAST_REGEXP = "\\b(not live|re-?(run|streaming)|(vod-?|re-?broad)cast(ing)?)\\b"; +export const DEFAULT_VODCAST_REGEXP + = "\\b(not live|re-?(run|streaming)|(vod-?|re-?broad)cast(ing)?)\\b"; -export default Fragment.extend({ - name: attr( "number", { defaultValue: ATTR_STREAMS_NAME_BOTH } ), - - modal_close_end: attr( "boolean", { defaultValue: false } ), - modal_close_launch: attr( "boolean", { defaultValue: false } ), - - chat_open: attr( "boolean", { defaultValue: false } ), - chat_open_context: attr( "boolean", { defaultValue: false } ), - twitchemotes: attr( "boolean", { defaultValue: false } ), - - filter_vodcast: attr( "boolean", { defaultValue: true } ), - vodcast_regexp: attr( "string", { defaultValue: "" } ), - - filter_languages: attr( "number", { defaultValue: ATTR_FILTER_LANGUAGES_NOOP } ), - language: attr( "string", { defaultValue: "en" } ), - - show_flag: attr( "boolean", { defaultValue: false } ), - show_info: attr( "boolean", { defaultValue: false } ), - info: attr( "number", { defaultValue: ATTR_STREAMS_INFO_TITLE } ), - uptime_hours_only: attr( "boolean", { defaultValue: false } ), - - click_middle: attr( "number", { defaultValue: ATTR_STREAMS_CLICK_CHAT } ), - click_modify: attr( "number", { defaultValue: ATTR_STREAMS_CLICK_SETTINGS } ) - -}).reopenClass({ - - contentName: [ +export default class SettingsStreams extends Fragment { + static contentName = [ { id: ATTR_STREAMS_NAME_BOTH, label: "both" }, { id: ATTR_STREAMS_NAME_CUSTOM, label: "custom" }, { id: ATTR_STREAMS_NAME_ORIGINAL, label: "original" } - ], + ]; - filterLanguages: [ + static filterLanguages = [ { id: ATTR_FILTER_LANGUAGES_NOOP, label: "noop" }, { id: ATTR_FILTER_LANGUAGES_FADE, label: "fade" }, { id: ATTR_FILTER_LANGUAGES_FILTER, label: "filter" } - ], + ]; - info: [ + static info = [ { id: ATTR_STREAMS_INFO_GAME, label: "game" }, { id: ATTR_STREAMS_INFO_TITLE, label: "title" } - ], + ]; - click: [ + static click = [ { id: ATTR_STREAMS_CLICK_NOOP, label: "noop" }, { id: ATTR_STREAMS_CLICK_LAUNCH, label: "launch" }, { id: ATTR_STREAMS_CLICK_CHAT, label: "chat" }, { id: ATTR_STREAMS_CLICK_CHANNEL, label: "channel" }, { id: ATTR_STREAMS_CLICK_SETTINGS, label: "settings" } - ] -}); + ]; + + @attr( "number", { defaultValue: ATTR_STREAMS_NAME_BOTH } ) + name; + + @attr( "boolean", { defaultValue: false } ) + modal_close_end; + @attr( "boolean", { defaultValue: false } ) + modal_close_launch; + + @attr( "boolean", { defaultValue: false } ) + chat_open; + @attr( "boolean", { defaultValue: false } ) + chat_open_context; + @attr( "boolean", { defaultValue: false } ) + twitchemotes; + + @attr( "boolean", { defaultValue: true } ) + filter_vodcast; + @attr( "string", { defaultValue: "" } ) + vodcast_regexp; + + @attr( "number", { defaultValue: ATTR_FILTER_LANGUAGES_NOOP } ) + filter_languages; + @attr( "string", { defaultValue: "en" } ) + languages; + + @attr( "boolean", { defaultValue: false } ) + show_flag; + @attr( "boolean", { defaultValue: false } ) + show_info; + @attr( "number", { defaultValue: ATTR_STREAMS_INFO_TITLE } ) + info; + @attr( "boolean", { defaultValue: false } ) + uptime_hours_only; + + @attr( "number", { defaultValue: ATTR_STREAMS_CLICK_CHAT } ) + click_middle; + @attr( "number", { defaultValue: ATTR_STREAMS_CLICK_SETTINGS } ) + click_modify; +} diff --git a/src/app/utils/decorators.js b/src/app/utils/decorators.js index b211970048..6c06f16978 100644 --- a/src/app/utils/decorators.js +++ b/src/app/utils/decorators.js @@ -1,3 +1,6 @@ +import { fragment as modelFragment } from "ember-data-model-fragments/attributes"; + + export function descriptor( descriptor ) { return () => descriptor; } @@ -9,3 +12,17 @@ export function urlFragments( fragments ) { cls.urlFragments = Object.assign( {}, parentFragments, fragments ); }; } + +export function name( name ) { + return cls => { + cls.toString = () => name; + }; +} + +export function fragment( name, options = {}, ...params ) { + return modelFragment( + name, + Object.assign( { defaultValue: {} }, options ), + ...params + ); +} From 2c48a82fe3e4886b9355d27dd992c94fbde45fbf Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:31:15 +0200 Subject: [PATCH 13/34] native classes: twitch models and serializers --- .../models/twitch/channel-followed/model.js | 19 +- .../twitch/channel-followed/serializer.js | 22 ++- src/app/data/models/twitch/channel/model.js | 167 ++++++++++-------- .../data/models/twitch/channel/serializer.js | 12 +- src/app/data/models/twitch/game-top/model.js | 19 +- .../data/models/twitch/game-top/serializer.js | 16 +- src/app/data/models/twitch/game/model.js | 26 +-- src/app/data/models/twitch/game/serializer.js | 18 +- src/app/data/models/twitch/image/model.js | 93 +++++----- .../data/models/twitch/image/serializer.js | 6 +- src/app/data/models/twitch/root/model.js | 31 ++-- src/app/data/models/twitch/root/serializer.js | 10 +- .../models/twitch/search-channel/model.js | 13 +- .../twitch/search-channel/serializer.js | 20 +-- .../data/models/twitch/search-game/model.js | 13 +- .../models/twitch/search-game/serializer.js | 20 +-- .../data/models/twitch/search-stream/model.js | 13 +- .../models/twitch/search-stream/serializer.js | 20 +-- src/app/data/models/twitch/serializer.js | 10 +- .../models/twitch/stream-featured/model.js | 31 ++-- .../twitch/stream-featured/serializer.js | 16 +- .../models/twitch/stream-followed/model.js | 13 +- .../twitch/stream-followed/serializer.js | 20 +-- .../models/twitch/stream-summary/model.js | 15 +- .../twitch/stream-summary/serializer.js | 12 +- src/app/data/models/twitch/stream/model.js | 134 +++++++------- .../data/models/twitch/stream/serializer.js | 18 +- .../data/models/twitch/subscription/model.js | 24 +-- .../models/twitch/subscription/serializer.js | 14 +- src/app/data/models/twitch/team/model.js | 48 ++--- src/app/data/models/twitch/team/serializer.js | 16 +- src/app/data/models/twitch/user/model.js | 21 ++- src/app/data/models/twitch/user/serializer.js | 22 +-- src/test/tests/data/models/twitch/channel.js | 6 +- src/test/tests/data/models/twitch/stream.js | 13 +- 35 files changed, 508 insertions(+), 463 deletions(-) diff --git a/src/app/data/models/twitch/channel-followed/model.js b/src/app/data/models/twitch/channel-followed/model.js index 3c30a85123..94627c3166 100644 --- a/src/app/data/models/twitch/channel-followed/model.js +++ b/src/app/data/models/twitch/channel-followed/model.js @@ -1,13 +1,16 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - channel: belongsTo( "twitchChannel", { async: false } ), - created_at: attr( "date" ), - notifications: attr( "boolean" ) - -}).reopenClass({ - toString() { return "kraken/users/:user_id/follows/channels"; } -}); +@name( "kraken/users/:user_id/follows/channels" ) +export default class TwitchChannelFollowed extends Model { + /** @type {TwitchChannel} */ + @belongsTo( "twitch-channel", { async: false } ) + channel; + @attr( "date" ) + created_at; + @attr( "boolean" ) + notifications; +} diff --git a/src/app/data/models/twitch/channel-followed/serializer.js b/src/app/data/models/twitch/channel-followed/serializer.js index a5cbc965f9..d8a43c3934 100644 --- a/src/app/data/models/twitch/channel-followed/serializer.js +++ b/src/app/data/models/twitch/channel-followed/serializer.js @@ -1,17 +1,15 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchChannelFollowed"; - }, +export default class TwitchChannelFollowedSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-channel-followed"; - attrs: { + attrs = { channel: { deserialize: "records" } - }, + }; normalizeArrayResponse( store, primaryModelClass, payload, id, requestType ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // fix payload format const follows = ( payload.follows /* istanbul ignore next */ || [] ); @@ -21,11 +19,11 @@ export default TwitchSerializer.extend({ return data; }); - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeArrayResponse( store, primaryModelClass, payload, id, requestType ); + } normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // fix payload format payload[ this.primaryKey ] = payload.channel[ foreignKey ]; @@ -34,6 +32,6 @@ export default TwitchSerializer.extend({ [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/app/data/models/twitch/channel/model.js b/src/app/data/models/twitch/channel/model.js index 30a9f10333..fe3093b932 100644 --- a/src/app/data/models/twitch/channel/model.js +++ b/src/app/data/models/twitch/channel/model.js @@ -1,4 +1,4 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import { inject as service } from "@ember/service"; import attr from "ember-data/attr"; import Model from "ember-data/model"; @@ -7,84 +7,111 @@ import { ATTR_STREAMS_NAME_ORIGINAL, ATTR_STREAMS_NAME_BOTH } from "data/models/settings/streams/fragment"; +import { name } from "utils/decorators"; const reLang = /^([a-z]{2})(:?-([a-z]{2}))?$/; -export default Model.extend({ - i18n: service(), - settings: service(), +@name( "kraken/channels" ) +export default class TwitchChannel extends Model { + /** @type {I18nService} */ + @service i18n; + /** @type {SettingsService} */ + @service settings; + + + @attr( "string" ) + broadcaster_language; + @attr( "date" ) + created_at; + @attr( "string" ) + display_name; + @attr( "number" ) + followers; + @attr( "string" ) + game; + @attr( "string" ) + language; + @attr( "string" ) + logo; + @attr( "boolean" ) + mature; + @attr( "string" ) + name; + @attr( "boolean" ) + partner; + @attr( "string" ) + profile_banner; + @attr( "string" ) + profile_banner_background_color; + @attr( "string" ) + status; + @attr( "date" ) + updated_at; + @attr( "string" ) + url; + @attr( "string" ) + video_banner; + @attr( "number" ) + views; - broadcaster_language: attr( "string" ), - created_at: attr( "date" ), - display_name: attr( "string" ), - followers: attr( "number" ), - game: attr( "string" ), - language: attr( "string" ), - logo: attr( "string" ), - mature: attr( "boolean" ), - name: attr( "string" ), - partner: attr( "boolean" ), - profile_banner: attr( "string" ), - profile_banner_background_color: attr( "string" ), - status: attr( "string" ), - updated_at: attr( "date" ), - url: attr( "string" ), - video_banner: attr( "string" ), - views: attr( "number" ), + /** @type {(TwitchSubscription|boolean)} subscribed */ + subscribed = null; + /** @type {(TwitchChannelFollowed|boolean)} following */ + followed = null; - hasCustomDisplayName: computed( "name", "display_name", function() { - return get( this, "name" ).toLowerCase() !== get( this, "display_name" ).toLowerCase(); - }), - detailedName: computed( + @computed( "name", "display_name" ) + get hasCustomDisplayName() { + return this.name.toLowerCase() !== this.display_name.toLowerCase(); + } + + @computed( "name", "display_name", "hasCustomDisplayName", - "settings.streams.name", - function() { - switch ( get( this, "settings.streams.name" ) ) { - case ATTR_STREAMS_NAME_CUSTOM: - return get( this, "display_name" ); - case ATTR_STREAMS_NAME_ORIGINAL: - return get( this, "name" ); - case ATTR_STREAMS_NAME_BOTH: - return get( this, "hasCustomDisplayName" ) - ? `${get( this, "display_name" )} (${get( this, "name" )})` - : get( this, "display_name" ); - } + "settings.content.streams.name" + ) + get detailedName() { + switch ( this.settings.content.streams.name ) { + case ATTR_STREAMS_NAME_ORIGINAL: + return this.name; + case ATTR_STREAMS_NAME_BOTH: + return this.hasCustomDisplayName + ? `${this.display_name} (${this.name})` + : this.display_name; + case ATTR_STREAMS_NAME_CUSTOM: + default: + return this.display_name; } - ), - - - titleFollowers: computed( "i18n.locale", "followers", function() { - const i18n = get( this, "i18n" ); - const count = get( this, "followers" ); + } - return i18n.t( "models.twitch.channel.followers", { count } ); - }), - titleViews: computed( "i18n.locale", "views", function() { - const i18n = get( this, "i18n" ); - const count = get( this, "views" ); + @computed( "i18n.locale", "followers" ) + get titleFollowers() { + return this.i18n.t( "models.twitch.channel.followers", { count: this.followers } ); + } - return i18n.t( "models.twitch.channel.views", { count } ); - }), + @computed( "i18n.locale", "views" ) + get titleViews() { + return this.i18n.t( "models.twitch.channel.views", { count: this.views } ); + } - hasLanguage: computed( "language", function() { - const lang = get( this, "language" ); + @computed( "language" ) + get hasLanguage() { + const language = this.language; - return !!lang && lang !== "other"; - }), + return !!language && language !== "other"; + } - hasBroadcasterLanguage: computed( "broadcaster_language", "language", function() { - const broadcaster = get( this, "broadcaster_language" ); - const language = get( this, "language" ); - const mBroadcaster = reLang.exec( broadcaster ); + @computed( "broadcaster_language", "language" ) + get hasBroadcasterLanguage() { + const { broadcaster_language, language } = this; + const mBroadcaster = reLang.exec( broadcaster_language ); const mLanguage = reLang.exec( language ); // show the broadcaster_language only if it is set and @@ -92,28 +119,21 @@ export default Model.extend({ // 2. the language is different from the broadcaster_language // WITHOUT comparing both lang variants return !!mBroadcaster && ( !mLanguage || mLanguage[1] !== mBroadcaster[1] ); - }), - - - /** @type {(TwitchSubscription|boolean)} subscribed */ - subscribed: null, - - /** @type {(TwitchChannelFollowed|boolean)} following */ - followed: null, + } /** * Load channel specific settings - * @returns {Promise} + * @returns {Promise} */ getChannelSettings() { - const store = get( this, "store" ); - const id = get( this, "name" ); + const store = this.store; + const name = this.name; // For a very weird reason, exceptions thrown by store.findRecord() are not being caught // when using an async function and a try/catch block with the await keyword. // So use a regular promise chain here instead. - return store.findRecord( "channelSettings", id ) - .catch( () => store.recordForId( "channelSettings", id ) ) + return store.findRecord( "channel-settings", name ) + .catch( () => store.recordForId( "channel-settings", name ) ) .then( record => { // get the record's data and then unload it const data = record.toJSON(); @@ -122,7 +142,4 @@ export default Model.extend({ return data; }); } - -}).reopenClass({ - toString() { return "kraken/channels"; } -}); +} diff --git a/src/app/data/models/twitch/channel/serializer.js b/src/app/data/models/twitch/channel/serializer.js index 1d5f9c4800..4e1c832b76 100644 --- a/src/app/data/models/twitch/channel/serializer.js +++ b/src/app/data/models/twitch/channel/serializer.js @@ -1,16 +1,14 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchChannel"; - }, +export default class TwitchChannelSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-channel"; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { payload = { - twitchChannel: payload + [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/app/data/models/twitch/game-top/model.js b/src/app/data/models/twitch/game-top/model.js index 139a56b9cf..952cf5d00c 100644 --- a/src/app/data/models/twitch/game-top/model.js +++ b/src/app/data/models/twitch/game-top/model.js @@ -1,13 +1,16 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - channels: attr( "number" ), - game: belongsTo( "twitchGame", { async: false } ), - viewers: attr( "number" ) - -}).reopenClass({ - toString() { return "kraken/games/top"; } -}); +@name( "kraken/games/top" ) +export default class TwitchGameTop extends Model { + @attr( "number" ) + channels; + /** @type {TwitchGame} */ + @belongsTo( "twitch-game", { async: false } ) + game; + @attr( "number" ) + viewers; +} diff --git a/src/app/data/models/twitch/game-top/serializer.js b/src/app/data/models/twitch/game-top/serializer.js index f3971767b9..e2e8474940 100644 --- a/src/app/data/models/twitch/game-top/serializer.js +++ b/src/app/data/models/twitch/game-top/serializer.js @@ -1,21 +1,19 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchGameTop"; - }, +export default class TwitchGameTopSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-game-top"; - attrs: { + attrs = { game: { deserialize: "records" } - }, + }; normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchGame" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-game" ).primaryKey; // get the id of the embedded TwitchGame record and apply it here resourceHash[ this.primaryKey ] = resourceHash.game[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/game/model.js b/src/app/data/models/twitch/game/model.js index 38e7f33a2b..3b98d86b72 100644 --- a/src/app/data/models/twitch/game/model.js +++ b/src/app/data/models/twitch/game/model.js @@ -1,15 +1,21 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - box: belongsTo( "twitchImage", { async: false } ), - //giantbomb_id: attr( "number" ), - logo: belongsTo( "twitchImage", { async: false } ), - name: attr( "string" ) - //popularity: attr( "number" ) - -}).reopenClass({ - toString() { return "kraken/games"; } -}); +@name( "kraken/games" ) +export default class TwitchGame extends Model { + /** @type {TwitchImage} */ + @belongsTo( "twitch-image", { async: false } ) + box; + //@attr( "number" ) + //giantbomb_id; + /** @type {TwitchImage} */ + @belongsTo( "twitch-image", { async: false } ) + logo; + @attr( "string" ) + name; + //@attr( "number" ) + //popularity; +} diff --git a/src/app/data/models/twitch/game/serializer.js b/src/app/data/models/twitch/game/serializer.js index 0b3bde3e0a..27497293f7 100644 --- a/src/app/data/models/twitch/game/serializer.js +++ b/src/app/data/models/twitch/game/serializer.js @@ -1,21 +1,19 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - primaryKey: "name", +export default class TwitchGameSerializer extends TwitchSerializer { + primaryKey = "name"; - modelNameFromPayloadKey() { - return "twitchGame"; - }, + modelNameFromPayloadKey = () => "twitch-game"; - attrs: { + attrs = { box: { deserialize: "records" }, logo: { deserialize: "records" } - }, + }; normalize( modelClass, resourceHash, prop ) { const id = resourceHash[ this.primaryKey ]; - const foreignKey = this.store.serializerFor( "twitchImage" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-image" ).primaryKey; // apply the id of this record to the embedded TwitchImage records (box and logo) if ( resourceHash.box ) { @@ -25,6 +23,6 @@ export default TwitchSerializer.extend({ resourceHash.logo[ foreignKey ] = `game/logo/${id}`; } - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/image/model.js b/src/app/data/models/twitch/image/model.js index 7206a1ad30..78c92eb851 100644 --- a/src/app/data/models/twitch/image/model.js +++ b/src/app/data/models/twitch/image/model.js @@ -14,71 +14,72 @@ function getURL( url, time ) { * Return the image URL with an already set expiration time. * Or create a new expiration time if it hasn't been set yet. * @param {string} attr - * @returns {string} + * @returns {function(): PropertyDescriptor} */ -function buffered( attr ) { - const exp = this[ `expiration_${attr}` ]; +const buffered = attr => () => ({ + get() { + const exp = this[ `expiration_${attr}` ]; - return exp - ? getURL( this[ `image_${attr}` ], exp ) - : this[ `${attr}Latest` ]; -} + return exp + ? getURL( this[ `image_${attr}` ], exp ) + : this[ `${attr}Latest` ]; + } +}); /** * Return the image URL with an expiration parameter, so the latest version will be requested. * Update the expiration timer only once every X seconds. * @param {string} attr - * @returns {string} + * @returns {function(): PropertyDescriptor} */ -function latest( attr ) { - const url = this[ `image_${attr}` ]; +const latest = attr => () => ({ + get() { + const url = this[ `image_${attr}` ]; - // use the same timestamp for `time` seconds - const key = `expiration_${attr}`; - const now = Date.now(); - let exp = this[ key ]; + // use the same timestamp for `time` seconds + const key = `expiration_${attr}`; + const now = Date.now(); + let exp = this[ key ]; - if ( !exp || exp <= now ) { - exp = now + time; - this[ key ] = exp; - } + if ( !exp || exp <= now ) { + exp = now + time; + this[ key ] = exp; + } - return getURL( url, exp ); -} + return getURL( url, exp ); + } +}); -export default Model.extend({ +export default class TwitchImage extends Model { // original attributes (renamed) - image_large: attr( "string" ), - image_medium: attr( "string" ), - image_small: attr( "string" ), + @attr( "string" ) + image_large; + @attr( "string" ) + image_medium; + @attr( "string" ) + image_small; // expiration times - expiration_large: null, - expiration_medium: null, - expiration_small: null, + expiration_large = null; + expiration_medium = null; + expiration_small = null; // "request latest image version, but only every X seconds" // should be used by a route's model hook - get largeLatest() { - return latest.call( this, "large" ); - }, - get mediumLatest() { - return latest.call( this, "medium" ); - }, - get smallLatest() { - return latest.call( this, "small" ); - }, + @latest( "large" ) + largeLatest; + @latest( "medium" ) + mediumLatest; + @latest( "small" ) + smallLatest; // "use the previous expiration parameter" // should be used by all image src attributes in the DOM - get large() { - return buffered.call( this, "large" ); - }, - get medium() { - return buffered.call( this, "medium" ); - }, - get small() { - return buffered.call( this, "small" ); - } -}); + @buffered( "large" ) + large; + @buffered( "medium" ) + medium; + @buffered( "small" ) + small; +} diff --git a/src/app/data/models/twitch/image/serializer.js b/src/app/data/models/twitch/image/serializer.js index fe313266d2..7269b6ff92 100644 --- a/src/app/data/models/twitch/image/serializer.js +++ b/src/app/data/models/twitch/image/serializer.js @@ -1,12 +1,12 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ +export default class TwitchImageSerializer extends TwitchSerializer { normalize( modelClass, resourceHash, prop ) { resourceHash.image_small = resourceHash.small; resourceHash.image_medium = resourceHash.medium; resourceHash.image_large = resourceHash.large; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/root/model.js b/src/app/data/models/twitch/root/model.js index 7a9021da7f..5d8bdafc51 100644 --- a/src/app/data/models/twitch/root/model.js +++ b/src/app/data/models/twitch/root/model.js @@ -1,20 +1,21 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; import { array } from "ember-data-model-fragments/attributes"; +import { name } from "utils/decorators"; -/** - * @class TwitchRoot - * @extends Model - */ -export default Model.extend({ - created_at: attr( "date" ), - scopes: array( "string" ), - updated_at: attr( "date" ), - user_id: attr( "number" ), - user_name: attr( "string" ), - valid: attr( "boolean" ) - -}).reopenClass({ - toString() { return "kraken/"; } -}); +@name( "kraken/" ) +export default class TwitchRoot extends Model { + @attr( "date" ) + created_at; + @array( "string" ) + scopes; + @attr( "date" ) + updated_at; + @attr( "number" ) + user_id; + @attr( "string" ) + user_name; + @attr( "boolean" ) + valid; +} diff --git a/src/app/data/models/twitch/root/serializer.js b/src/app/data/models/twitch/root/serializer.js index d27542972d..f327945c00 100644 --- a/src/app/data/models/twitch/root/serializer.js +++ b/src/app/data/models/twitch/root/serializer.js @@ -1,10 +1,8 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchRoot"; - }, +export default class TwitchRootSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-root"; normalize( modelClass, resourceHash, prop ) { // add an ID to the record @@ -16,6 +14,6 @@ export default TwitchSerializer.extend({ resourceHash.created_at = created_at; resourceHash.updated_at = updated_at; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/search-channel/model.js b/src/app/data/models/twitch/search-channel/model.js index 91ab6ca044..e02151a5cf 100644 --- a/src/app/data/models/twitch/search-channel/model.js +++ b/src/app/data/models/twitch/search-channel/model.js @@ -1,10 +1,11 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - channel: belongsTo( "twitchChannel", { async: false } ) - -}).reopenClass({ - toString() { return "kraken/search/channels"; } -}); +@name( "kraken/search/channels" ) +export default class TwitchSearchChannel extends Model { + /** @type {TwitchChannel} */ + @belongsTo( "twitch-channel", { async: false } ) + channel; +} diff --git a/src/app/data/models/twitch/search-channel/serializer.js b/src/app/data/models/twitch/search-channel/serializer.js index 48bc5b0e12..0b6a264800 100644 --- a/src/app/data/models/twitch/search-channel/serializer.js +++ b/src/app/data/models/twitch/search-channel/serializer.js @@ -1,28 +1,26 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchSearchChannel"; - }, +export default class TwitchSearchChannelSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-search-channel"; - attrs: { + attrs = { channel: { deserialize: "records" } - }, + }; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { // fix payload format payload.channels = ( payload.channels || [] ).map( channel => ({ channel }) ); - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); + } normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here resourceHash[ this.primaryKey ] = resourceHash.channel[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/search-game/model.js b/src/app/data/models/twitch/search-game/model.js index 46bdd512ea..42a7ff3002 100644 --- a/src/app/data/models/twitch/search-game/model.js +++ b/src/app/data/models/twitch/search-game/model.js @@ -1,10 +1,11 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - game: belongsTo( "twitchGame", { async: false } ) - -}).reopenClass({ - toString() { return "kraken/search/games"; } -}); +@name( "kraken/search/games" ) +export default class TwitchSearchGame extends Model { + /** @type {TwitchGame} */ + @belongsTo( "twitch-game", { async: false } ) + game; +} diff --git a/src/app/data/models/twitch/search-game/serializer.js b/src/app/data/models/twitch/search-game/serializer.js index ffc84432ba..a3fa5e939b 100644 --- a/src/app/data/models/twitch/search-game/serializer.js +++ b/src/app/data/models/twitch/search-game/serializer.js @@ -1,28 +1,26 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchSearchGame"; - }, +export default class TwitchSearchGameSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-search-game"; - attrs: { + attrs = { game: { deserialize: "records" } - }, + }; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { // fix payload format payload.games = ( payload.games || [] ).map( game => ({ game }) ); - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); + } normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchGame" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-game" ).primaryKey; // get the id of the embedded TwitchGame record and apply it here resourceHash[ this.primaryKey ] = resourceHash.game[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/search-stream/model.js b/src/app/data/models/twitch/search-stream/model.js index 72ee9a1471..241f3ca5ab 100644 --- a/src/app/data/models/twitch/search-stream/model.js +++ b/src/app/data/models/twitch/search-stream/model.js @@ -1,10 +1,11 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - stream: belongsTo( "twitchStream", { async: false } ) - -}).reopenClass({ - toString() { return "kraken/search/streams"; } -}); +@name( "kraken/search/streams" ) +export default class TwitchSearchStream extends Model { + /** @type {TwitchStream} */ + @belongsTo( "twitch-stream", { async: false } ) + stream; +} diff --git a/src/app/data/models/twitch/search-stream/serializer.js b/src/app/data/models/twitch/search-stream/serializer.js index 810ce61b54..c3ecc17b2c 100644 --- a/src/app/data/models/twitch/search-stream/serializer.js +++ b/src/app/data/models/twitch/search-stream/serializer.js @@ -1,28 +1,26 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchSearchStream"; - }, +export default class TwitchSearchStreamSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-search-stream"; - attrs: { + attrs = { stream: { deserialize: "records" } - }, + }; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { // fix payload format payload.streams = ( payload.streams || [] ).map( stream => ({ stream }) ); - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); + } normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here resourceHash[ this.primaryKey ] = resourceHash.stream.channel[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/serializer.js b/src/app/data/models/twitch/serializer.js index 7fe94c8303..a1cd250c10 100644 --- a/src/app/data/models/twitch/serializer.js +++ b/src/app/data/models/twitch/serializer.js @@ -2,10 +2,10 @@ import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin" import RESTSerializer from "ember-data/serializers/rest"; -export default RESTSerializer.extend( EmbeddedRecordsMixin, { - isNewSerializerAPI: true, +export default class TwitchSerializer extends RESTSerializer.extend( EmbeddedRecordsMixin ) { + isNewSerializerAPI = true; - primaryKey: "_id", + primaryKey = "_id"; /** * All underscored properties contain metadata (except the primaryKey) @@ -19,7 +19,7 @@ export default RESTSerializer.extend( EmbeddedRecordsMixin, { const primaryKey = this.primaryKey; const data = {}; - Object.keys( payload ).forEach(function( key ) { + Object.keys( payload ).forEach( key => { if ( key.charAt( 0 ) === "_" && key !== primaryKey ) { data[ key.substr( 1 ) ] = payload[ key ]; delete payload[ key ]; @@ -28,4 +28,4 @@ export default RESTSerializer.extend( EmbeddedRecordsMixin, { return data; } -}); +} diff --git a/src/app/data/models/twitch/stream-featured/model.js b/src/app/data/models/twitch/stream-featured/model.js index d450bae1c8..4bf40ad8b9 100644 --- a/src/app/data/models/twitch/stream-featured/model.js +++ b/src/app/data/models/twitch/stream-featured/model.js @@ -1,17 +1,24 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - image: attr( "string" ), - priority: attr( "number" ), - scheduled: attr( "boolean" ), - sponsored: attr( "boolean" ), - stream: belongsTo( "twitchStream", { async: false } ), - text: attr( "string" ), - title: attr( "string" ) - -}).reopenClass({ - toString() { return "kraken/streams/featured"; } -}); +@name( "kraken/streams/featured" ) +export default class TwitchStreamFeatured extends Model { + @attr( "string" ) + image; + @attr( "number" ) + priority; + @attr( "boolean" ) + scheduled; + @attr( "boolean" ) + sponsored; + /** @type {TwitchStream} */ + @belongsTo( "twitch-stream", { async: false } ) + stream; + @attr( "string" ) + text; + @attr( "string" ) + title; +} diff --git a/src/app/data/models/twitch/stream-featured/serializer.js b/src/app/data/models/twitch/stream-featured/serializer.js index e40ea0bfa9..6e225c85e1 100644 --- a/src/app/data/models/twitch/stream-featured/serializer.js +++ b/src/app/data/models/twitch/stream-featured/serializer.js @@ -1,21 +1,19 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchStreamFeatured"; - }, +export default class TwitchStreamFeaturedSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-stream-featured"; - attrs: { + attrs = { stream: { deserialize: "records" } - }, + }; normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here resourceHash[ this.primaryKey ] = resourceHash.stream.channel[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/stream-followed/model.js b/src/app/data/models/twitch/stream-followed/model.js index 6ee90dbae9..fa605fe23a 100644 --- a/src/app/data/models/twitch/stream-followed/model.js +++ b/src/app/data/models/twitch/stream-followed/model.js @@ -1,10 +1,11 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - stream: belongsTo( "twitchStream", { async: false } ) - -}).reopenClass({ - toString() { return "kraken/streams/followed"; } -}); +@name( "kraken/streams/followed" ) +export default class TwitchStreamFollowed extends Model { + /** @type {TwitchStream} */ + @belongsTo( "twitch-stream", { async: false } ) + stream; +} diff --git a/src/app/data/models/twitch/stream-followed/serializer.js b/src/app/data/models/twitch/stream-followed/serializer.js index 7e8d99b2dc..c296ce28ad 100644 --- a/src/app/data/models/twitch/stream-followed/serializer.js +++ b/src/app/data/models/twitch/stream-followed/serializer.js @@ -1,28 +1,26 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchStreamFollowed"; - }, +export default class TwitchStreamFollowedSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-stream-followed"; - attrs: { + attrs = { stream: { deserialize: "records" } - }, + }; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { // fix payload format payload.streams = ( payload.streams || [] ).map( stream => ({ stream }) ); - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); + } normalize( modelClass, resourceHash, prop ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here resourceHash[ this.primaryKey ] = resourceHash.stream.channel[ foreignKey ]; - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/stream-summary/model.js b/src/app/data/models/twitch/stream-summary/model.js index e45af39e3f..9b2a4f0af9 100644 --- a/src/app/data/models/twitch/stream-summary/model.js +++ b/src/app/data/models/twitch/stream-summary/model.js @@ -1,11 +1,12 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend({ - channels: attr( "number" ), - viewers: attr( "number" ) - -}).reopenClass({ - toString() { return "kraken/streams/summary"; } -}); +@name( "kraken/streams/summary" ) +export default class TwitchStreamSummary extends Model { + @attr( "number" ) + channels; + @attr( "number" ) + viewers; +} diff --git a/src/app/data/models/twitch/stream-summary/serializer.js b/src/app/data/models/twitch/stream-summary/serializer.js index 04ab2c9e1a..ac7c99ebd6 100644 --- a/src/app/data/models/twitch/stream-summary/serializer.js +++ b/src/app/data/models/twitch/stream-summary/serializer.js @@ -1,10 +1,8 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchStreamSummary"; - }, +export default class TwitchStreamSummarySerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-stream-summary"; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { // always use 1 as id @@ -12,9 +10,9 @@ export default TwitchSerializer.extend({ // fix payload format payload = { - twitchStreamSummary: payload + [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/app/data/models/twitch/stream/model.js b/src/app/data/models/twitch/stream/model.js index 32534d6f54..ae0b90a20d 100644 --- a/src/app/data/models/twitch/stream/model.js +++ b/src/app/data/models/twitch/stream/model.js @@ -1,4 +1,4 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import { and } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import attr from "ember-data/attr"; @@ -6,6 +6,7 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; import Moment from "moment"; import { DEFAULT_VODCAST_REGEXP } from "data/models/settings/streams/fragment"; +import { name } from "utils/decorators"; /** @@ -38,26 +39,43 @@ const fpsRanges = [ const reRerun = /rerun|watch_party/; -export default Model.extend({ - i18n: service(), - settings: service(), - - - average_fps: attr( "number" ), - broadcast_platform: attr( "string" ), - channel: belongsTo( "twitchChannel", { async: false } ), - created_at: attr( "date" ), - delay: attr( "number" ), - game: attr( "string" ), - //is_playlist: attr( "boolean" ), - preview: belongsTo( "twitchImage", { async: false } ), - stream_type: attr( "string" ), - video_height: attr( "number" ), - viewers: attr( "number" ), - - - reVodcast: computed( "settings.streams.vodcast_regexp", function() { - const vodcast_regexp = get( this, "settings.streams.vodcast_regexp" ); +@name( "kraken/streams" ) +export default class TwitchStream extends Model { + /** @type {I18nService} */ + @service i18n; + /** @type {SettingsService} */ + @service settings; + + + @attr( "number" ) + average_fps; + @attr( "string" ) + broadcast_platform; + /** @type {TwitchChannel} */ + @belongsTo( "twitch-channel", { async: false } ) + channel; + @attr( "date" ) + created_at; + @attr( "number" ) + delay; + @attr( "string" ) + game; + //@attr( "boolean" ) + //is_playlist; + /** @type {TwitchImage} */ + @belongsTo( "twitch-image", { async: false } ) + preview; + @attr( "string" ) + stream_type; + @attr( "number" ) + video_height; + @attr( "number" ) + viewers; + + + @computed( "settings.content.streams.vodcast_regexp" ) + get reVodcast() { + const vodcast_regexp = this.settings.content.streams.vodcast_regexp; if ( vodcast_regexp.length && !vodcast_regexp.trim().length ) { return null; } @@ -66,36 +84,38 @@ export default Model.extend({ } catch ( e ) { return null; } - }), + } // both properties are not documented in the v5 API - isVodcast: computed( + @computed( "broadcast_platform", "stream_type", "reVodcast", - "channel.status", - function() { - if ( - reRerun.test( get( this, "broadcast_platform" ) ) - || reRerun.test( get( this, "stream_type" ) ) - ) { - return true; - } - - const reVodcast = get( this, "reVodcast" ); - const status = get( this, "channel.status" ); - - return reVodcast && status - ? reVodcast.test( status ) - : false; + "channel.status" + ) + get isVodcast() { + if ( + reRerun.test( this.broadcast_platform ) + || reRerun.test( this.stream_type ) + ) { + return true; } - ), + const reVodcast = this.reVodcast; + const status = this.channel.status; + + return reVodcast && status + ? reVodcast.test( status ) + : false; + } - hasFormatInfo: and( "video_height", "average_fps" ), + @and( "video_height", "average_fps" ) + hasFormatInfo; - titleCreatedAt: computed( "i18n.locale", "created_at", function() { + + @computed( "i18n.locale", "created_at" ) + get titleCreatedAt() { const moment = new Moment( this.created_at ); const last24h = moment.diff( new Date(), "days" ) === 0; const format = last24h @@ -103,27 +123,26 @@ export default Model.extend({ : this.i18n.t( "models.twitch.stream.created-at.more-than-24h" ); return moment.format( format.toString() ); - }), - - titleViewers: computed( "i18n.locale", "viewers", function() { - const i18n = get( this, "i18n" ); - const count = get( this, "viewers" ); + } - return i18n.t( "models.twitch.stream.viewers", { count } ); - }), + @computed( "i18n.locale", "viewers" ) + get titleViewers() { + return this.i18n.t( "models.twitch.stream.viewers", { count: this.viewers } ); + } - resolution: computed( "video_height", function() { + @computed( "video_height" ) + get resolution() { // assume 16:9 - const video_height = get( this, "video_height" ); + const video_height = this.video_height; const width = Math.round( ( 16 / 9 ) * video_height ); const height = Math.round( video_height ); return `${width}x${height}`; - }), - - fps: computed( "average_fps", function() { - const average_fps = get( this, "average_fps" ); + } + @computed( "average_fps" ) + get fps() { + const average_fps = this.average_fps; if ( !average_fps ) { return null; } const fpsRange = fpsRanges.find( fpsRange => @@ -134,8 +153,5 @@ export default Model.extend({ return fpsRange ? fpsRange.target : Math.floor( average_fps ); - }) - -}).reopenClass({ - toString() { return "kraken/streams"; } -}); + } +} diff --git a/src/app/data/models/twitch/stream/serializer.js b/src/app/data/models/twitch/stream/serializer.js index 776c6ca736..f402e58429 100644 --- a/src/app/data/models/twitch/stream/serializer.js +++ b/src/app/data/models/twitch/stream/serializer.js @@ -1,19 +1,17 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchStream"; - }, +export default class TwitchStreamSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-stream"; - attrs: { + attrs = { channel: { deserialize: "records" }, preview: { deserialize: "records" } - }, + }; normalize( modelClass, resourceHash, prop ) { - const foreignKeyChannel = this.store.serializerFor( "twitchChannel" ).primaryKey; - const foreignKeyImage = this.store.serializerFor( "twitchImage" ).primaryKey; + const foreignKeyChannel = this.store.serializerFor( "twitch-channel" ).primaryKey; + const foreignKeyImage = this.store.serializerFor( "twitch-image" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here // this is required for refreshing the record so that the correct id is being used @@ -25,6 +23,6 @@ export default TwitchSerializer.extend({ resourceHash.preview[ foreignKeyImage ] = `stream/preview/${id}`; } - return this._super( modelClass, resourceHash, prop ); + return super.normalize( modelClass, resourceHash, prop ); } -}); +} diff --git a/src/app/data/models/twitch/subscription/model.js b/src/app/data/models/twitch/subscription/model.js index 35b15c20af..de171d8e32 100644 --- a/src/app/data/models/twitch/subscription/model.js +++ b/src/app/data/models/twitch/subscription/model.js @@ -1,14 +1,18 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend({ - //channel: belongsTo( "twitchChannel" ), - //is_gift: attr( "boolean" ), - //sender: attr( "number or string???" ), - //sub_plan: attr( "string" ), - created_at: attr( "date" ) - -}).reopenClass({ - toString() { return "kraken/users/:user_id/subscriptions"; } -}); +@name( "kraken/users/:user_id/subscriptions" ) +export default class TwitchSubscription extends Model { + //@belongsTo( "twitch-channel" ) + //channel; + //@attr( "boolean" ) + //is_gift; + //@attr( "number or string???" ) + //sender; + //@attr( "string" ) + //sub_plan; + @attr( "date" ) + created_at; +} diff --git a/src/app/data/models/twitch/subscription/serializer.js b/src/app/data/models/twitch/subscription/serializer.js index 641fc1c1ef..4457685420 100644 --- a/src/app/data/models/twitch/subscription/serializer.js +++ b/src/app/data/models/twitch/subscription/serializer.js @@ -1,22 +1,20 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - modelNameFromPayloadKey() { - return "twitchSubscription"; - }, +export default class TwitchSubscriptionSerializer extends TwitchSerializer { + modelNameFromPayloadKey = () => "twitch-subscription"; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { - const foreignKey = this.store.serializerFor( "twitchChannel" ).primaryKey; + const foreignKey = this.store.serializerFor( "twitch-channel" ).primaryKey; // get the id of the embedded TwitchChannel record and apply it here payload[ this.primaryKey ] = payload.channel[ foreignKey ]; // fix payload format payload = { - twitchSubscription: payload + [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/app/data/models/twitch/team/model.js b/src/app/data/models/twitch/team/model.js index 022c50504e..0de4eda5cc 100644 --- a/src/app/data/models/twitch/team/model.js +++ b/src/app/data/models/twitch/team/model.js @@ -1,26 +1,34 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import attr from "ember-data/attr"; import Model from "ember-data/model"; import { hasMany } from "ember-data/relationships"; +import { name } from "utils/decorators"; -export default Model.extend({ - background: attr( "string" ), - banner: attr( "string" ), - created_at: attr( "date" ), - display_name: attr( "string" ), - info: attr( "string" ), - logo: attr( "string" ), - name: attr( "string" ), - updated_at: attr( "date" ), - users: hasMany( "twitchChannel", { async: false } ), +@name( "kraken/teams" ) +export default class TwitchTeam extends Model { + @attr( "string" ) + background; + @attr( "string" ) + banner; + @attr( "date" ) + created_at; + @attr( "string" ) + display_name; + @attr( "string" ) + info; + @attr( "string" ) + logo; + @attr( "string" ) + name; + @attr( "date" ) + updated_at; + /** @type {TwitchChannel[]} */ + @hasMany( "twitch-channel", { async: false } ) + users; - - title: computed( "name", "display_name", function() { - return get( this, "display_name" ) - || get( this, "name" ); - }) - -}).reopenClass({ - toString() { return "kraken/teams"; } -}); + @computed( "name", "display_name" ) + get title() { + return this.display_name || this.name; + } +} diff --git a/src/app/data/models/twitch/team/serializer.js b/src/app/data/models/twitch/team/serializer.js index ef7f6e27a8..32c9dabc1e 100644 --- a/src/app/data/models/twitch/team/serializer.js +++ b/src/app/data/models/twitch/team/serializer.js @@ -1,16 +1,14 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - primaryKey: "name", +export default class TwitchTeamSerializer extends TwitchSerializer { + primaryKey = "name"; - modelNameFromPayloadKey() { - return "twitchTeam"; - }, + modelNameFromPayloadKey = () => "twitch-team"; - attrs: { + attrs = { users: { deserialize: "records" } - }, + }; normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ) { // fix payload format @@ -18,6 +16,6 @@ export default TwitchSerializer.extend({ [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/app/data/models/twitch/user/model.js b/src/app/data/models/twitch/user/model.js index 7b36416a3a..5829f7ec12 100644 --- a/src/app/data/models/twitch/user/model.js +++ b/src/app/data/models/twitch/user/model.js @@ -1,18 +1,21 @@ import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { name } from "utils/decorators"; /** - * This model is only being used for mapping channel names to user IDs. - * Users are being looked up via GET /kraken/users?login=:name + * This model only gets used for mapping channel names to user IDs. + * Users are looked up via GET /kraken/users?login=:name * * The primary key is the user/channel name, so it can be looked up via store.findRecord. * The original primary key (_id) is used as a key for TwitchChannel/TwitchStream relationships. */ -export default Model.extend({ - channel: belongsTo( "twitchChannel", { async: true } ), - stream: belongsTo( "twitchStream", { async: true } ) - -}).reopenClass({ - toString() { return "kraken/users"; } -}); +@name( "kraken/users" ) +export default class TwitchUser extends Model { + /** @type {PromiseObject} */ + @belongsTo( "twitch-channel", { async: true } ) + channel; + /** @type {PromiseObject} */ + @belongsTo( "twitch-stream", { async: true } ) + stream; +} diff --git a/src/app/data/models/twitch/user/serializer.js b/src/app/data/models/twitch/user/serializer.js index 1f07327705..59c3e4fed1 100644 --- a/src/app/data/models/twitch/user/serializer.js +++ b/src/app/data/models/twitch/user/serializer.js @@ -1,12 +1,10 @@ import TwitchSerializer from "data/models/twitch/serializer"; -export default TwitchSerializer.extend({ - primaryKey: "id", +export default class TwitchUserSerializer extends TwitchSerializer { + primaryKey = "id"; - modelNameFromPayloadKey() { - return "twitchUser"; - }, + modelNameFromPayloadKey = () => "twitch-user"; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { payload = { @@ -18,17 +16,13 @@ export default TwitchSerializer.extend({ }) ) }; - return this._super( store, primaryModelClass, payload, id, requestType ); - }, + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); + } - normalizeFindRecordResponse( store, primaryModelClass, payload, id, requestType ) { + normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ) { const key = this.modelNameFromPayloadKey(); payload[ key ] = payload[ key ][0] /* istanbul ignore next */ || null; - return this._super( store, primaryModelClass, payload, id, requestType ); - }, - - normalizeQueryRecordResponse( ...args ) { - return this.normalizeFindRecordResponse( ...args ); + return super.normalizeSingleResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} diff --git a/src/test/tests/data/models/twitch/channel.js b/src/test/tests/data/models/twitch/channel.js index 01287b8e69..ffdb80efbe 100644 --- a/src/test/tests/data/models/twitch/channel.js +++ b/src/test/tests/data/models/twitch/channel.js @@ -38,7 +38,9 @@ module( "data/models/twitch/channel", { owner.register( "service:auth", Service.extend() ); owner.register( "service:i18n", FakeI18nService ); owner.register( "service:settings", Service.extend({ - streams: {} + content: { + streams: {} + } }) ); owner.register( "model:twitch-channel", Channel ); owner.register( "serializer:twitch-channel", ChannelSerializer ); @@ -122,7 +124,7 @@ test( "Computed properties", assert => { // detailedName - const settings = owner.lookup( "service:settings" ); + const settings = owner.lookup( "service:settings" ).content; run( () => set( settings, "streams.name", ATTR_STREAMS_NAME_CUSTOM ) ); assert.strictEqual( diff --git a/src/test/tests/data/models/twitch/stream.js b/src/test/tests/data/models/twitch/stream.js index e67e53c86e..3b7cb5009e 100644 --- a/src/test/tests/data/models/twitch/stream.js +++ b/src/test/tests/data/models/twitch/stream.js @@ -49,8 +49,10 @@ module( "data/models/twitch/stream", { owner.register( "service:auth", Service.extend() ); owner.register( "service:i18n", FakeI18nService ); owner.register( "service:settings", Service.extend({ - streams: { - vodcast_regexp: "" + content: { + streams: { + vodcast_regexp: "" + } } }) ); @@ -192,19 +194,20 @@ test( "Computed properties", function( assert ) { status: "" }); const record = env.store.createRecord( "twitchStream", { channel } ); + const settings = owner.lookup( "service:settings" ).content; // vodcast assert.ok( get( record, "reVodcast" ) instanceof RegExp, "Has a default vodcast RegExp" ); - set( record, "settings.streams.vodcast_regexp", " " ); + set( settings, "streams.vodcast_regexp", " " ); assert.strictEqual( get( record, "reVodcast" ), null, "Returns null on empty RegExp" ); - set( record, "settings.streams.vodcast_regexp", "(" ); + set( settings, "streams.vodcast_regexp", "(" ); assert.strictEqual( get( record, "reVodcast" ), null, "Returns null on invalid RegExp" ); - set( record, "settings.streams.vodcast_regexp", "I'm a vodcast" ); + set( settings, "streams.vodcast_regexp", "I'm a vodcast" ); assert.ok( get( record, "reVodcast" ).test( "I'M A VODCAST" ), "Has a custom vodcast RegExp" ); assert.notOk( get( record, "isVodcast" ), "Not a vodcast" ); From fdeb8604302226847aa1223e1c9577a8cfd5bd0e Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:33:16 +0200 Subject: [PATCH 14/34] native classes: github models and serializers --- src/app/data/models/github/releases/model.js | 62 ++++++++++++------- .../data/models/github/releases/serializer.js | 12 ++-- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/app/data/models/github/releases/model.js b/src/app/data/models/github/releases/model.js index ebdfe8a615..9b5e1b490c 100644 --- a/src/app/data/models/github/releases/model.js +++ b/src/app/data/models/github/releases/model.js @@ -1,30 +1,46 @@ import { computed } from "@ember/object"; import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend( /** @class GithubReleases */ { - assets: attr(), - assets_url: attr(), - author: attr(), - body: attr(), - created_at: attr(), - draft: attr( "boolean" ), - html_url: attr( "string" ), - name: attr(), - prerelease: attr(), - published_at: attr(), - tag_name: attr( "string" ), - tarball_url: attr(), - target_commitish: attr(), - upload_url: attr(), - url: attr(), - zipball_url: attr(), +@name( "releases" ) +export default class GithubReleases extends Model { + @attr + assets; + @attr + assets_url; + @attr + author; + @attr + body; + @attr + created_at; + @attr( "boolean" ) + draft; + @attr( "string" ) + html_url; + @attr + name; + @attr + prerelease; + @attr + published_at; + @attr( "string" ) + tag_name; + @attr + tarball_url; + @attr + target_commitish; + @attr + upload_url; + @attr + url; + @attr + zipball_url; - version: computed( "tag_name", function() { + @computed( "tag_name" ) + get version() { return this.tag_name.replace( /^v/, "" ); - }) - -}).reopenClass({ - toString() { return "releases"; } -}); + } +} diff --git a/src/app/data/models/github/releases/serializer.js b/src/app/data/models/github/releases/serializer.js index b5103a4f79..fe1b1b8880 100644 --- a/src/app/data/models/github/releases/serializer.js +++ b/src/app/data/models/github/releases/serializer.js @@ -1,16 +1,14 @@ import RESTSerializer from "ember-data/serializers/rest"; -export default RESTSerializer.extend({ - modelNameFromPayloadKey() { - return "githubReleases"; - }, +export default class GithubReleasesSerializer extends RESTSerializer { + modelNameFromPayloadKey = () => "github-releases"; normalizeResponse( store, primaryModelClass, payload, id, requestType ) { payload = { - githubReleases: payload + [ this.modelNameFromPayloadKey() ]: payload }; - return this._super( store, primaryModelClass, payload, id, requestType ); + return super.normalizeResponse( store, primaryModelClass, payload, id, requestType ); } -}); +} From 441ab2328de629541de9a70594983b9ef41bcd3b Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:34:05 +0200 Subject: [PATCH 15/34] native classes: LS models and adapters --- src/app/data/models/auth/adapter.js | 6 +-- src/app/data/models/auth/model.js | 38 +++++++------- .../data/models/channel-settings/adapter.js | 6 +-- src/app/data/models/channel-settings/model.js | 38 +++++++------- src/app/data/models/search/adapter.js | 6 +-- src/app/data/models/search/model.js | 50 +++++++++++-------- src/app/data/models/versioncheck/adapter.js | 6 +-- src/app/data/models/versioncheck/model.js | 18 ++++--- src/app/data/models/window/adapter.js | 6 +-- src/app/data/models/window/model.js | 24 +++++---- 10 files changed, 106 insertions(+), 92 deletions(-) diff --git a/src/app/data/models/auth/adapter.js b/src/app/data/models/auth/adapter.js index ce07c84946..45ecca7342 100644 --- a/src/app/data/models/auth/adapter.js +++ b/src/app/data/models/auth/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "auth" -}); +export default class AuthAdapter extends LocalStorageAdapter { + namespace = "auth"; +} diff --git a/src/app/data/models/auth/model.js b/src/app/data/models/auth/model.js index 05e9a2aa7b..cff4292c57 100644 --- a/src/app/data/models/auth/model.js +++ b/src/app/data/models/auth/model.js @@ -1,28 +1,28 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend( /** @class Auth */ { - access_token: attr( "string" ), - scope : attr( "string" ), - date : attr( "date" ), +@name( "Auth" ) +export default class Auth extends Model { + @attr( "string" ) + access_token; + @attr( "string" ) + scope; + @attr( "date" ) + date; - // volatile property - user_id: null, - user_name: null, + // runtime "attributes" + user_id = null; + user_name = null; // status properties - isPending : false, - isLoggedIn: computed( "access_token", "user_id", "isPending", function() { - let token = get( this, "access_token" ); - let id = get( this, "user_id" ); - let pending = get( this, "isPending" ); + isPending = false; - return token && id && !pending; - }) - -}).reopenClass({ - toString() { return "Auth"; } -}); + @computed( "access_token", "user_id", "isPending" ) + get isLoggedIn() { + return this.access_token && this.user_id && !this.isPending; + } +} diff --git a/src/app/data/models/channel-settings/adapter.js b/src/app/data/models/channel-settings/adapter.js index d20107e153..e7f03c3e1b 100644 --- a/src/app/data/models/channel-settings/adapter.js +++ b/src/app/data/models/channel-settings/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "channelsettings" -}); +export default class ChannelSettingsAdapter extends LocalStorageAdapter { + namespace = "channelsettings"; +} diff --git a/src/app/data/models/channel-settings/model.js b/src/app/data/models/channel-settings/model.js index 2e26b8c877..3972d78106 100644 --- a/src/app/data/models/channel-settings/model.js +++ b/src/app/data/models/channel-settings/model.js @@ -3,31 +3,31 @@ import Model from "ember-data/model"; import SettingsStreaming from "data/models/settings/streaming/fragment"; import SettingsStreams from "data/models/settings/streams/fragment"; import SettingsNotification from "data/models/settings/notification/fragment"; +import { name } from "utils/decorators"; -/** - * @type {Object.} - */ -const attributes = { - streaming_quality: [ SettingsStreaming, "quality", "streaming.quality" ], - streaming_low_latency: [ SettingsStreaming, "low_latency", "streaming.low_latency" ], - streaming_disable_ads: [ SettingsStreaming, "disable_ads", "streaming.disable_ads" ], - streams_chat_open: [ SettingsStreams, "chat_open", "streams.chat_open" ], - notification_enabled: [ SettingsNotification, "enabled", "notification.enabled" ] -}; - -for ( const [ name, [ settings, prop, settingsPath ] ] of Object.entries( attributes ) ) { - const meta = settings.metaForProperty( prop ); - if ( !meta || !meta.isAttribute ) { continue; } +const settingsAttribute = ( Settings, attribute, settingsPath ) => () => { + const meta = Settings.metaForProperty( attribute ); + if ( !meta || !meta.isAttribute ) { return; } - attributes[ name ] = attr( meta.type, { + return attr( meta.type, { defaultValue: null, // the ChannelSettingsController needs this attribute option settingsPath }); -} +}; -export default Model.extend( attributes ).reopenClass({ - toString() { return "ChannelSettings"; } -}); +@name( "ChannelSettings" ) +export default class ChannelSettings extends Model { + @settingsAttribute( SettingsStreaming, "quality", "streaming.quality" ) + streaming_quality; + @settingsAttribute( SettingsStreaming, "low_latency", "streaming.low_latency" ) + streaming_low_latency; + @settingsAttribute( SettingsStreaming, "disable_ads", "streaming.disable_ads" ) + streaming_disable_ads; + @settingsAttribute( SettingsStreams, "chat_open", "streams.chat_open" ) + streams_chat_open; + @settingsAttribute( SettingsNotification, "enabled", "notification.enabled" ) + notification_enabled; +} diff --git a/src/app/data/models/search/adapter.js b/src/app/data/models/search/adapter.js index 9ca079821a..095320a84a 100644 --- a/src/app/data/models/search/adapter.js +++ b/src/app/data/models/search/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "search" -}); +export default class SearchAdapter extends LocalStorageAdapter { + namespace = "search"; +} diff --git a/src/app/data/models/search/model.js b/src/app/data/models/search/model.js index 41dfcfa0c1..b8bb65e601 100644 --- a/src/app/data/models/search/model.js +++ b/src/app/data/models/search/model.js @@ -1,39 +1,47 @@ -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend({ - query : attr( "string" ), - filter: attr( "string" ), - date : attr( "date" ), +const { hasOwnProperty } = {}; - label: computed( "filter", function() { - const filter = get( this, "filter" ); - return this.constructor.getLabel( filter ); - }) -}).reopenClass({ - toString() { return "Search"; }, - - filters: [ +@name( "Search" ) +export default class Search extends Model { + static filters = [ { label: "All", id: "all" }, { label: "Game", id: "games" }, { label: "Channel", id: "channels" }, { label: "Stream", id: "streams" } - ], + ]; - filtersmap: computed(function() { + @computed() + static get filtersmap() { return this.filters.reduce( ( map, filter ) => { map[ filter.id ] = filter; + return map; }, {} ); - }), + } + + static getLabel( filter ) { + const { filtersmap } = this; - getLabel( filter ) { - const map = get( this, "filtersmap" ); - return map.hasOwnProperty( filter ) - ? map[ filter ].label + return hasOwnProperty.call( filtersmap, filter ) + ? filtersmap[ filter ].label : "All"; } -}); + + @attr( "string" ) + query; + @attr( "string" ) + filter; + @attr( "date" ) + date; + + @computed( "filter" ) + get label() { + return this.constructor.getLabel( this.filter ); + } +} diff --git a/src/app/data/models/versioncheck/adapter.js b/src/app/data/models/versioncheck/adapter.js index 37d8b4beea..53fc527b54 100644 --- a/src/app/data/models/versioncheck/adapter.js +++ b/src/app/data/models/versioncheck/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "versioncheck" -}); +export default class VersioncheckAdapter extends LocalStorageAdapter { + namespace = "versioncheck"; +} diff --git a/src/app/data/models/versioncheck/model.js b/src/app/data/models/versioncheck/model.js index 9a8d8dc360..6361546a1d 100644 --- a/src/app/data/models/versioncheck/model.js +++ b/src/app/data/models/versioncheck/model.js @@ -1,12 +1,14 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend({ - version: attr( "string", { defaultValue: "" } ), - checkagain: attr( "number", { defaultValue: 0 } ), - showdebugmessage: attr( "number", { defaultValue: 0 } ) - -}).reopenClass({ - toString() { return "Versioncheck"; } -}); +@name( "Versioncheck" ) +export default class Versioncheck extends Model { + @attr( "string", { defaultValue: "" } ) + version; + @attr( "number", { defaultValue: 0 } ) + checkagain; + @attr( "number", { defaultValue: 0 } ) + showdebugmessage; +} diff --git a/src/app/data/models/window/adapter.js b/src/app/data/models/window/adapter.js index 298c42bc35..d1d4b0108b 100644 --- a/src/app/data/models/window/adapter.js +++ b/src/app/data/models/window/adapter.js @@ -1,6 +1,6 @@ import LocalStorageAdapter from "ember-localstorage-adapter/adapters/ls-adapter"; -export default LocalStorageAdapter.extend({ - namespace: "window" -}); +export default class WindowAdapter extends LocalStorageAdapter { + namespace = "window"; +} diff --git a/src/app/data/models/window/model.js b/src/app/data/models/window/model.js index 72fd10b795..4c7eb4d176 100644 --- a/src/app/data/models/window/model.js +++ b/src/app/data/models/window/model.js @@ -1,14 +1,18 @@ import attr from "ember-data/attr"; import Model from "ember-data/model"; +import { name } from "utils/decorators"; -export default Model.extend({ - x: attr( "number", { defaultValue: null } ), - y: attr( "number", { defaultValue: null } ), - width: attr( "number", { defaultValue: null } ), - height: attr( "number", { defaultValue: null } ), - maximized: attr( "boolean", { defaultValue: false } ) - -}).reopenClass({ - toString() { return "Window"; } -}); +@name( "Window" ) +export default class Window extends Model { + @attr( "number", { defaultValue: null } ) + x; + @attr( "number", { defaultValue: null } ) + y; + @attr( "number", { defaultValue: null } ) + width; + @attr( "number", { defaultValue: null } ) + height; + @attr( "boolean", { defaultValue: false } ) + maximized; +} From 9e8702a37ee0bc920f8d60c681c63bfd2d7aaf7e Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 03:41:08 +0200 Subject: [PATCH 16/34] native classes: stream model --- src/app/data/models/stream/model.js | 192 ++++++++++++++-------------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/src/app/data/models/stream/model.js b/src/app/data/models/stream/model.js index a6a27b2afa..ebf2cf0d63 100644 --- a/src/app/data/models/stream/model.js +++ b/src/app/data/models/stream/model.js @@ -1,11 +1,13 @@ -import { get, set, computed, observer } from "@ember/object"; +import { set, computed } from "@ember/object"; import { alias } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import attr from "ember-data/attr"; import Model from "ember-data/model"; import { belongsTo } from "ember-data/relationships"; +import { observes } from "@ember-decorators/object"; import { twitch as twitchConfig } from "config"; import qualities from "./-qualities"; +import { name } from "utils/decorators"; const { "stream-url": twitchStreamUrl } = twitchConfig; @@ -18,33 +20,32 @@ const STATUS_WATCHING = 3; const STATUS_COMPLETED = 4; +const { hasOwnProperty } = {}; + const qualitiesById = qualities.reduce( ( presets, preset ) => { presets[ preset.id ] = preset; return presets; }, {} ); - -function computedStatus( status ) { - return computed( "status", { - get() { - return get( this, "status" ) === status; - }, - set( value ) { - if ( value ) { - set( this, "status", status ); - return true; - } +const computedStatus = status => computed( "status", { + get() { + return this.status === status; + }, + set( value ) { + if ( value ) { + set( this, "status", status ); + return true; } - }); -} + } +}); function cpQualityFromPresetOrCustomValue( key ) { /** @this {Stream} */ - return function() { + return computed( "streamQualityPreset", "settings.content.streaming.qualities", function() { const { id, [ key ]: defaultValue } = this.streamQualityPreset; const custom = this.settings.content.streaming.qualities.toJSON(); - if ( custom.hasOwnProperty( id ) ) { + if ( hasOwnProperty.call( custom, id ) ) { const customValue = String( custom[ id ][ key ] || "" ).trim(); if ( customValue.length ) { return customValue; @@ -52,7 +53,7 @@ function cpQualityFromPresetOrCustomValue( key ) { } return defaultValue; - }; + }); } @@ -62,116 +63,121 @@ export { }; -/** - * @class Stream - */ -export default Model.extend({ - /** @property {TwitchStream} stream */ - stream: belongsTo( "twitchStream", { async: false } ), - /** @property {TwitchChannel} channel */ - channel: belongsTo( "twitchChannel", { async: false } ), - quality: attr( "string" ), - low_latency: attr( "boolean" ), - disable_ads: attr( "boolean" ), - chat_open: attr( "boolean" ), - started: attr( "date" ), +@name( "Stream" ) +export default class Stream extends Model { + /** @type {AuthService} */ + @service auth; + /** @type {SettingsService} */ + @service settings; + /** @type {StreamingService} */ + @service streaming; + + /** @type {TwitchStream} */ + @belongsTo( "twitch-stream", { async: false } ) + stream; + /** @type {TwitchChannel} */ + @belongsTo( "twitch-channel", { async: false } ) + channel; + @attr( "string" ) + quality; + @attr( "boolean" ) + low_latency; + @attr( "boolean" ) + disable_ads; + @attr( "boolean" ) + chat_open; + @attr( "date" ) + started; // passthrough type (twitch streams are HLS) - playerInputPassthrough: "hls", - - /** @property {String} status */ - status: STATUS_PREPARING, - - /** @property {ChildProcess} spawn */ - spawn: null, - - /** @property {Error} error */ - error: null, - warning: false, + playerInputPassthrough = "hls"; - /** @property {Object[]} log */ - log: null, - showLog: false, + /** @type {boolean} */ + strictQuality = false; + /** @type {number} */ + status = STATUS_PREPARING; - auth: service(), - settings: service(), - streaming: service(), + /** @type {ChildProcess} */ + spawn = null; + /** @type {Error} */ + error = null; + warning = false; - session: alias( "auth.session" ), + /** @type {Object[]} */ + log = null; + showLog = false; + /** @type {Auth} */ + @alias( "auth.session" ) + session; - isPreparing: computedStatus( STATUS_PREPARING ), - isAborted: computedStatus( STATUS_ABORTED ), - isLaunching: computedStatus( STATUS_LAUNCHING ), - isWatching: computedStatus( STATUS_WATCHING ), - isCompleted: computedStatus( STATUS_COMPLETED ), - hasEnded: computed( "status", "error", function() { - const status = get( this, "status" ); - const error = get( this, "error" ); + @computedStatus( STATUS_PREPARING ) + isPreparing; + @computedStatus( STATUS_ABORTED ) + isAborted; + @computedStatus( STATUS_LAUNCHING ) + isLaunching; + @computedStatus( STATUS_WATCHING ) + isWatching; + @computedStatus( STATUS_COMPLETED ) + isCompleted; - return !!error || status === STATUS_ABORTED || status === STATUS_COMPLETED; - }), + @computed( "status", "error" ) + get hasEnded() { + return !!this.error + || this.status === STATUS_ABORTED + || this.status === STATUS_COMPLETED; + } get customParameters() { - const provider = get( this, "settings.streaming.provider" ); - const providers = get( this, "settings.streaming.providers" ); + const { provider, providers } = this.settings.content.streaming; - return get( providers, `${provider}.params` ) || ""; - }, + return hasOwnProperty.call( providers, provider ) + ? providers[ provider ].params || "" + : ""; + } kill() { if ( this.spawn ) { this.spawn.kill( "SIGTERM" ); } - }, + } pushLog( type, line ) { - get( this, "log" ).pushObject({ type, line }); - }, + this.log.pushObject({ type, line }); + } - qualityObserver: observer( "quality", function() { + @observes( "quality" ) + qualityObserver() { // the StreamingService knows that it has to spawn a new child process this.kill(); - }), + } // get the default quality object of the selected quality and streaming provider - streamQualityPreset: computed( "quality", function() { - const quality = get( this, "quality" ); - - return qualitiesById[ quality ] + @computed( "quality" ) + get streamQualityPreset() { + return qualitiesById[ this.quality ] || qualitiesById[ "source" ]; - }), + } // get the --stream-sorting-excludes parameter value - streamQualitiesExclude: computed( - "streamQualityPreset", - "settings.content.streaming.qualities", - cpQualityFromPresetOrCustomValue( "exclude" ) - ), + @cpQualityFromPresetOrCustomValue( "exclude" ) + streamQualitiesExclude; // get the stream quality selection - streamQuality: computed( - "streamQualityPreset", - "settings.content.streaming.qualities", - cpQualityFromPresetOrCustomValue( "quality" ) - ), - - streamUrl: computed( "channel.name", function() { - const channel = get( this, "channel.name" ); + @cpQualityFromPresetOrCustomValue( "quality" ) + streamQuality; - return twitchStreamUrl.replace( "{channel}", channel ); - }) - -}).reopenClass({ - - toString() { return "Stream"; } - -}); + @computed( "channel.name" ) + get streamUrl() { + return twitchStreamUrl.replace( "{channel}", this.channel.name ); + } +} From 98d1b82acd1ce4a78dd354fa869d436cb4e53621 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Tue, 23 Apr 2019 09:26:07 +0200 Subject: [PATCH 17/34] native classes: services (WIP) --- src/app/services/hotkey.js | 45 +++++++++++-------------- src/app/services/i18n/service.js | 37 +++++++++++++------- src/app/services/modal.js | 24 +++++-------- src/app/services/nwjs.js | 58 ++++++++++++++++++-------------- src/app/services/settings.js | 35 +++++++++---------- 5 files changed, 103 insertions(+), 96 deletions(-) diff --git a/src/app/services/hotkey.js b/src/app/services/hotkey.js index d64ccff282..ef391ced42 100644 --- a/src/app/services/hotkey.js +++ b/src/app/services/hotkey.js @@ -219,20 +219,24 @@ class HotkeyRegistry { } -/** - * @class HotkeyService - */ -export default Service.extend({ +export default class HotkeyService extends Service { /** @type {I18nService} */ - i18n: service(), + @service i18n; /** @type {SettingsService} */ - settings: service(), + @service settings; + + /** @type {HotkeysMap} */ + hotkeys = new Map(); + + /** @type {HotkeyRegistry[]} */ + registries = []; + + /** @type {KeyboardLayoutMap} */ + layoutMap = new Map(); init() { - this._super( ...arguments ); + super.init( ...arguments ); - this.registries = []; - this.hotkeys = new Map(); hotkeysMapBuild( this.hotkeys ); const hotkeysMapUpdate = () => { const userData = this.settings.content && this.settings.content.hotkeys; @@ -264,16 +268,7 @@ export default Service.extend({ const resetLayoutMap = async () => this.layoutMap = await navigator.keyboard.getLayoutMap(); //navigator.keyboard.addEventListener( "layoutchange", resetLayoutMap ); this.settings.on( "didUpdate", resetLayoutMap ); - }, - - /** @type {HotkeysMap} */ - hotkeys: null, - - /** @type {HotkeyRegistry[]} */ - registries: null, - - /** @type {KeyboardLayoutMap} */ - layoutMap: null, + } /** * Register hotkeys of a component @@ -304,7 +299,7 @@ export default Service.extend({ } this.registries.unshift( ...registries ); - }, + } /** * Remove all hotkeys registered by a component @@ -319,7 +314,7 @@ export default Service.extend({ l--; } } - }, + } /** * Find a registered hotkey that matches and execute the action of the one added last @@ -345,7 +340,7 @@ export default Service.extend({ break; } } - }, + } /** * @param {string} namespace @@ -358,7 +353,7 @@ export default Service.extend({ return hotkeys.has( id ) && hotkeys.get( id ).find( hotkey => !hotkey.disabled && hotkey.code !== null ); - }, + } /** * @param {HotkeyComponent} context @@ -372,7 +367,7 @@ export default Service.extend({ return hotkey; } } - }, + } /** * @param {Hotkey} hotkey @@ -406,4 +401,4 @@ export default Service.extend({ ? `[${str}] ${title}` : str; } -}); +} diff --git a/src/app/services/i18n/service.js b/src/app/services/i18n/service.js index f3208617ab..469de8c717 100644 --- a/src/app/services/i18n/service.js +++ b/src/app/services/i18n/service.js @@ -1,6 +1,7 @@ -import { get, set, observer } from "@ember/object"; +import { set } from "@ember/object"; import { inject as service } from "@ember/service"; -import { Service } from "ember-i18n/addon"; +import { observes, on } from "@ember-decorators/object"; +import { Service as OriginalI18nService } from "ember-i18n/addon"; import { locales as localesConfig } from "config"; import systemLocale from "./system-locale"; @@ -9,22 +10,32 @@ const { locales } = localesConfig; const { hasOwnProperty } = {}; -export default Service.extend({ - settings: service(), +export default class I18nService extends OriginalI18nService { + /** @type {SettingsService} */ + @service settings; - _settingsObserver: observer( "settings.content.gui.language", function() { - let locale = get( this, "settings.content.gui.language" ); + + @on( "init" ) + _initSettings() { + return this.settings; + } + + @observes( "settings.content.gui.language" ) + _languageObserver() { + let locale = this.settings.content.gui.language; if ( locale === "auto" || !locales || !hasOwnProperty.call( locales, locale ) ) { locale = systemLocale /* istanbul ignore next */ || "en"; } set( this, "locale", locale ); - }), - - init() { - this._super( ...arguments ); + } - // the observer doesn't trigger without reading the settings property first - get( this, "settings" ); + /** + * @param {string} key + * @param {Object?} data + * @returns {Handlebars.SafeString} + */ + t( key, data = {} ) { + return super.t( key, data ); } -}); +} diff --git a/src/app/services/modal.js b/src/app/services/modal.js index 3ac7f828cc..5147b9a33c 100644 --- a/src/app/services/modal.js +++ b/src/app/services/modal.js @@ -1,6 +1,6 @@ import { A } from "@ember/array"; import { getOwner } from "@ember/application"; -import { set, setProperties } from "@ember/object"; +import { setProperties } from "@ember/object"; import { notEmpty } from "@ember/object/computed"; import Evented from "@ember/object/evented"; import Service from "@ember/service"; @@ -14,18 +14,12 @@ import Service from "@ember/service"; */ -/** */ -export default Service.extend( Evented, /** @class ModalService */ { +export default class ModalService extends Service.extend( Evented ) { /** @type {ModalServiceEntry[]} */ - modals: null, - - isModalOpened: notEmpty( "modals" ), - - init() { - this._super( ...arguments ); - set( this, "modals", A() ); - }, + modals = A(); + @notEmpty( "modals" ) + isModalOpened; /** * @param {string} name @@ -77,7 +71,7 @@ export default Service.extend( Evented, /** @class ModalService */ { } return context; - }, + } /** * @param {(Object|null)} context @@ -98,7 +92,7 @@ export default Service.extend( Evented, /** @class ModalService */ { this.trigger( "close", n, c ); } } - }, + } promiseModal( name, context, ...args ) { return new Promise( resolve => { @@ -110,7 +104,7 @@ export default Service.extend( Evented, /** @class ModalService */ { this.on( "close", onClose ); context = this.openModal( name, context, ...args ); }); - }, + } /** * @param {string?} name @@ -125,4 +119,4 @@ export default Service.extend( Evented, /** @class ModalService */ { || !context && n === name ); } -}); +} diff --git a/src/app/services/nwjs.js b/src/app/services/nwjs.js index 017828dacd..8ab9899c9c 100644 --- a/src/app/services/nwjs.js +++ b/src/app/services/nwjs.js @@ -1,5 +1,5 @@ import { getOwner } from "@ember/application"; -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import { default as Service, inject as service } from "@ember/service"; import { quit } from "nwjs/App"; import { Clipboard, Shell } from "nwjs/nwGui"; @@ -18,29 +18,34 @@ const { hasOwnProperty } = {}; const reVariable = /{(\w+)}/g; -export default Service.extend( /** @class NwjsService */ { - modal: service(), - settings: service(), - streaming: service(), +export default class NwjsService extends Service { + /** @type {ModalService} */ + @service modal; + /** @type {SettingsService} */ + @service settings; + /** @type {StreamingService} */ + @service streaming; /** @type {NWJS_Helpers.clip} */ - clipboard: computed(function() { + @computed() + get clipboard() { return Clipboard.get(); - }), + } - tray: computed(function() { + @computed() + get tray() { return getOwner( this ).lookup( "nwjs:tray" ); - }), + } reload() { nwWindow.reloadIgnoringCache(); - }, + } devTools() { nwWindow.showDevTools(); - }, + } /** * @param {string} url @@ -62,7 +67,7 @@ export default Service.extend( /** @class NwjsService */ { }); Shell.openExternal( url ); - }, + } minimize() { const { integration, minimizetotray } = this.settings.content.gui; @@ -78,31 +83,32 @@ export default Service.extend( /** @class NwjsService */ { } else { toggleMinimized(); } - }, + } maximize() { toggleMaximized(); - }, + } focus( focus = true ) { setFocused( focus ); }, close() { - const streams = get( this, "streaming.model" ).toArray(); - if ( streams.length && streams.some( stream => !get( stream, "hasEnded" ) ) ) { - get( this, "modal" ).openModal( "quit", this ); + /** @type {Stream[]} */ + const streams = this.streaming.model.toArray(); + if ( streams.length && streams.some( stream => !stream.hasEnded ) ) { + this.modal.openModal( "quit", this ); } else { this.quit(); } - }, + } quit() { quit(); - }, + } setShowInTray( visible, removeOnClick ) { - const tray = get( this, "tray" ); + const tray = this.tray; if ( visible ) { tray._createTray(); if ( removeOnClick ) { @@ -111,7 +117,7 @@ export default Service.extend( /** @class NwjsService */ { } else { tray._removeTray(); } - }, + } contextMenu( event, items ) { event.preventDefault(); @@ -120,19 +126,19 @@ export default Service.extend( /** @class NwjsService */ { const menu = getOwner( this ).lookup( "nwjs:menu" ); menu.items.pushObjects( items ); menu.menu.popup( event.x, event.y ); - }, + } addTrayMenuItem( item, position ) { - const tray = get( this, "tray" ); + const tray = this.tray; if ( position === undefined ) { tray.menu.items.unshiftObject( item ); } else { tray.menu.items.insertAt( position, item ); } - }, + } removeTrayMenuItem( item ) { - const tray = get( this, "tray" ); + const tray = this.tray; tray.menu.items.removeObject( item ); } -}); +} diff --git a/src/app/services/settings.js b/src/app/services/settings.js index 362df442e3..cd8e14867b 100644 --- a/src/app/services/settings.js +++ b/src/app/services/settings.js @@ -1,26 +1,27 @@ -import { get, set } from "@ember/object"; +import { set } from "@ember/object"; import Evented from "@ember/object/evented"; import ObjectProxy from "@ember/object/proxy"; import { inject as service } from "@ember/service"; +import { on } from "@ember-decorators/object"; // A service object is just a regular object, so we can use an ObjectProxy as well -export default ObjectProxy.extend( Evented, { - store: service(), +export default class SettingsService extends ObjectProxy.extend( Evented ) { + static isServiceFactory = true; - content: null, + /** @type {DS.Store} */ + @service store; - init() { - const store = get( this, "store" ); - // don't use async functions here and use Ember RSVP promises instead - store.findOrCreateRecord( "settings" ) - .then( settings => { - set( this, "content", settings ); - settings.on( "didUpdate", ( ...args ) => this.trigger( "didUpdate", ...args ) ); - this.trigger( "initialized" ); - }); - } + /** @type {Settings} */ + content = null; + + @on( "init" ) + async _initContent() { + /** @type {Settings} */ + const settings = await this.store.findOrCreateRecord( "settings" ); + set( this, "content", settings ); -}).reopenClass({ - isServiceFactory: true -}); + settings.on( "didUpdate", ( ...args ) => this.trigger( "didUpdate", ...args ) ); + this.trigger( "initialized" ); + } +} From 915f808e168239222937556c8850c39c6034dd23 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Fri, 26 Apr 2019 15:35:03 +0200 Subject: [PATCH 18/34] native classes: settings route - remove isStreamlinkMixin - refactor SettingsChannelsRoute --- src/app/ui/routes/settings/-submenu/route.js | 8 +- .../ui/routes/settings/channels/controller.js | 40 ++++---- src/app/ui/routes/settings/channels/route.js | 93 +++++++++++-------- src/app/ui/routes/settings/chat/controller.js | 28 +++--- src/app/ui/routes/settings/controller.js | 60 ++++++------ src/app/ui/routes/settings/gui/controller.js | 24 +++-- src/app/ui/routes/settings/index/route.js | 29 +++--- .../routes/settings/languages/controller.js | 11 ++- src/app/ui/routes/settings/main/controller.js | 16 ++-- .../settings/notifications/controller.js | 53 +++++------ .../ui/routes/settings/player/controller.js | 53 ++++++----- src/app/ui/routes/settings/route.js | 57 ++++++------ .../routes/settings/streaming/controller.js | 74 +++++++++------ .../ui/routes/settings/streams/controller.js | 16 ++-- 14 files changed, 298 insertions(+), 264 deletions(-) diff --git a/src/app/ui/routes/settings/-submenu/route.js b/src/app/ui/routes/settings/-submenu/route.js index 6b5fcb557f..8a4c55e7d6 100644 --- a/src/app/ui/routes/settings/-submenu/route.js +++ b/src/app/ui/routes/settings/-submenu/route.js @@ -2,18 +2,18 @@ import { set } from "@ember/object"; import Route from "@ember/routing/route"; -export default Route.extend({ +export default class SettingsSubmenuRoute extends Route { model() { return this.modelFor( "settings" ); - }, + } activate() { const settingsController = this.controllerFor( "settings" ); set( settingsController, "currentSubmenu", this.routeName ); - }, + } deactivate() { const settingsController = this.controllerFor( "settings" ); set( settingsController, "isAnimated", true ); } -}); +} diff --git a/src/app/ui/routes/settings/channels/controller.js b/src/app/ui/routes/settings/channels/controller.js index fc47ca67d5..bae53f1faf 100644 --- a/src/app/ui/routes/settings/channels/controller.js +++ b/src/app/ui/routes/settings/channels/controller.js @@ -1,36 +1,32 @@ import Controller from "@ember/controller"; -import { get, computed } from "@ember/object"; +import { computed, action } from "@ember/object"; import { run } from "@ember/runloop"; const reFilter = /^\w+$/; -export default Controller.extend({ - filter: "", +export default class SettingsChannelsController extends Controller { + filter = ""; - modelFiltered: computed( "model.[]", "all", "filter", function() { - const filter = get( this, "filter" ).toLowerCase(); + @computed( "model.[]", "all", "filter" ) + get modelFiltered() { + const filter = this.filter.toLowerCase(); if ( !reFilter.test( filter ) ) { - return get( this, "model" ); + return this.model; } - return get( this, "all" ).filter(function( item ) { - return get( item, "settings.id" ).toLowerCase().indexOf( filter ) !== -1; - }); - }), - + return this.all.filter( item => + item.settings.id.toLowerCase().includes( filter ) + ); + } - actions: { - erase( modelItem ) { - const model = get( this, "model" ); - const settingsRecord = get( modelItem, "settings" ); - if ( get( settingsRecord, "isDeleted" ) ) { return; } + @action + async erase( modelItem ) { + const settingsRecord = modelItem.settings; + if ( settingsRecord.isDeleted ) { return; } - run( () => settingsRecord.destroyRecord() ) - .then( () => { - model.removeObject( modelItem ); - }); - } + await run( () => settingsRecord.destroyRecord() ); + this.model.removeObject( modelItem ); } -}); +} diff --git a/src/app/ui/routes/settings/channels/route.js b/src/app/ui/routes/settings/channels/route.js index f277d46451..3ca6d23515 100644 --- a/src/app/ui/routes/settings/channels/route.js +++ b/src/app/ui/routes/settings/channels/route.js @@ -1,63 +1,78 @@ -import { default as EmberObject, get, set, computed } from "@ember/object"; -import PromiseProxyMixin from "@ember/object/promise-proxy-mixin"; -import ObjectProxy from "@ember/object/proxy"; +import { set, computed } from "@ember/object"; +import { PromiseObject } from "ember-data/-private"; import SettingsSubmenuRoute from "../-submenu/route"; import InfiniteScrollMixin from "ui/routes/-mixins/routes/infinite-scroll"; import preload from "utils/preload"; -// build our own PromiseObject in order to avoid importing from a private ember-data module -// TODO: import from @ember-data/promise-proxies once it becomes available -const PromiseObject = ObjectProxy.extend( PromiseProxyMixin ); +class SettingsChannelsItem { + constructor( store, channelSettings ) { + this.store = store; + this.settings = channelSettings; + } + + /** @type {DS.Store} */ + store; + + /** @type {ChannelSettings} */ + settings; + + /** + * @returns {Promise} + */ + async _getChannel() { + /** @type {TwitchUser} */ + const user = await this.store.findRecord( "twitch-user", this.settings.id ); + await user.channel.promise; + /** @type {TwitchChannel} */ + const channel = user.channel.content; + await preload( channel, "logo" ); + + return channel; + } + /** @type {DS.PromiseObject} channel */ + @computed() + get channel() { + const promise = this._getChannel(); + + return PromiseObject.create({ promise }); + } +} -export default SettingsSubmenuRoute.extend( InfiniteScrollMixin, { - controllerName: "settingsChannels", - itemSelector: ".settings-channel-item-component", - all: null, +export default class SettingsChannelsRoute +extends SettingsSubmenuRoute.extend( InfiniteScrollMixin ) { + controllerName = "settingsChannels"; + itemSelector = ".settings-channel-item-component"; + /** @type {SettingsChannelsItem[]} */ + all = null; async model() { - const store = get( this, "store" ); - const channelSettings = await store.findAll( "channelSettings" ); - - // we need all channelSettings records, so we can search for specific ones - // that have not been added to the controller's model yet - this.all = channelSettings.map( record => - // return both channelSettings and twitchChannel records - EmberObject.extend({ - settings: record, - // load the twitchChannel record on demand (PromiseObject) - // will be triggered by the first property read-access - channel: computed(function() { - const id = get( record, "id" ); - const promise = store.findRecord( "twitchUser", id ) - .then( user => get( user, "channel" ) ) - .then( record => preload( record, "logo" ) ); - - return PromiseObject.create({ promise }); - }) - }).create() - ); + const store = this.store; + /** @type {ChannelSettings[]} */ + const channelSettings = await store.findAll( "channel-settings" ); + this.all = channelSettings.map( record => new SettingsChannelsItem( store, record ) ); return await this.fetchContent(); - }, + } async fetchContent() { - const limit = get( this, "limit" ); - const offset = get( this, "offset" ); + const limit = this.limit; + const offset = this.offset; return this.all.slice( offset, offset + limit ); - }, + } setupController( controller ) { set( controller, "all", this.all ); - this._super( ...arguments ); - }, + + return super.setupController( ...arguments ); + } deactivate() { - this._super( ...arguments ); + super.deactivate( ...arguments ); this.all = null; } -}); +} diff --git a/src/app/ui/routes/settings/chat/controller.js b/src/app/ui/routes/settings/chat/controller.js index cd6673b2e6..037ac3cfec 100644 --- a/src/app/ui/routes/settings/chat/controller.js +++ b/src/app/ui/routes/settings/chat/controller.js @@ -11,14 +11,16 @@ const { "chat-url": twitchChatUrl } = twitchConfig; const { userArgsSubstitutions } = ChatProviderBasic; -export default Controller.extend({ - chat: service(), +export default class SettingsChatController extends Controller { + /** @type {ChatService} */ + @service chat; - providers, - chatConfig, - userArgsSubstitutions, + providers = providers; + chatConfig = chatConfig; + userArgsSubstitutions = userArgsSubstitutions; - contentChatProvider: computed(function() { + @computed() + get contentChatProvider() { const list = []; for ( const [ id ] of providers ) { const { exec } = chatConfig[ id ]; @@ -26,16 +28,18 @@ export default Controller.extend({ list.push({ id }); } return list; - }), + } - contentChatUrl: computed(function() { + @computed() + get contentChatUrl() { return Object.keys( twitchChatUrl ) .map( id => ({ id }) ); - }), + } // EmberData (2.9) is stupid and uses an internal Map implementation that is not iterable // so we can't iterate SettingsChatProvider.attributes in the template - providerAttributes: computed(function() { + @computed() + get providerAttributes() { const map = {}; for ( const [ id, provider ] of providers ) { const attrs = []; @@ -44,5 +48,5 @@ export default Controller.extend({ map[ id ] = attrs; } return map; - }) -}); + } +} diff --git a/src/app/ui/routes/settings/controller.js b/src/app/ui/routes/settings/controller.js index f0200f4eb7..63b09b6bad 100644 --- a/src/app/ui/routes/settings/controller.js +++ b/src/app/ui/routes/settings/controller.js @@ -1,45 +1,45 @@ import Controller from "@ember/controller"; -import { get, set } from "@ember/object"; +import { set, action } from "@ember/object"; import { inject as service } from "@ember/service"; import RetryTransitionMixin from "ui/routes/-mixins/controllers/retry-transition"; import "./styles.less"; -export default Controller.extend( RetryTransitionMixin, { - modal: service(), - settings: service(), +export default class SettingsController extends Controller.extend( RetryTransitionMixin ) { + /** @type {ModalService} */ + @service modal; + /** @type {SettingsService} */ + @service settings; - isAnimated: false, + isAnimated = false; - actions: { - apply( success, failure ) { - const modal = get( this, "modal" ); - const settings = get( this, "settings.content" ); + @action + apply( success, failure ) { + const settings = this.settings.content; - get( this, "model" ).applyChanges( settings ); + this.model.applyChanges( settings ); - settings.save() - .then( success, failure ) - .then( () => modal.closeModal( this ) ) - .then( () => this.retryTransition() ) - .catch( () => settings.rollbackAttributes() ); - }, - - discard( success ) { - const modal = get( this, "modal" ); + settings.save() + .then( success, failure ) + .then( () => this.modal.closeModal( this ) ) + .then( () => this.retryTransition() ) + .catch( () => settings.rollbackAttributes() ); + } - get( this, "model" ).discardChanges(); + @action + discard( success ) { + this.model.discardChanges(); - Promise.resolve() - .then( success ) - .then( () => modal.closeModal( this ) ) - .then( () => this.retryTransition() ); - }, + Promise.resolve() + .then( success ) + .then( () => this.modal.closeModal( this ) ) + .then( () => this.retryTransition() ); + } - cancel() { - set( this, "previousTransition", null ); - get( this, "modal" ).closeModal( this ); - } + @action + cancel() { + set( this, "previousTransition", null ); + this.modal.closeModal( this ); } -}); +} diff --git a/src/app/ui/routes/settings/gui/controller.js b/src/app/ui/routes/settings/gui/controller.js index b56aca1fdd..71765da324 100644 --- a/src/app/ui/routes/settings/gui/controller.js +++ b/src/app/ui/routes/settings/gui/controller.js @@ -1,5 +1,6 @@ import Controller from "@ember/controller"; -import { get, set, observer } from "@ember/object"; +import { get, set } from "@ember/object"; +import { observes } from "@ember-decorators/object"; import { equal } from "@ember/object/computed"; import { default as SettingsGui, @@ -18,15 +19,18 @@ const { } = SettingsGui; -export default Controller.extend({ - contentGuiIntegration, - contentGuiMinimize, - contentGuiFocusrefresh, +export default class SettingsGuiController extends Controller { + contentGuiIntegration = contentGuiIntegration; + contentGuiMinimize = contentGuiMinimize; + contentGuiFocusrefresh = contentGuiFocusrefresh; - hasTaskBarIntegration: equal( "model.gui.integration", ATTR_GUI_INTEGRATION_TASKBAR ), - hasBothIntegrations: equal( "model.gui.integration", ATTR_GUI_INTEGRATION_BOTH ), + @equal( "model.gui.integration", ATTR_GUI_INTEGRATION_TASKBAR ) + hasTaskBarIntegration; + @equal( "model.gui.integration", ATTR_GUI_INTEGRATION_BOTH ) + hasBothIntegrations; - _integrationObserver: observer( "model.gui.integration", function() { + @observes( "model.gui.integration" ) + _integrationObserver() { const integration = get( this, "model.gui.integration" ); const minimize = get( this, "model.gui.minimize" ); const noTask = ( integration & ATTR_GUI_INTEGRATION_TASKBAR ) === 0; @@ -43,5 +47,5 @@ export default Controller.extend({ // enable/disable buttons set( contentGuiMinimize[ ATTR_GUI_MINIMIZE_MINIMIZE ], "disabled", noTask ); set( contentGuiMinimize[ ATTR_GUI_MINIMIZE_TRAY ], "disabled", noTray ); - }) -}); + } +} diff --git a/src/app/ui/routes/settings/index/route.js b/src/app/ui/routes/settings/index/route.js index f64c3cdcb6..98a8e9ab45 100644 --- a/src/app/ui/routes/settings/index/route.js +++ b/src/app/ui/routes/settings/index/route.js @@ -1,23 +1,20 @@ -import { get, set } from "@ember/object"; +import { set, action } from "@ember/object"; import Route from "@ember/routing/route"; -export default Route.extend({ - actions: { - didTransition() { - const settingsController = this.controllerFor( "settings" ); - let goto = get( settingsController, "currentSubmenu" ); - if ( !goto ) { - goto = "settings.main"; - } +export default class SettingsIndexRoute extends Route { + @action + didTransition() { + const settingsController = this.controllerFor( "settings" ); + const goto = settingsController.currentSubmenu || "settings.main"; - set( settingsController, "isAnimated", false ); + set( settingsController, "isAnimated", false ); - this.replaceWith( goto ); - }, + this.replaceWith( goto ); + } - willTransition() { - return false; - } + @action + willTransition() { + return false; } -}); +} diff --git a/src/app/ui/routes/settings/languages/controller.js b/src/app/ui/routes/settings/languages/controller.js index e0876833d6..f5fec49020 100644 --- a/src/app/ui/routes/settings/languages/controller.js +++ b/src/app/ui/routes/settings/languages/controller.js @@ -7,12 +7,13 @@ import SettingsStreams from "data/models/settings/streams/fragment"; const { filterLanguages: contentStreamsFilterLanguages } = SettingsStreams; -export default Controller.extend({ - contentStreamsFilterLanguages, +export default class SettingsLanguagesController extends Controller { + contentStreamsFilterLanguages = contentStreamsFilterLanguages; - languages: computed(function() { + @computed() + get languages() { return Object.keys( langsConfig ) .filter( code => !langsConfig[ code ].disabled ) .map( code => ({ id: code, label: code }) ); - }) -}); + } +} diff --git a/src/app/ui/routes/settings/main/controller.js b/src/app/ui/routes/settings/main/controller.js index 68a976e748..81fbcabc63 100644 --- a/src/app/ui/routes/settings/main/controller.js +++ b/src/app/ui/routes/settings/main/controller.js @@ -8,10 +8,11 @@ const { locales } = localesConfig; const { themes } = themesConfig; -export default Controller.extend({ - systemThemeId: "system", +export default class SettingsMainController extends Controller { + systemThemeId = "system"; - contentGuiLanguages: computed(function() { + @computed() + get contentGuiLanguages() { const compare = new Intl.Collator( "en", { sensitivity: "base" } ).compare; const languages = Object.keys( locales ) .map( key => ({ @@ -25,9 +26,10 @@ export default Controller.extend({ languages.unshift({ id: "auto", label: locales[ systemLocale ] }); return languages; - }), + } - contentGuiTheme: computed(function() { + @computed() + get contentGuiTheme() { return [ this.systemThemeId, ...themes ].map( id => ({ id }) ); - }) -}); + } +} diff --git a/src/app/ui/routes/settings/notifications/controller.js b/src/app/ui/routes/settings/notifications/controller.js index d09b0a406b..838075f3d5 100644 --- a/src/app/ui/routes/settings/notifications/controller.js +++ b/src/app/ui/routes/settings/notifications/controller.js @@ -1,5 +1,5 @@ import Controller from "@ember/controller"; -import { get, computed } from "@ember/object"; +import { get, computed, action } from "@ember/object"; import { inject as service } from "@ember/service"; import { main as mainConfig } from "config"; import SettingsNotification from "data/models/settings/notification/fragment"; @@ -16,34 +16,35 @@ const { } = SettingsNotification; -export default Controller.extend({ - contentNotificationFilter, - contentNotificationClick, - contentNotificationClickGroup, +export default class SettingsNotificationsController extends Controller { + /** @type {I18nService} */ + @service i18n; - i18n: service(), + contentNotificationFilter = contentNotificationFilter; + contentNotificationClick = contentNotificationClick; + contentNotificationClickGroup = contentNotificationClickGroup; // filter available notification providers - contentNotificationProviders: computed(function() { + @computed() + get contentNotificationProviders() { return SettingsNotification.providers .filter( item => isSupported( item.id ) || item.id === "auto" ); - }), - - actions: { - testNotification( success, failure ) { - const i18n = get( this, "i18n" ); - const provider = get( this, "model.notification.provider" ); - const message = i18n.t( "settings.notifications.provider.test.message" ).toString(); - - const data = new NotificationData({ - title: displayName, - icon, - message - }); - - showNotification( provider, data, true ) - .then( success, failure ) - .catch( () => {} ); - } } -}); + + + @action + testNotification( success, failure ) { + const provider = get( this, "model.notification.provider" ); + const message = this.i18n.t( "settings.notifications.provider.test.message" ).toString(); + + const data = new NotificationData({ + title: displayName, + icon, + message + }); + + showNotification( provider, data, true ) + .then( success, failure ) + .catch( () => {} ); + } +} diff --git a/src/app/ui/routes/settings/player/controller.js b/src/app/ui/routes/settings/player/controller.js index 0ff823fb9d..b7476dbcfc 100644 --- a/src/app/ui/routes/settings/player/controller.js +++ b/src/app/ui/routes/settings/player/controller.js @@ -12,14 +12,17 @@ const { assign } = Object; const { isArray } = Array; -export default Controller.extend({ - i18n: service(), - store: service(), +export default class SettingsPlayerController extends Controller { + /** @type {I18nService} */ + @service i18n; + /** @type {DS.Store} */ + @service store; - substitutionsPlayer, + substitutionsPlayer = substitutionsPlayer; // filter platform dependent player parameters - players: computed(function() { + @computed() + get players() { const list = {}; for ( const [ id, player ] of Object.entries( playersConfig ) ) { const obj = list[ id ] = assign( {}, player ); @@ -36,14 +39,13 @@ export default Controller.extend({ } return list; - }), - - contentStreamingPlayer: computed(function() { - const i18n = get( this, "i18n" ); + } + @computed() + get contentStreamingPlayer() { const presets = [{ id: "default", - label: i18n.t( "settings.player.players.default.label" ).toString() + label: this.i18n.t( "settings.player.players.default.label" ).toString() }]; for ( const [ id, { exec, disabled } ] of Object.entries( playersConfig ) ) { if ( disabled || !exec[ platform ] ) { continue; } @@ -52,34 +54,31 @@ export default Controller.extend({ } return presets; - }), - - playerPlaceholder: computed( "i18n.locale", "model.streaming.player", function() { - const i18n = get( this, "i18n" ); + } + @computed( "i18n.locale", "model.streaming.player" ) + get playerPlaceholder() { const player = get( this, "model.streaming.player" ); if ( player === "default" || !playersConfig[ player ] ) { - return i18n.t( "settings.player.executable.default.placeholder" ).toString(); + return this.i18n.t( "settings.player.executable.default.placeholder" ).toString(); } const exec = playersConfig[ player ][ "exec" ][ platform ]; if ( !exec ) { - return i18n.t( "settings.player.executable.preset.placeholder" ).toString(); + return this.i18n.t( "settings.player.executable.preset.placeholder" ).toString(); } return isArray( exec ) ? exec.join( `${delimiter} ` ) : exec; - }), + } - playerPresetDefault: equal( "model.streaming.player", "default" ), + @equal( "model.streaming.player", "default" ) + playerPresetDefault; - playerPresetDefaultAndPlayerEmpty: computed( - "playerPresetDefault", - "model.streaming.players.default.exec", - function() { - return get( this, "playerPresetDefault" ) - && !get( this, "model.streaming.players.default.exec" ); - } - ) -}); + @computed( "playerPresetDefault", "model.streaming.players.default.exec" ) + get playerPresetDefaultAndPlayerEmpty() { + return this.playerPresetDefault + && !get( this, "model.streaming.players.default.exec" ); + } +} diff --git a/src/app/ui/routes/settings/route.js b/src/app/ui/routes/settings/route.js index 0e4e1d5a82..fe13c81317 100644 --- a/src/app/ui/routes/settings/route.js +++ b/src/app/ui/routes/settings/route.js @@ -1,4 +1,4 @@ -import { get, set } from "@ember/object"; +import { set, action } from "@ember/object"; import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; import ObjectBuffer from "utils/ember/ObjectBuffer"; @@ -7,42 +7,41 @@ import ObjectBuffer from "utils/ember/ObjectBuffer"; const reRouteNames = /^settings\.\w+$/; -export default Route.extend({ - modal: service(), - settings: service(), +export default class SettingsRoute extends Route { + /** @type {ModalService} */ + @service modal; + /** @type {SettingsService} */ + @service settings; - model() { - const settings = get( this, "settings.content" ); + model() { return ObjectBuffer.create({ - content: settings.toJSON() + content: this.settings.content.toJSON() }); - }, + } resetController( controller, isExiting ) { if ( isExiting ) { set( controller, "isAnimated", false ); } - }, - - actions: { - willTransition( previousTransition ) { - // don't show modal when transitioning between settings subroutes - if ( previousTransition && reRouteNames.test( previousTransition.targetName ) ) { - return true; - } - - // check whether the user has changed any values - const controller = get( this, "controller" ); - if ( !get( controller, "model.isDirty" ) ) { return; } - - // stay here... - previousTransition.abort(); - - // and let the user decide - get( this, "modal" ).openModal( "confirm", controller, { - previousTransition - }); + } + + @action + willTransition( previousTransition ) { + // don't show modal when transitioning between settings subroutes + if ( previousTransition && reRouteNames.test( previousTransition.targetName ) ) { + return true; } + + // check whether the user has changed any values + if ( !this.controller.model.isDirty ) { return; } + + // stay here... + previousTransition.abort(); + + // and let the user decide + this.modal.openModal( "confirm", this.controller, { + previousTransition + }); } -}); +} diff --git a/src/app/ui/routes/settings/streaming/controller.js b/src/app/ui/routes/settings/streaming/controller.js index 3604a7f076..11116c17d9 100644 --- a/src/app/ui/routes/settings/streaming/controller.js +++ b/src/app/ui/routes/settings/streaming/controller.js @@ -20,12 +20,13 @@ function settingsAttrMeta( attr, prop ) { } -export default Controller.extend({ - platform, - providers, - contentStreamingPlayerInput, +export default class SettingsStreamingController extends Controller { + platform = platform; + providers = providers; + contentStreamingPlayerInput = contentStreamingPlayerInput; - contentStreamingProvider: computed(function() { + @computed() + get contentStreamingProvider() { return Object.keys( providers ) // exclude unsupported providers .filter( id => providers[ id ][ "exec" ][ platform ] ) @@ -33,37 +34,52 @@ export default Controller.extend({ id, label: providers[ id ][ "label" ] }) ); - }), + } // can't use the fragment's providerName computed property here // the controller's model is an ObjectBuffer instance - providerName: computed( "model.streaming.provider", function() { + @computed( "model.streaming.provider" ) + get providerName() { const provider = get( this, "model.streaming.provider" ); return providers[ provider ][ "name" ]; - }), + } - playerInputDocumentation: computed( "model.streaming.player_input", function() { + @computed( "model.streaming.player_input" ) + get playerInputDocumentation() { const input = get( this, "model.streaming.player_input" ); return contentStreamingPlayerInput.findBy( "id", input ).documentation; - }), - - playerInputPassthrough: equal( "model.streaming.player_input", inputPassthrough ), - - hlsLiveEdgeDefault: settingsAttrMeta( "hls_live_edge", "defaultValue" ), - hlsLiveEdgeMin: settingsAttrMeta( "hls_live_edge", "min" ), - hlsLiveEdgeMax: settingsAttrMeta( "hls_live_edge", "max" ), - - hlsSegmentThreadsDefault: settingsAttrMeta( "hls_segment_threads", "defaultValue" ), - hlsSegmentThreadsMin: settingsAttrMeta( "hls_segment_threads", "min" ), - hlsSegmentThreadsMax: settingsAttrMeta( "hls_segment_threads", "max" ), - - retryStreamsDefault: settingsAttrMeta( "retry_streams", "defaultValue" ), - retryStreamsMin: settingsAttrMeta( "retry_streams", "min" ), - retryStreamsMax: settingsAttrMeta( "retry_streams", "max" ), - - retryOpenDefault: settingsAttrMeta( "retry_open", "defaultValue" ), - retryOpenMin: settingsAttrMeta( "retry_open", "min" ), - retryOpenMax: settingsAttrMeta( "retry_open", "max" ) -}); + } + + @equal( "model.streaming.player_input", inputPassthrough ) + playerInputPassthrough; + + @settingsAttrMeta( "hls_live_edge", "defaultValue" ) + hlsLiveEdgeDefault; + @settingsAttrMeta( "hls_live_edge", "min" ) + hlsLiveEdgeMin; + @settingsAttrMeta( "hls_live_edge", "max" ) + hlsLiveEdgeMax; + + @settingsAttrMeta( "hls_segment_threads", "defaultValue" ) + hlsSegmentThreadsDefault; + @settingsAttrMeta( "hls_segment_threads", "min" ) + hlsSegmentThreadsMin; + @settingsAttrMeta( "hls_segment_threads", "max" ) + hlsSegmentThreadsMax; + + @settingsAttrMeta( "retry_streams", "defaultValue" ) + retryStreamsDefault; + @settingsAttrMeta( "retry_streams", "min" ) + retryStreamsMin; + @settingsAttrMeta( "retry_streams", "max" ) + retryStreamsMax; + + @settingsAttrMeta( "retry_open", "defaultValue" ) + retryOpenDefault; + @settingsAttrMeta( "retry_open", "min" ) + retryOpenMin; + @settingsAttrMeta( "retry_open", "max" ) + retryOpenMax; +} diff --git a/src/app/ui/routes/settings/streams/controller.js b/src/app/ui/routes/settings/streams/controller.js index e0c21e9d16..7d50b44b43 100644 --- a/src/app/ui/routes/settings/streams/controller.js +++ b/src/app/ui/routes/settings/streams/controller.js @@ -14,13 +14,13 @@ const { } = SettingsStreams; -export default Controller.extend({ - contentStreamingQuality, - contentStreamsName, - contentStreamsInfo, - contentStreamsClick, +export default class SettingsStreamsController extends Controller { + contentStreamingQuality = contentStreamingQuality; + contentStreamsName = contentStreamsName; + contentStreamsInfo = contentStreamsInfo; + contentStreamsClick = contentStreamsClick; - DEFAULT_VODCAST_REGEXP, + DEFAULT_VODCAST_REGEXP = DEFAULT_VODCAST_REGEXP; - isDarwin -}); + isDarwin = isDarwin; +} From e94f1c3ef4c5304f9b58cb35a814ee731820ae18 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Wed, 1 May 2019 17:00:48 +0200 Subject: [PATCH 19/34] native classes: simple routes --- src/app/ui/routes/about/controller.js | 14 +++--- src/app/ui/routes/application/route.js | 10 ++-- src/app/ui/routes/error/route.js | 10 ++-- src/app/ui/routes/featured/controller.js | 27 +++++----- src/app/ui/routes/featured/route.js | 14 +++--- src/app/ui/routes/games/game/route.js | 23 ++++----- src/app/ui/routes/games/index/route.js | 11 +++-- src/app/ui/routes/index/route.js | 4 +- src/app/ui/routes/loading/route.js | 6 +-- src/app/ui/routes/search/controller.js | 38 ++++++++------ src/app/ui/routes/search/route.js | 63 +++++++++++++++--------- src/app/ui/routes/streams/route.js | 11 +++-- src/app/ui/routes/team/index/route.js | 23 +++++---- src/app/ui/routes/team/info/route.js | 6 +-- src/app/ui/routes/team/members/route.js | 14 +++--- src/app/ui/routes/team/route.js | 8 ++- src/app/ui/routes/watching/controller.js | 33 +++++++------ src/app/ui/routes/watching/route.js | 10 ++-- 18 files changed, 175 insertions(+), 150 deletions(-) diff --git a/src/app/ui/routes/about/controller.js b/src/app/ui/routes/about/controller.js index 8bc6f1800a..8fd5b14278 100644 --- a/src/app/ui/routes/about/controller.js +++ b/src/app/ui/routes/about/controller.js @@ -6,10 +6,10 @@ import { arch } from "utils/node/platform"; import "./styles.less"; -export default Controller.extend({ - mainConfig, - localesConfig, - metadata, - arch, - releaseUrl: mainConfig.urls.release.replace( "{version}", manifest.version ) -}); +export default class AboutController extends Controller { + mainConfig = mainConfig; + localesConfig = localesConfig; + metadata = metadata; + arch = arch; + releaseUrl = mainConfig.urls.release.replace( "{version}", manifest.version ); +} diff --git a/src/app/ui/routes/application/route.js b/src/app/ui/routes/application/route.js index f2fc87a3bc..cb643cd6ce 100644 --- a/src/app/ui/routes/application/route.js +++ b/src/app/ui/routes/application/route.js @@ -2,15 +2,15 @@ import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; -export default Route.extend({ +export default class ApplicationRoute extends Route { /** @type {AuthService} */ - auth: service(), + @service auth; /** @type {VersioncheckService} */ - versioncheck: service(), + @service versioncheck; init() { - this._super( ...arguments ); + super.init( ...arguments ); this.auth.autoLogin(); this.versioncheck.check(); } -}); +} diff --git a/src/app/ui/routes/error/route.js b/src/app/ui/routes/error/route.js index 0c5b4f716f..1fe7013042 100644 --- a/src/app/ui/routes/error/route.js +++ b/src/app/ui/routes/error/route.js @@ -1,3 +1,4 @@ +/* globals DEBUG */ import { get, set, getProperties } from "@ember/object"; import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; @@ -25,8 +26,9 @@ const duplicates = { }; -export default Route.extend({ - router: service(), +export default class ErrorRoute extends Route { + /** @type {RouterService} */ + @service router; /** * Do all the error display stuff here instead of using an error controller. @@ -35,7 +37,7 @@ export default Route.extend({ * @param {Error} error */ setupController( controller, error ) { - this._super( controller ); + super.setupController( controller ); error = error || new Error( "Unknown error" ); @@ -100,4 +102,4 @@ export default Route.extend({ : () => getProperties( trans.to, "name", "params" ) ); } -}); +} diff --git a/src/app/ui/routes/featured/controller.js b/src/app/ui/routes/featured/controller.js index 34d9130dcb..a3fe92b922 100644 --- a/src/app/ui/routes/featured/controller.js +++ b/src/app/ui/routes/featured/controller.js @@ -1,24 +1,25 @@ import Controller from "@ember/controller"; -import { get, set } from "@ember/object"; +import { set, action } from "@ember/object"; import { alias } from "@ember/object/computed"; import "./styles.less"; -export default Controller.extend({ - summary : alias( "model.summary" ), - featured: alias( "model.featured" ), +export default class FeaturedController extends Controller { + @alias( "model.summary" ) + summary; + @alias( "model.featured" ) + featured; - isAnimated: false, + isAnimated = false; // reference the active stream by id // so we can safely go back to the route - _index: 0, + _index = 0; - actions: { - switchFeatured( index ) { - if ( index === get( this, "_index" ) ) { return; } - set( this, "_index", index ); - set( this, "isAnimated", true ); - } + @action + switchFeatured( index ) { + if ( index === this._index ) { return; } + set( this, "_index", index ); + set( this, "isAnimated", true ); } -}); +} diff --git a/src/app/ui/routes/featured/route.js b/src/app/ui/routes/featured/route.js index 42e30188d8..30433adf04 100644 --- a/src/app/ui/routes/featured/route.js +++ b/src/app/ui/routes/featured/route.js @@ -1,16 +1,16 @@ -import { get, set } from "@ember/object"; +import { set } from "@ember/object"; import Route from "@ember/routing/route"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; import preload from "utils/preload"; -export default Route.extend( RefreshRouteMixin, { +export default class FeaturedRoute extends Route.extend( RefreshRouteMixin ) { async model() { - const store = get( this, "store" ); + const store = this.store; const [ summary, featured ] = await Promise.all([ - store.queryRecord( "twitchStreamSummary", {} ), - store.query( "twitchStreamFeatured", { + store.queryRecord( "twitch-stream-summary", {} ), + store.query( "twitch-stream-featured", { offset: 0, limit : 5 }) @@ -20,11 +20,11 @@ export default Route.extend( RefreshRouteMixin, { ]); return { summary, featured }; - }, + } resetController( controller, isExiting ) { if ( isExiting ) { set( controller, "isAnimated", false ); } } -}); +} diff --git a/src/app/ui/routes/games/game/route.js b/src/app/ui/routes/games/game/route.js index 64ab2b4d5a..0562fab43d 100644 --- a/src/app/ui/routes/games/game/route.js +++ b/src/app/ui/routes/games/game/route.js @@ -1,30 +1,31 @@ -import { get, set } from "@ember/object"; +import { set } from "@ember/object"; import Route from "@ember/routing/route"; import InfiniteScrollOffsetMixin from "ui/routes/-mixins/routes/infinite-scroll/offset"; import FilterLanguagesMixin from "ui/routes/-mixins/routes/filter-languages"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; -export default Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin, { - itemSelector: ".stream-item-component", - modelName: "twitchStream", - modelPreload: "preview.mediumLatest", +export default class GamesGamesRoute +extends Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin ) { + itemSelector = ".stream-item-component"; + modelName = "twitch-stream"; + modelPreload = "preview.mediumLatest"; async model({ game }) { - const model = await this._super({ game }); + const model = await super.model({ game }); return { game, model }; - }, + } async fetchContent() { - const game = get( this.controller, "game" ); + const game = this.controller.game; const { model } = await this.model({ game }); return model; - }, + } setupController( controller, { game, model }, ...args ) { - this._super( controller, model, ...args ); + super.setupController( controller, model, ...args ); set( controller, "game", game ); } -}); +} diff --git a/src/app/ui/routes/games/index/route.js b/src/app/ui/routes/games/index/route.js index 1fee96f82e..28b29512f8 100644 --- a/src/app/ui/routes/games/index/route.js +++ b/src/app/ui/routes/games/index/route.js @@ -3,8 +3,9 @@ import InfiniteScrollOffsetMixin from "ui/routes/-mixins/routes/infinite-scroll/ import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; -export default Route.extend( InfiniteScrollOffsetMixin, RefreshRouteMixin, { - itemSelector: ".game-item-component", - modelName: "twitchGameTop", - modelPreload: "game.box.large" -}); +export default class GamesIndexRoute +extends Route.extend( InfiniteScrollOffsetMixin, RefreshRouteMixin ) { + itemSelector = ".game-item-component"; + modelName = "twitch-game-top"; + modelPreload = "game.box.large"; +} diff --git a/src/app/ui/routes/index/route.js b/src/app/ui/routes/index/route.js index 576beb6ece..fa30de7adf 100644 --- a/src/app/ui/routes/index/route.js +++ b/src/app/ui/routes/index/route.js @@ -1,7 +1,7 @@ import Route from "@ember/routing/route"; -export default Route.extend({ +export default class IndexRoute extends Route { beforeModel( transition ) { // access to this route is restricted // but don't block the initial transition @@ -9,4 +9,4 @@ export default Route.extend({ transition.abort(); } } -}); +} diff --git a/src/app/ui/routes/loading/route.js b/src/app/ui/routes/loading/route.js index 7138c5c16a..86d1e3b5f6 100644 --- a/src/app/ui/routes/loading/route.js +++ b/src/app/ui/routes/loading/route.js @@ -1,7 +1,7 @@ import Route from "@ember/routing/route"; -export default Route.extend({ +export default class LoadingRoute extends Route { // override automatically generated templateName for all routes which import LoadingRoute - templateName: "loading" -}); + templateName = "loading"; +} diff --git a/src/app/ui/routes/search/controller.js b/src/app/ui/routes/search/controller.js index ee94488e17..436772b504 100644 --- a/src/app/ui/routes/search/controller.js +++ b/src/app/ui/routes/search/controller.js @@ -1,25 +1,31 @@ import Controller from "@ember/controller"; -import { get, computed } from "@ember/object"; +import { computed } from "@ember/object"; import { alias, empty, equal } from "@ember/object/computed"; import "./styles.less"; -export default Controller.extend({ - queryParams: [ "filter", "query" ], +export default class SearchController extends Controller { + queryParams = [ "filter", "query" ]; - games : alias( "model.games" ), - streams : alias( "model.streams" ), - channels: alias( "model.channels" ), + @alias( "model.games" ) + games; + @alias( "model.streams" ) + streams; + @alias( "model.channels" ) + channels; - notFiltered: equal( "filter", "all" ), + @equal( "filter", "all" ) + notFiltered; - emptyGames : empty( "games" ), - emptyStreams : empty( "streams" ), - emptyChannels: empty( "channels" ), + @empty( "games" ) + emptyGames; + @empty( "streams" ) + emptyStreams; + @empty( "channels" ) + emptyChannels; - noResults: computed( "emptyGames", "emptyStreams", "emptyChannels", function() { - return get( this, "emptyGames" ) - && get( this, "emptyStreams" ) - && get( this, "emptyChannels" ); - }) -}); + @computed( "emptyGames", "emptyStreams", "emptyChannels" ) + get noResults() { + return this.emptyGames && this.emptyStreams && this.emptyChannels; + } +} diff --git a/src/app/ui/routes/search/route.js b/src/app/ui/routes/search/route.js index 4aa54c2db9..1685c1d1e5 100644 --- a/src/app/ui/routes/search/route.js +++ b/src/app/ui/routes/search/route.js @@ -1,4 +1,4 @@ -import { get, setProperties } from "@ember/object"; +import { setProperties } from "@ember/object"; import Route from "@ember/routing/route"; import InfiniteScrollMixin from "ui/routes/-mixins/routes/infinite-scroll"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; @@ -32,8 +32,8 @@ const fetchMethods = { }; -export default Route.extend( InfiniteScrollMixin, RefreshRouteMixin, { - queryParams: { +export default class SearchRoute extends Route.extend( InfiniteScrollMixin, RefreshRouteMixin ) { + queryParams = { filter: { refreshModel: true, replace: false @@ -42,7 +42,11 @@ export default Route.extend( InfiniteScrollMixin, RefreshRouteMixin, { refreshModel: true, replace: false } - }, + }; + + contentPath; + itemSelector; + fetchMethod; beforeModel() { @@ -55,8 +59,8 @@ export default Route.extend( InfiniteScrollMixin, RefreshRouteMixin, { fetchMethod: fetchMethods[ filter ] }); - return this._super( ...arguments ); - }, + return super.beforeModel( ...arguments ); + } async model( params ) { const [ games, channels, streams ] = await Promise.all([ @@ -66,59 +70,70 @@ export default Route.extend( InfiniteScrollMixin, RefreshRouteMixin, { ]); return { games, channels, streams }; - }, + } fetchContent() { - const fetchMethod = get( this, "fetchMethod" ); - const filter = get( this, "controller.filter" ); - const query = get( this, "controller.query" ); + const fetchMethod = this.fetchMethod; + const { filter, query } = this.controller; return this[ fetchMethod ]({ filter, query }); - }, + } + /** + * @param filter + * @param query + * @returns {Promise} + */ async fetchGames({ filter, query }) { if ( !filterMatches( filter, "games" ) ) { return []; } - const store = get( this, "store" ); - const records = await store.query( "twitchSearchGame", { + const records = await this.store.query( "twitch-search-game", { type: "suggest", live: true, query }); return await preload( toArray( records ), "game.box.largeLatest" ); - }, + } + /** + * @param filter + * @param query + * @returns {Promise} + */ async fetchChannels({ filter, query }) { if ( !filterMatches( filter, "channels" ) ) { return []; } - const store = get( this, "store" ); - const records = await store.query( "twitchSearchChannel", { - offset: get( this, "offset" ), - limit: get( this, "limit" ), + const records = await this.store.query( "twitch-search-channel", { + offset: this.offset, + limit: this.limit, query }); return await preload( mapBy( records, "channel" ), "logo" ); - }, + } + /** + * @param filter + * @param query + * @returns {Promise} + */ async fetchStreams({ filter, query }) { if ( !filterMatches( filter, "streams" ) ) { return []; } - const store = get( this, "store" ); - const records = await store.query( "twitchSearchStream", { - offset: get( this, "offset" ), - limit: get( this, "limit" ), + const records = await this.store.query( "twitch-search-stream", { + offset: this.offset, + limit: this.limit, query }); return await preload( mapBy( records, "stream" ), "preview.mediumLatest" ); } -}); +} diff --git a/src/app/ui/routes/streams/route.js b/src/app/ui/routes/streams/route.js index 9d02f648f8..a55aa7485f 100644 --- a/src/app/ui/routes/streams/route.js +++ b/src/app/ui/routes/streams/route.js @@ -4,8 +4,9 @@ import FilterLanguagesMixin from "ui/routes/-mixins/routes/filter-languages"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; -export default Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin, { - itemSelector: ".stream-item-component", - modelName: "twitchStream", - modelPreload: "preview.mediumLatest" -}); +export default class StreamsRoute +extends Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin ) { + itemSelector = ".stream-item-component"; + modelName = "twitch-stream"; + modelPreload = "preview.mediumLatest"; +} diff --git a/src/app/ui/routes/team/index/route.js b/src/app/ui/routes/team/index/route.js index 312347ee66..c97dea90ce 100644 --- a/src/app/ui/routes/team/index/route.js +++ b/src/app/ui/routes/team/index/route.js @@ -1,34 +1,33 @@ -import { get } from "@ember/object"; import Route from "@ember/routing/route"; import InfiniteScrollMixin from "ui/routes/-mixins/routes/infinite-scroll"; import { toArray } from "utils/ember/recordArrayMethods"; import preload from "utils/preload"; -export default Route.extend( InfiniteScrollMixin, { - itemSelector: ".stream-item-component", +export default class TeamIndexRoute extends Route.extend( InfiniteScrollMixin ) { + itemSelector = ".stream-item-component"; beforeModel() { this.customOffset = 0; - return this._super( ...arguments ); - }, + return super.beforeModel( ...arguments ); + } async model() { - const store = get( this, "store" ); - const limit = get( this, "limit" ); + const store = this.store; + const limit = this.limit; const model = this.modelFor( "team" ); - const users = get( model, "users" ); - const length = get( users, "length" ); + const channels = model.users; + const length = channels.length; let offsetCalculated = false; const options = { reload: true }; const fill = async ( streams, start ) => { const end = start + limit; - const records = await Promise.all( users + const records = await Promise.all( channels .slice( start, end ) - .map( channel => store.findRecord( "twitchStream", get( channel, "id" ), options ) + .map( channel => store.findRecord( "twitch-stream", channel.id, options ) .catch( () => false ) ) ); @@ -55,4 +54,4 @@ export default Route.extend( InfiniteScrollMixin, { return await preload( records, "preview.mediumLatest" ); } -}); +} diff --git a/src/app/ui/routes/team/info/route.js b/src/app/ui/routes/team/info/route.js index ac10b1ca08..9d63662705 100644 --- a/src/app/ui/routes/team/info/route.js +++ b/src/app/ui/routes/team/info/route.js @@ -2,12 +2,12 @@ import { getOwner } from "@ember/application"; import Route from "@ember/routing/route"; -export default Route.extend({ +export default class TeamInfoRoute extends Route { model() { return this.modelFor( "team" ); - }, + } refresh() { return getOwner( this ).lookup( "route:team" ).refresh(); } -}); +} diff --git a/src/app/ui/routes/team/members/route.js b/src/app/ui/routes/team/members/route.js index 23a019d7b0..dd96a38c5d 100644 --- a/src/app/ui/routes/team/members/route.js +++ b/src/app/ui/routes/team/members/route.js @@ -1,22 +1,20 @@ -import { get } from "@ember/object"; import Route from "@ember/routing/route"; import InfiniteScrollMixin from "ui/routes/-mixins/routes/infinite-scroll"; import preload from "utils/preload"; -export default Route.extend( InfiniteScrollMixin, { - itemSelector: ".channel-item-component", +export default class TeamMembersRoute extends Route.extend( InfiniteScrollMixin ) { + itemSelector = ".channel-item-component"; async model() { const model = this.modelFor( "team" ); - const offset = get( this, "offset" ); - const limit = get( this, "limit" ); + const offset = this.offset; + const limit = this.limit; - const channels = get( model, "users" ) - .slice( offset, offset + limit ); + const channels = model.users.slice( offset, offset + limit ); const records = await Promise.all( channels ); return await preload( records, "logo" ); } -}); +} diff --git a/src/app/ui/routes/team/route.js b/src/app/ui/routes/team/route.js index 7ea01b2b83..42bdf03196 100644 --- a/src/app/ui/routes/team/route.js +++ b/src/app/ui/routes/team/route.js @@ -1,14 +1,12 @@ -import { get } from "@ember/object"; import Route from "@ember/routing/route"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; import preload from "utils/preload"; -export default Route.extend( RefreshRouteMixin, { +export default class TeamRoute extends Route.extend( RefreshRouteMixin ) { async model({ team }) { - const store = get( this, "store" ); - const record = await store.findRecord( "twitchTeam", team, { reload: true } ); + const record = await this.store.findRecord( "twitch-team", team, { reload: true } ); return await preload( record, "logo" ); } -}); +} diff --git a/src/app/ui/routes/watching/controller.js b/src/app/ui/routes/watching/controller.js index 061f7f12f7..bcd32435f6 100644 --- a/src/app/ui/routes/watching/controller.js +++ b/src/app/ui/routes/watching/controller.js @@ -1,27 +1,30 @@ import Controller from "@ember/controller"; -import { get } from "@ember/object"; +import { action } from "@ember/object"; import { sort } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import { qualities } from "data/models/stream/model"; import "./styles.less"; -export default Controller.extend({ - auth: service(), - streaming: service(), +export default class WatchingController extends Controller { + /** @type {AuthService} */ + @service auth; + /** @type {StreamingService} */ + @service streaming; - sortedModel: sort( "model", "sortBy" ), - sortBy: [ "started:desc" ], + @sort( "model", "sortBy" ) + sortedModel; + sortBy = [ "started:desc" ]; - qualities, + qualities = qualities; - actions: { - openDialog( stream ) { - get( this, "streaming" ).startStream( stream ); - }, + @action + openDialog( stream ) { + this.streaming.startStream( stream ); + } - closeStream( stream ) { - get( this, "streaming" ).closeStream( stream ); - } + @action + closeStream( stream ) { + this.streaming.closeStream( stream ); } -}); +} diff --git a/src/app/ui/routes/watching/route.js b/src/app/ui/routes/watching/route.js index bb9596ccf8..3be34513b4 100644 --- a/src/app/ui/routes/watching/route.js +++ b/src/app/ui/routes/watching/route.js @@ -1,4 +1,3 @@ -import { get } from "@ember/object"; import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; @@ -6,13 +5,14 @@ import { mapBy } from "utils/ember/recordArrayMethods"; import preload from "utils/preload"; -export default Route.extend( RefreshRouteMixin, { - streaming: service(), +export default class WatchingRoute extends Route.extend( RefreshRouteMixin ) { + /** @type {StreamingService} */ + @service streaming; async model() { - const model = get( this, "streaming.model" ); + const model = this.streaming.model; await preload( mapBy( model, "stream" ), "preview.largeLatest" ); return model; } -}); +} From c0c5780c806207989f013e1352e8f108e1430577 Mon Sep 17 00:00:00 2001 From: bastimeyer Date: Wed, 1 May 2019 17:58:24 +0200 Subject: [PATCH 20/34] native classes: user routes --- src/app/ui/routes/user/auth/controller.js | 203 +++++++++--------- src/app/ui/routes/user/auth/route.js | 29 +-- src/app/ui/routes/user/auth/template.hbs | 4 +- .../user/followed-channels/controller.js | 26 +-- .../ui/routes/user/followed-channels/route.js | 26 +-- .../ui/routes/user/followed-streams/route.js | 13 +- src/app/ui/routes/user/index/controller.js | 63 +++--- src/app/ui/routes/user/index/route.js | 17 +- src/app/ui/routes/user/index/template.hbs | 2 +- src/app/utils/wait.js | 17 -- 10 files changed, 201 insertions(+), 199 deletions(-) delete mode 100644 src/app/utils/wait.js diff --git a/src/app/ui/routes/user/auth/controller.js b/src/app/ui/routes/user/auth/controller.js index afad7e4839..a65cd0f555 100644 --- a/src/app/ui/routes/user/auth/controller.js +++ b/src/app/ui/routes/user/auth/controller.js @@ -1,26 +1,28 @@ import Controller from "@ember/controller"; -import { get, set, computed, observer } from "@ember/object"; +import { set, computed, action } from "@ember/object"; +import { later } from "@ember/runloop"; import { inject as service } from "@ember/service"; -import { twitch } from "config"; +import { observes } from "@ember-decorators/object"; +import { twitch as twitchConfig } from "config"; import RetryTransitionMixin from "ui/routes/-mixins/controllers/retry-transition"; -import wait from "utils/wait"; -const { oauth: { scope } } = twitch; +const { oauth: { scope } } = twitchConfig; -export default Controller.extend( RetryTransitionMixin, { - auth: service(), - settings: service(), +export default class UserAuthController extends Controller.extend( RetryTransitionMixin ) { + /** @type {AuthService} */ + @service auth; + /** @type {SettingsService} */ + @service settings; retryTransition() { // use "user.index" as default route - return this._super( "user.index" ); - }, - - token: "", + return super.retryTransition( "user.index" ); + } - scope: scope.join( ", " ), + token = ""; + scope = scope.join( ", " ); /** * 0 000: start @@ -32,107 +34,114 @@ export default Controller.extend( RetryTransitionMixin, { * 6 110: token - failure * 7 111: token - success */ - loginStatus: 0, + loginStatus = 0; - userStatus: computed( "loginStatus", function() { - return get( this, "loginStatus" ) & 3; - }), + @computed( "loginStatus" ) + get userStatus() { + return this.loginStatus & 0b011; + } - hasUserInteraction: computed( "userStatus", function() { - return get( this, "userStatus" ) > 0; - }), + @computed( "userStatus" ) + get hasUserInteraction() { + return this.userStatus > 0; + } - isLoggingIn: computed( "loginStatus", function() { - return get( this, "loginStatus" ) === 1; - }), + @computed( "loginStatus" ) + get isLoggingIn() { + return this.loginStatus === 1; + } - hasLoginResult: computed( "userStatus", function() { - const userStatus = get( this, "userStatus" ); - return ( userStatus & 2 ) > 0; - }), + @computed( "userStatus" ) + get hasLoginResult() { + return ( this.userStatus & 0b010 ) > 0; + } - showFailMessage: computed( "userStatus", function() { - return get( this, "userStatus" ) === 2; - }), + @computed( "userStatus" ) + get isFailMessageVisible() { + return this.userStatus === 0b010; + } - showTokenForm: computed( "loginStatus", function() { - return get( this, "loginStatus" ) & 4; - }), + @computed( "loginStatus" ) + get isTokenFormVisible() { + return this.loginStatus & 0b100; + } - serverObserver: observer( "auth.server", function() { - const authServer = get( this, "auth.server" ); + @observes( "auth.server" ) + serverObserver() { + const authServer = this.auth.server; set( this, "loginStatus", authServer ? 1 : 0 ); - }), + } resetProperties() { set( this, "token", "" ); set( this, "loginStatus", 0 ); - }, + } + + @action + showTokenForm() { + set( this, "loginStatus", 4 ); + } - actions: { - showTokenForm() { + // login via user and password + @action + async signin() { + if ( this.isLoggingIn ) { return; } + set( this, "loginStatus", 1 ); + + try { + await this.auth.signin(); + set( this, "loginStatus", 3 ); + this.retryTransition(); + + } catch ( e ) { + set( this, "loginStatus", 2 ); + await new Promise( r => later( r, 3000 ) ); + set( this, "loginStatus", 0 ); + } + } + + // login via access token + @action + async signinToken( success, failure ) { + if ( this.isLoggingIn ) { return; } + set( this, "loginStatus", 5 ); + + const token = this.token; + + // show the loading icon for a sec and wait + await new Promise( r => later( r, 1000 ) ); + + let successful = false; + try { + // login attempt + await this.auth.login( token, false ); + + // visualize result: update button and icon + set( this, "loginStatus", 7 ); + await new Promise( r => later( r, 1000 ) ); + await success(); + successful = true; + + } catch ( e ) { + set( this, "loginStatus", 6 ); + await new Promise( r => later( r, 3000 ) ); + await failure(); + + } finally { set( this, "loginStatus", 4 ); - }, - - // login via user and password - signin() { - if ( get( this, "isLoggingIn" ) ) { return; } - set( this, "loginStatus", 1 ); - - const auth = get( this, "auth" ); - - auth.signin() - .then( () => { - set( this, "loginStatus", 3 ); - this.retryTransition(); - }) - .catch( () => { - set( this, "loginStatus", 2 ); - wait( 3000 )() - .then( () => { - set( this, "loginStatus", 0 ); - }); - }); - }, - - // login via access token - signinToken( success, failure ) { - if ( get( this, "isLoggingIn" ) ) { return; } - set( this, "loginStatus", 5 ); - - const token = get( this, "token" ); - const auth = get( this, "auth" ); - - // show the loading icon for a sec and wait - wait( 1000 )() - // login attempt - .then( () => auth.login( token, false ) ) - // visualize result: update button and icon - .then( () => { - set( this, "loginStatus", 7 ); - return wait( 1000 )( true ) - .then( success ); - }, () => { - set( this, "loginStatus", 6 ); - return wait( 3000 )( false ) - .then( failure ) - .catch( data => data ); - }) - // retry transition on success - .then( result => { - set( this, "loginStatus", 4 ); - if ( result ) { - this.retryTransition(); - } - }); - }, - - // abort sign in with username + password - abort() { - get( this, "auth" ).abortSignin(); + // retry transition on success + if ( successful ) { + this.retryTransition(); + } } } -}); + + // abort sign in with username + password + @action + abort() { + this.auth.abortSignin(); + } +} diff --git a/src/app/ui/routes/user/auth/route.js b/src/app/ui/routes/user/auth/route.js index e03011fd84..f9a1a5b47a 100644 --- a/src/app/ui/routes/user/auth/route.js +++ b/src/app/ui/routes/user/auth/route.js @@ -1,23 +1,28 @@ -import { get } from "@ember/object"; +import { action } from "@ember/object"; import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; -export default Route.extend({ - auth: service(), +export default class UserAuthRoute extends Route { + /** @type {AuthService} */ + @service auth; + /** @type {RouterService} */ + @service router; beforeModel( transition ) { + /** @type {Auth} */ + const session = this.auth.session; + // check if user is successfully logged in - if ( get( this, "auth.session.isLoggedIn" ) ) { + if ( session && session.isLoggedIn ) { transition.abort(); - this.transitionTo( "user.index" ); + this.router.transitionTo( "user.index" ); } - }, + } - actions: { - willTransition() { - this.controller.send( "abort" ); - this.controller.resetProperties(); - } + @action + willTransition() { + this.controller.send( "abort" ); + this.controller.resetProperties(); } -}); +} diff --git a/src/app/ui/routes/user/auth/template.hbs b/src/app/ui/routes/user/auth/template.hbs index a14d4dc5c4..5303d027ee 100644 --- a/src/app/ui/routes/user/auth/template.hbs +++ b/src/app/ui/routes/user/auth/template.hbs @@ -20,7 +20,7 @@ {{/if}}
    {{#if settings.advanced}} -{{#if showTokenForm}} +{{#if isTokenFormVisible}}
    {{input type="text" @@ -54,7 +54,7 @@ {{/form-button}} {{/if}} {{/if}} -{{#if showFailMessage}} +{{#if isFailMessageVisible}}

    {{t "routes.user.auth.fail"}}

    {{/if}}
    diff --git a/src/app/ui/routes/user/followed-channels/controller.js b/src/app/ui/routes/user/followed-channels/controller.js index fd00b05be6..3fada196b0 100644 --- a/src/app/ui/routes/user/followed-channels/controller.js +++ b/src/app/ui/routes/user/followed-channels/controller.js @@ -1,20 +1,20 @@ import Controller from "@ember/controller"; -import { set } from "@ember/object"; +import { set, action } from "@ember/object"; -export default Controller.extend({ - queryParams: [ "sortby", "direction" ], +export default class UserFollowedChannelsRoute extends Controller { + queryParams = [ "sortby", "direction" ]; - sortby : "created_at", - direction: "desc", + sortby = "created_at"; + direction = "desc"; - actions: { - sortMethod( sortby ) { - set( this, "sortby", sortby ); - }, + @action + sortMethod( sortby ) { + set( this, "sortby", sortby ); + } - sortOrder( direction ) { - set( this, "direction", direction ); - } + @action + sortOrder( direction ) { + set( this, "direction", direction ); } -}); +} diff --git a/src/app/ui/routes/user/followed-channels/route.js b/src/app/ui/routes/user/followed-channels/route.js index 89dfa76bc2..bfb23981e9 100644 --- a/src/app/ui/routes/user/followed-channels/route.js +++ b/src/app/ui/routes/user/followed-channels/route.js @@ -1,32 +1,32 @@ -import { getProperties } from "@ember/object"; import UserIndexRoute from "../index/route"; import InfiniteScrollOffsetMixin from "ui/routes/-mixins/routes/infinite-scroll/offset"; import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh"; -export default UserIndexRoute.extend( InfiniteScrollOffsetMixin, RefreshRouteMixin, { - itemSelector: ".channel-item-component", - modelName: "twitchChannelFollowed", - modelMapBy: "channel", - modelPreload: "logo", +export default class UserFollowedChannelsRoute +extends UserIndexRoute.extend( InfiniteScrollOffsetMixin, RefreshRouteMixin ) { + itemSelector = ".channel-item-component"; + modelName = "twitch-channel-followed"; + modelMapBy = "channel"; + modelPreload = "logo"; - queryParams: { + queryParams = { sortby: { refreshModel: true }, direction: { refreshModel: true } - }, + }; model({ sortby = "created_at", direction = "desc" }) { - return this._super({ sortby, direction }); - }, + return super.model({ sortby, direction }); + } fetchContent() { - const params = getProperties( this.controller, "sortby", "direction" ); + const { sortby, direction } = this.controller; - return this.model( params ); + return this.model({ sortby, direction }); } -}); +} diff --git a/src/app/ui/routes/user/followed-streams/route.js b/src/app/ui/routes/user/followed-streams/route.js index c41423aa9c..f20f11f140 100644 --- a/src/app/ui/routes/user/followed-streams/route.js +++ b/src/app/ui/routes/user/followed-streams/route.js @@ -6,13 +6,14 @@ import { mapBy } from "utils/ember/recordArrayMethods"; import { preload } from "utils/preload"; -export default UserIndexRoute.extend( InfiniteScrollMixin, RefreshRouteMixin, { - itemSelector: ".stream-item-component", +export default class UserFollowedStreamsRoute +extends UserIndexRoute.extend( InfiniteScrollMixin, RefreshRouteMixin ) { + itemSelector = ".stream-item-component"; // Guard against infinite API queries in case Twitch's query offset implemention breaks. // Assume that nobody has followed so many channels that more than 500 (5*maxLimit) streams // are online at the same time. - maxQueries: 5, + maxQueries = 5; /** * Twitch doesn't sort the followed streams response anymore: @@ -43,7 +44,7 @@ export default UserIndexRoute.extend( InfiniteScrollMixin, RefreshRouteMixin, { // return the first infinite scroll result as initial model data return await this.fetchContent(); - }, + } /** * @returns {Promise} @@ -57,10 +58,10 @@ export default UserIndexRoute.extend( InfiniteScrollMixin, RefreshRouteMixin, { }; return await preload( streams, "preview.mediumLatest" ); - }, + } deactivate() { this._super( ...arguments ); this.all = null; } -}); +} diff --git a/src/app/ui/routes/user/index/controller.js b/src/app/ui/routes/user/index/controller.js index 3acc7811e9..3e7ca5af4e 100644 --- a/src/app/ui/routes/user/index/controller.js +++ b/src/app/ui/routes/user/index/controller.js @@ -1,47 +1,50 @@ import Controller from "@ember/controller"; -import { set, computed } from "@ember/object"; +import { set, computed, action } from "@ember/object"; import { inject as service } from "@ember/service"; -export default Controller.extend({ +export default class UserIndexController extends Controller { /** @type {AuthService} */ - auth: service(), + @service auth; /** @type {NotificationService} */ - notification: service(), + @service notification; /** @type {NwjsService} */ - nwjs: service(), + @service nwjs; /** @type {RouterService} */ - router: service(), + @service router; /** @type {SettingsService} */ - settings: service(), + @service settings; - scope: computed( "auth.session.scope", function() { + isTokenFormVisible = false; + + @computed( "auth.session.scope" ) + get scope() { + /** @type {Auth} */ const { session } = this.auth; return session && session.scope ? session.scope.split( "+" ).join( ", " ) : ""; - }), - - showTokenForm: false, - - actions: { - async signout() { - await this.auth.signout(); - this.router.transitionTo( "user.auth" ); - }, - - async copyToken( success, failure ) { - try { - this.nwjs.clipboard.set( this.auth.session.access_token ); - await success(); - } catch ( err ) { - await failure( err ); - } - }, - - showTokenForm() { - set( this, "showTokenForm", true ); + } + + @action + async signout() { + await this.auth.signout(); + this.router.transitionTo( "user.auth" ); + } + + @action + async copyToken( success, failure ) { + try { + this.nwjs.clipboard.set( this.auth.session.access_token ); + await success(); + } catch ( err ) { + await failure( err ); } } -}); + + @action + showTokenForm() { + set( this, "isTokenFormVisible", true ); + } +} diff --git a/src/app/ui/routes/user/index/route.js b/src/app/ui/routes/user/index/route.js index 0740ca9345..be94488e29 100644 --- a/src/app/ui/routes/user/index/route.js +++ b/src/app/ui/routes/user/index/route.js @@ -4,10 +4,11 @@ import Route from "@ember/routing/route"; import { inject as service } from "@ember/service"; -export default Route.extend({ - auth: service(), +export default class UserIndexRoute extends Route { + /** @type {AuthService} */ + @service auth; /** @type {RouterService} */ - router: service(), + @service router; beforeModel( transition ) { /** @type {Auth} */ @@ -25,13 +26,13 @@ export default Route.extend({ } else { this._waitForLogin(); } - }, + } _redirectToLoginForm() { const controller = this.controllerFor( "userAuth" ); set( controller, "previousTransition", this._transition ); this.router.transitionTo( "user.auth" ); - }, + } _waitForLogin() { // no ongoing login? prompt user to log in. @@ -47,11 +48,11 @@ export default Route.extend({ // register callback once addListener( this.auth, "login", this, "_onLogin", true ); - }, + } _removeOnLoginListener() { removeListener( this.auth, "login", this, "_onLogin" ); - }, + } _onLogin( success ) { this._removeOnLoginListener(); @@ -62,4 +63,4 @@ export default Route.extend({ this._redirectToLoginForm(); } } -}); +} diff --git a/src/app/ui/routes/user/index/template.hbs b/src/app/ui/routes/user/index/template.hbs index a04ff85089..1d171c3160 100644 --- a/src/app/ui/routes/user/index/template.hbs +++ b/src/app/ui/routes/user/index/template.hbs @@ -8,7 +8,7 @@ {{/form-button}} {{#if settings.advanced}}