├── .gitignore
├── .npmignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── demo
├── index.html
├── logo-114.png
├── logo-120.png
├── logo-128.png
├── logo-144.png
├── logo-152.png
├── logo-16.png
├── logo-180.png
├── logo-192.png
├── logo-32.png
├── manifest.json
├── nocode.html
├── other.html
└── sw.js
├── package.json
├── pwacompat.min.js
├── src
├── externs.js
├── pwacompat.js
└── test.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .travis.yml
2 | suite.*
3 | testrunner.*
4 | yarn.lock
5 | test/
6 | src/suite.*
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | dist: trusty
3 | node_js:
4 | - "node"
5 | addons:
6 | chrome: stable
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Want to contribute? Great! First, read this page (including the small print at the end).
2 |
3 | ### Before you contribute
4 | Before we can use your code, you must sign the
5 | [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
6 | (CLA), which you can do online. The CLA is necessary mainly because you own the
7 | copyright to your changes, even after your contribution becomes part of our
8 | codebase, so we need your permission to use and distribute your code. We also
9 | need to be sure of various other things—for instance that you'll tell us if you
10 | know that your code infringes on other people's patents. You don't have to sign
11 | the CLA until after you've submitted your code for review and a member has
12 | approved it, but you must do it before we can put your code into our codebase.
13 | Before you start working on a larger contribution, you should get in touch with
14 | us first through the issue tracker with your idea so that we can help out and
15 | possibly guide you. Coordinating up front makes it much easier to avoid
16 | frustration later on.
17 |
18 | ### Code reviews
19 | All submissions, including submissions by project members, require review. We
20 | use Github pull requests for this purpose.
21 |
22 | ### The small print
23 | Contributions made by corporations are covered by a different agreement than
24 | the one above, the Software Grant and Corporate Contributor License Agreement.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/GoogleChromeLabs/pwacompat)
2 |
3 | PWACompat is a library that brings the [Web App Manifest](https://developers.google.com/web/fundamentals/web-app-manifest/) to non-compliant browsers for better [Progressive Web Apps](https://en.wikipedia.org/wiki/Progressive_Web_Apps).
4 | This mostly means creating splash screens and icons for Mobile Safari, as well as supporting IE/Edge's Pinned Sites feature.
5 |
6 | So, if you've created a `manifest.webmanifest` but want to have wide support everywhere else—through legacy HTML tags for icons and theming—look no further.
7 | We recommend including it from a CDN to get the latest version, or [bundling it yourself](https://npmjs.com/package/pwacompat):
8 |
9 | ```html
10 |
11 |
12 |
13 |
14 | ```
15 |
16 | And you're done^! 🎉📄
17 |
18 | For more on the Web App Manifest, read 📖 [how to add a Web App Manifest and mobile-proof your site](https://medium.com/dev-channel/how-to-add-a-web-app-manifest-and-mobile-proof-your-site-450e6e485638), watch 📹 [theming as part of The Standard](https://www.youtube.com/watch?v=5fEMTxpA6BA), or check out 📬 [the Web Fundamentals post on PWACompat](https://developers.google.com/web/updates/2018/07/pwacompat).
19 |
20 |
21 |
22 | PWACompat takes your regular manifest and enhances other browsers
23 |
24 |
25 | # ^Best Practice & Caveats
26 |
27 | While PWACompat can generate most icons, meta tags etc that your PWA might need, it's best practice to include at least one ` `.
28 | This is standardized and older browsers, along with search engines, may use it from your page to display an icon.
29 | For example:
30 |
31 | ```html
32 |
33 |
34 |
35 |
36 | ```
37 |
38 | You should also consider only loading PWACompat after your site is loaded, as adding your site to a homescreen is a pretty rare operation.
39 | This is the approach taken on [v8.dev](https://github.com/v8/v8.dev/pull/310/files) and [Emojityper](https://github.com/emojityper/emojityper/blob/master/src/loader.js#L8).
40 |
41 | ## iOS
42 |
43 | PWACompat looks for a viewport tag which includes `viewport-fit=cover`, such as ` `.
44 | If this tag is detected, PWACompat will generate a meta tag that makes your PWA load in fullscreen mode—this is particularly useful for devices with a notch.
45 |
46 | You can customize the generated splash screen's font by using a CSS Variable.
47 | For example:
48 |
49 | ```html
50 |
55 | ```
56 |
57 | This is set directly as a [canvas font](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font), so you must as a minimum include size _and_ family.
58 | The default value is "24px HelveticaNeue-CondensedBold".
59 |
60 | ⚠️ PWACompat won't wait for your fonts to load, so if you're using custom fonts, be sure to only load the library after they're ready.
61 |
62 | ### Old Versions
63 |
64 | Prior [to iOS 12.2](https://twitter.com/mhartington/status/1089293403089784832), Mobile Safari opens external sites in the regular browser, meaning that flows like Oauth won't complete correctly.
65 | This [isn't a problem with PWACompat](https://github.com/GoogleChromeLabs/pwacompat/issues/15), but is an issue with PWAs on iOS generally.
66 |
67 | ## Session Storage
68 |
69 | PWACompat uses `window.sessionStorage` to cache your site's manifest (and on iOS, any updated icons and generated splash screens).
70 | This expires after a user navigates away from your page or closes their tab.
71 |
72 | # Details
73 |
74 | What does PWACompat actually do?
75 | If you provide a Web App Manifest, PWACompat will update your page and:
76 |
77 | * Create meta icon tags for all icons in the manifest (e.g., for a favicon, older browsers)
78 | * Create fallback meta tags for various browsers (e.g., iOS, WebKit/Chromium forks etc) describing how a PWA should open
79 | * Sets [the theme color](https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android) based on the manifest
80 |
81 | For Safari, PWACompat also:
82 |
83 | * Sets `apple-mobile-web-app-capable` (opening without a browser chrome) for display modes `standalone`, `fullscreen` or `minimal-ui`
84 | * Creates `apple-touch-icon` images, adding the manifest background to transparent icons: otherwise, iOS renders transparency as black
85 | * Creates dynamic splash images, closely matching the splash images generated [for Chromium-based browsers](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashScreenController.java?type=cs&q=webappsplash&sq=package:chromium&g=0&l=70)
86 |
87 | For IE and Edge:
88 |
89 | * Adds meta tags for the [Pinned Sites](https://blogs.msdn.microsoft.com/jennifer/2011/04/20/ie-pinned-sites-part-1-what-are-pinned-sites/) feature
90 |
91 | For PWAs on Windows with access to UWP APIs:
92 |
93 | * Sets the titlebar color
94 |
95 | Do you think PWACompat should support backfilling more HTML tags needed for older browsers?
96 | [Let us know!](https://github.com/GoogleChromeLabs/pwacompat/issues)
97 |
98 | ## Demo
99 |
100 | For a demo, try adding [Emojityper](https://emojityper.com/) or [the demo site](https://googlechromelabs.github.io/pwacompat/demo/) to an iOS home screen (to see splash screens and icons).
101 | You can also install Emojityper from the [Microsoft Store](https://www.microsoft.com/p/emojityper/9np2xx3sxmct) (where the titlebar color is automatically set the manifest's `theme_color`).
102 |
103 | ## Support
104 |
105 | This is supported in most modern browsers (UC Browser, Safari, Firefox, Chrome, IE10+), and fails silenty when unsupported.
106 | Mobile Safari benefits the most from PWACompat, as generating [a large number of splash screens](https://google.com/search?q=ios%20webapp%20splash%20screens) manually is a complex task.
107 |
108 | # Web App Manifest
109 |
110 | Your Web App Manifest is:
111 |
112 | * normally named `manifest.webmanifest` (although some folks name it `manifest.json`)
113 | * referenced from all pages on your site like ` `
114 | * and should look a bit like this:
115 |
116 | ```js
117 | {
118 | "name": "Always Be Progressive",
119 | "short_name": "Progressive!",
120 | "display": "browser",
121 | "start_url": "/",
122 | "background_color": "#102a48",
123 | "icons": [
124 | {
125 | "src": "res/icon-256.png",
126 | "sizes": "256x256"
127 | },
128 | {
129 | "src": "res/icon-128.png",
130 | "sizes": "128x128"
131 | }
132 | ]
133 | }
134 | ```
135 |
136 | For more information on the Web App Manifest, and how e.g., modern browsers will prompt engaged users to install your site to their home screen, check out [Web Fundamentals](https://developers.google.com/web/fundamentals/web-app-manifest/).
137 | There's also a number of [online generators](https://www.google.com/search?q=web+app+manifest+generator).
138 |
139 | # Release
140 |
141 | Compile code with [Closure Compiler](https://closure-compiler.appspot.com/home).
142 |
143 | ```
144 | // ==ClosureCompiler==
145 | // @compilation_level ADVANCED_OPTIMIZATIONS
146 | // @output_file_name pwacompat.min.js
147 | // ==/ClosureCompiler==
148 |
149 | // code here
150 | ```
151 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
24 | PWA Compat
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | This is a test of PWA Compat .
35 | Try adding this site to your home screen on an iOS device to see correctly rendered icons and dynamic splash screens!
36 | It uses the uncompiled file, for testing.
37 |
38 |
39 | Links to local page , page without PWA Compat or an external site .
40 |
41 |
42 | Change Hash 1
43 | Change Hash 2
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/demo/logo-114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-114.png
--------------------------------------------------------------------------------
/demo/logo-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-120.png
--------------------------------------------------------------------------------
/demo/logo-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-128.png
--------------------------------------------------------------------------------
/demo/logo-144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-144.png
--------------------------------------------------------------------------------
/demo/logo-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-152.png
--------------------------------------------------------------------------------
/demo/logo-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-16.png
--------------------------------------------------------------------------------
/demo/logo-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-180.png
--------------------------------------------------------------------------------
/demo/logo-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-192.png
--------------------------------------------------------------------------------
/demo/logo-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/pwacompat/b24effcc909b6a8d8b50e0f3b1e8157425dfb30c/demo/logo-32.png
--------------------------------------------------------------------------------
/demo/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "long long `PWA Compat` long long",
3 | "short_name": "short `PWA Compat` short",
4 | "icons": [
5 | {
6 | "src": "logo-192.png",
7 | "sizes": "192x192"
8 | },
9 | {
10 | "src": "logo-180.png",
11 | "sizes": "180x180"
12 | },
13 | {
14 | "src": "logo-152.png",
15 | "sizes": "152x152"
16 | },
17 | {
18 | "src": "logo-144.png",
19 | "sizes": "144x144"
20 | },
21 | {
22 | "src": "logo-128.png",
23 | "sizes": "128x128"
24 | },
25 | {
26 | "src": "logo-128.png",
27 | "sizes": "128x128"
28 | },
29 | {
30 | "src": "logo-120.png",
31 | "sizes": "120x120"
32 | },
33 | {
34 | "src": "logo-114.png",
35 | "sizes": "114x114"
36 | },
37 | {
38 | "src": "logo-32.png",
39 | "sizes": "32x32"
40 | },
41 | {
42 | "src": "logo-16.png",
43 | "sizes": "16x16"
44 | }
45 | ],
46 | "display": "standalone",
47 | "scope": "/",
48 | "start_url": "./?homescreen=true",
49 | "orientation": "portrait",
50 | "theme_color": "#1abc9c",
51 | "background_color": "#2c3e50",
52 | "related_applications": [
53 | {
54 | "platform": "play",
55 | "url": "https://play.google.com/store/apps/details?id=com.example.app1",
56 | "id": "com.example.app1"
57 | },
58 | {
59 | "platform": "itunes",
60 | "url": "https://itunes.apple.com/app/example-app1/id123456789"
61 | }
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/demo/nocode.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | PWA Compat
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | This is a test of PWA Compat .
29 | This does NOT include the PWA Compat code, however.
30 |
31 |
32 | Links to home page .
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/demo/other.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | Other — PWA Compat
20 |
21 |
22 |
23 |
24 |
29 |
48 |
49 |
50 |
51 |
52 |
53 | Different page for the PWA Compat Test.
54 | This page registers a zero Service Worker.
55 |
56 |
57 | Link back to the starter page . Reload
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/demo/sw.js:
--------------------------------------------------------------------------------
1 | self.addEventListener('fetch', () => {
2 | // literally does nothing
3 | });
4 |
5 | console.info('SW for test running');
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pwacompat",
3 | "version": "2.0.17",
4 | "description": "library to bring Web App Manifest contents to non-compliant browsers",
5 | "main": "pwacompat.min.js",
6 | "module": "src/pwacompat.js",
7 | "jsnext:main": "src/pwacompat.js",
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/GoogleChrome/pwacompat.git"
11 | },
12 | "keywords": [
13 | "pwa",
14 | "compatibility",
15 | "ios",
16 | "homescreen",
17 | "manifest"
18 | ],
19 | "author": "The Chromium Authors",
20 | "license": "Apache-2.0",
21 | "bugs": {
22 | "url": "https://github.com/GoogleChrome/pwacompat/issues"
23 | },
24 | "homepage": "https://github.com/GoogleChrome/pwacompat",
25 | "scripts": {
26 | "test": "headless-test src/test.js"
27 | },
28 | "devDependencies": {
29 | "chai": "^4.1.2",
30 | "headless-test": "^1.0.2",
31 | "mocha": "^5.2.0"
32 | },
33 | "resolutions": {
34 | "**/minimist": "^1.2.5"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/pwacompat.min.js:
--------------------------------------------------------------------------------
1 | (function(){function B(a){try{return document.head.querySelector(a)}catch(b){return null}}function v(a,b){a="__pwacompat_"+a;void 0!==b&&(w[a]=b);return w[a]}function F(){var a=(x=B('link[rel="manifest"]'))?x.href:"";if(!a)throw'can\'t find \'';var b=Q([a,location]),d=v("manifest");if(d)try{var g=JSON.parse(d);G(g,b)}catch(r){console.warn("PWACompat error",r)}else{var n=new XMLHttpRequest;n.open("GET",a);n.withCredentials="use-credentials"===x.getAttribute("crossorigin");
2 | n.onload=function(){try{var r=JSON.parse(n.responseText);v("manifest",n.responseText);G(r,b)}catch(t){console.warn("PWACompat error",t)}};n.send(null)}}function Q(a){for(var b={},d=0;d.6*f)l.fillText(H,I/-2,0),l.translate(0,1.2*m),e.splice(0,
5 | c),c=0}return function(){var J=l.canvas.toDataURL();g(h,J);return J}}function g(f,c){var h=document.createElement("link");h.setAttribute("rel","apple-touch-startup-image");h.setAttribute("media","(orientation: "+f+")");h.setAttribute("href",c);document.head.appendChild(h)}function n(f,c){var h=window.screen,m=d(h.width,h.height,"portrait",f),e=d(h.height,h.width,"landscape",f);setTimeout(function(){u.p=m();setTimeout(function(){u.l=e();c()},10)},10)}function r(f){function c(){--h||f()}var h=z.length+
6 | 1;c();z.forEach(function(m){var e=new Image;e.crossOrigin="anonymous";e.onerror=c;e.onload=function(){e.onload=null;m.href=K(e,y,!0);u.i[e.src]=m.href;c()};e.src=m.href})}function t(){v("iOS",JSON.stringify(u))}function L(){var f=z.shift();if(f){var c=new Image;c.crossOrigin="anonymous";c.onerror=function(){return void L()};c.onload=function(){c.onload=null;n(c,function(){var h=a.background_color&&K(c,y);h?(f.href=h,u.i[c.src]=h,r(t)):t()})};c.src=f.href}else n(null,t)}var p=(a.icons||[]).map(R).sort(function(f,
7 | c){return c.h-f.h}),q=p.filter(function(f){return-1f.h))return c.rel="apple-touch-icon",C("link",c,'[rel="apple-touch-icon"]'+h)}).filter(Boolean);p=B('meta[name="viewport"]');var T=!!(p&&p.content||"").match(/\bviewport-fit\s*=\s*cover\b/),M=a.display;p=-1!==U.indexOf(M);
8 | k("mobile-web-app-capable",p);V(a.theme_color||"black",T);W&&(k("application-name",a.short_name),k("msapplication-tooltip",a.description),k("msapplication-starturl",b(a.start_url||".")),k("msapplication-navbutton-color",a.theme_color),(q=q[0])&&k("msapplication-TileImage",b(q.src)),k("msapplication-TileColor",a.background_color));k("theme-color",a.theme_color);if(A){var y=a.background_color||"#f8f9fa",S=N(y);(q=X(a.related_applications))&&k("apple-itunes-app","app-id="+q);k("apple-mobile-web-app-capable",
9 | p);k("apple-mobile-web-app-title",a.short_name||a.name);if(q=v("iOS"))try{var E=JSON.parse(q);g("portrait",E.p);g("landscape",E.l);z.forEach(function(f){var c=E.i[f.href];c&&(f.href=c)});return}catch(f){}var u={i:{}};L()}else q={por:"portrait",lan:"landscape"}[String(a.orientation||"").substr(0,3)]||"",k("x5-orientation",q),k("screen-orientation",q),"fullscreen"===M?(k("x5-fullscreen","true"),k("full-screen","yes")):p&&(k("x5-page-mode","app"),k("browsermode","application"))}function X(a){var b;(a||
10 | []).filter(function(d){return"itunes"===d.platform}).forEach(function(d){d.id?b=d.id:(d=d.url.match(/id(\d+)/))&&(b=d[1])});return b}function V(a,b){if(A||Y){var d=N(a);if(A)k("apple-mobile-web-app-status-bar-style",b?"black-translucent":d?"black":"default");else{a:{try{var g=Windows.UI.ViewManagement.ApplicationView.getForCurrentView().titleBar;break a}catch(n){}g=void 0}if(b=g)d=d?255:0,b.foregroundColor={r:d,g:d,b:d,a:255},a=O(a),b.backgroundColor={r:a[0],g:a[1],b:a[2],a:a[3]}}}}function O(a){var b=
11 | D();b.fillStyle=a;b.fillRect(0,0,1,1);return b.getImageData(0,0,1,1).data||[]}function N(a){a=O(a).map(function(b){b/=255;return.03928>b?b/12.92:Math.pow((b+.055)/1.055,2.4)});return 3 '`;
94 | }
95 |
96 | const hrefFactory = buildHrefFactory([manifestHref, location]);
97 | const storedResponse = store('manifest');
98 | if (storedResponse) {
99 | try {
100 | const data = /** @type {!Object} */ (JSON.parse(storedResponse));
101 | process(data, hrefFactory);
102 | } catch (err) {
103 | console.warn('PWACompat error', err);
104 | }
105 | return;
106 | }
107 |
108 | const xhr = new XMLHttpRequest();
109 | xhr.open('GET', manifestHref);
110 |
111 | // nb. use getAttribute for older brower safety
112 | xhr.withCredentials = (manifestEl.getAttribute('crossorigin') === 'use-credentials');
113 |
114 | // this is IE10+
115 | xhr.onload = () => {
116 | try {
117 | const data = /** @type {!Object} */ (JSON.parse(xhr.responseText));
118 | store('manifest', xhr.responseText);
119 | process(data, hrefFactory);
120 | } catch (err) {
121 | console.warn('PWACompat error', err);
122 | }
123 | };
124 | xhr.send(null);
125 | }
126 |
127 | /**
128 | * @param {!Array} options
129 | * @return {function(string): string}
130 | */
131 | function buildHrefFactory(options) {
132 | for (let i = 0; i < options.length; ++i) {
133 | const opt = options[i];
134 | try {
135 | new URL('', opt);
136 | return (part) => (new URL(part || '', opt)).toString();
137 | } catch (e) {}
138 | }
139 | return (part) => part || '';
140 | }
141 |
142 | /**
143 | * Adds an element in the if it's not present already based on the passed check.
144 | * @param {string} localName tag name
145 | * @param {!Object} attr key-value collection of attributes
146 | * @param {string} check to apply to the tag
147 | */
148 | function push(localName, attr, check) {
149 | if (getElementInHead(localName + check)) {
150 | return;
151 | }
152 | const node = document.createElement(localName);
153 | for (const k in attr) {
154 | node.setAttribute(k, attr[k]);
155 | }
156 | document.head.appendChild(node);
157 | return node;
158 | }
159 |
160 | function meta(name, content) {
161 | if (content) {
162 | if (content === true) {
163 | content = 'yes';
164 | }
165 | push('meta', {name, content}, `[name="${name}"]`);
166 | }
167 | }
168 |
169 | /**
170 | * Pre-process the icon sizes and purpose into a tuple and array.
171 | */
172 | function normalizeIcon(icon) {
173 | const parsedSizes = icon.sizes.split(/\s+/g).map((size) => {
174 | if (size === 'any') {
175 | return Infinity;
176 | }
177 | return parseInt(size, 10) || 0; // NaN is falsey
178 | });
179 |
180 | return {
181 | src: icon.src,
182 | type: icon.type,
183 | sizes: icon.sizes,
184 | // Get the largest size from a processed icon.
185 | largestSize: Math.max.apply(null, parsedSizes),
186 | purpose: icon.purpose ? icon.purpose.split(/\s+/g) : ['any'],
187 | };
188 | }
189 |
190 | /**
191 | * @param {!Object} manifest
192 | * @param {function(string): string} urlFactory
193 | */
194 | function process(manifest, urlFactory) {
195 | // largest first
196 | const allIcons = (manifest['icons'] || [])
197 | .map(normalizeIcon)
198 | .sort((a, b) => b.largestSize - a.largestSize);
199 |
200 | const icons = allIcons.filter((icon) => icon.purpose.indexOf('any') > -1)
201 | const maskable = allIcons.filter((icon) => icon.purpose.indexOf('maskable') > -1);
202 |
203 | const appleTouchIcons = (maskable.length > 0 ? maskable : icons).map((icon) => {
204 | // create regular link icons as byproduct
205 | const attr = {'rel': 'icon', 'href': urlFactory(icon['src']), 'sizes': icon['sizes']};
206 | // This checks for matching "rel" and "sizes". We don't check for the same image file, as
207 | // it is used literally by ourselves (and could be set by users for another icon).
208 | const querySuffix = `[sizes="${icon['sizes']}"]`;
209 | push('link', attr, '[rel="icon"]' + querySuffix);
210 | if (!isSafariMobile) {
211 | return;
212 | }
213 | if (icon.largestSize < appleIconSizeMin) {
214 | return;
215 | }
216 | attr['rel'] = 'apple-touch-icon';
217 |
218 | // nb. we used to call `removeAttribute('sizes')` here, which crashed iOS 8
219 | // ... sizes has been supported since iOS 4.2 (!)
220 | return push('link', attr, '[rel="apple-touch-icon"]' + querySuffix);
221 | }).filter(Boolean);
222 |
223 | // nb. only for iOS, but watch for future CSS rule `@viewport { viewport-fit: cover; }`
224 | const metaViewport = getElementInHead('meta[name="viewport"]');
225 | const viewport = metaViewport && metaViewport.content || '';
226 | const viewportFitCover = Boolean(viewport.match(/\bviewport-fit\s*=\s*cover\b/));
227 |
228 | const display = manifest['display'];
229 | const isCapable = capableDisplayModes.indexOf(display) !== -1;
230 | meta('mobile-web-app-capable', isCapable);
231 | updateThemeColorRender(/** @type {string} */ (manifest['theme_color']) || 'black', viewportFitCover);
232 |
233 | if (isIEOrEdge) {
234 | // Pinned Sites, largely from https://technet.microsoft.com/en-us/windows/dn255024(v=vs.60)
235 | meta('application-name', manifest['short_name']);
236 | meta('msapplication-tooltip', manifest['description']);
237 | meta('msapplication-starturl', urlFactory(/** @type {string} */ (manifest['start_url']) || '.'));
238 | meta('msapplication-navbutton-color', manifest['theme_color']);
239 |
240 | const largest = icons[0];
241 | if (largest) {
242 | meta('msapplication-TileImage', urlFactory(largest['src']));
243 | }
244 | meta('msapplication-TileColor', manifest['background_color']);
245 | }
246 |
247 | meta('theme-color', manifest['theme_color']);
248 |
249 | if (!isSafariMobile) {
250 | // TODO(samthor): We don't detect QQ or UC, we just set the vars anyway.
251 | const orientation = simpleOrientationFor(manifest['orientation']);
252 | meta('x5-orientation', orientation); // QQ
253 | meta('screen-orientation', orientation); // UC
254 | if (display === 'fullscreen') {
255 | meta('x5-fullscreen', 'true'); // QQ
256 | meta('full-screen', 'yes'); // UC
257 | } else if (isCapable) {
258 | meta('x5-page-mode', 'app'); // QQ
259 | meta('browsermode', 'application'); // UC
260 | }
261 |
262 | return; // the rest of this file is for Mobile Safari
263 | }
264 |
265 | const backgroundColor =
266 | /** @type {string} */ (manifest['background_color']) || defaultSplashColor;
267 | const backgroundIsLight = shouldUseLightForeground(backgroundColor);
268 |
269 | // Add related iTunes app from manifest.
270 | const itunes = findAppleId(manifest['related_applications']);
271 | itunes && meta('apple-itunes-app', `app-id=${itunes}`);
272 |
273 | // General iOS meta tags.
274 | meta('apple-mobile-web-app-capable', isCapable);
275 | meta('apple-mobile-web-app-title', manifest['short_name'] || manifest['name']);
276 |
277 | /**
278 | * @param {number} width
279 | * @param {number} height
280 | * @param {string} orientation
281 | * @param {?Image} icon
282 | * @return {function(): string}
283 | */
284 | function splashFor(width, height, orientation, icon) {
285 | const ratio = window.devicePixelRatio;
286 | const ctx = contextForCanvas({width: width * ratio, height: height * ratio});
287 |
288 | ctx.scale(ratio, ratio);
289 | ctx.fillStyle = backgroundColor;
290 | ctx.fillRect(0, 0, width, height);
291 | ctx.translate(width / 2, (height - splashIconPadding) / 2);
292 |
293 | if (icon) {
294 | // nb: on Chrome, we need the image >=48px, use the big layout >=80dp, ideal is >=128dp
295 | let iconWidth = (icon.width / ratio);
296 | let iconHeight = (icon.height / ratio);
297 | if (iconHeight > idealSplashIconSize) {
298 | // clamp to 128px height max
299 | iconWidth /= (iconHeight / idealSplashIconSize);
300 | iconHeight = idealSplashIconSize;
301 | }
302 |
303 | if (iconWidth >= minimumSplashIconSize && iconHeight >= minimumSplashIconSize) {
304 | ctx.drawImage(icon, iconWidth / -2, iconHeight / -2, iconWidth, iconHeight);
305 | ctx.translate(0, iconHeight / 2 + splashIconPadding);
306 | }
307 | }
308 |
309 | ctx.fillStyle = backgroundIsLight ? 'white' : 'black';
310 | ctx.font = `${defaultSplashTextSize}px ${defaultFontName}`;
311 |
312 | // Set the user-requested font; if it's invalid, the set will fail.
313 | const s = getComputedStyle(manifestEl);
314 | ctx.font = s.getPropertyValue('--pwacompat-splash-font'); // blank for old browsers
315 |
316 | const title = manifest['name'] || manifest['short_name'] || document.title;
317 | const measure = ctx.measureText(title);
318 | const textHeight = (measure.actualBoundingBoxAscent || defaultSplashTextSize);
319 | ctx.translate(0, textHeight);
320 |
321 | if (measure.width < width * 0.8) {
322 | // short-circuit, just draw entire string
323 | ctx.fillText(title, measure.width / -2, 0);
324 | } else {
325 | // longer wrap case, draw once we have >0.7 width accumulated
326 | const words = title.split(/\s+/g);
327 | for (let i = 1; i <= words.length; ++i) {
328 | const cand = words.slice(0, i).join(' ');
329 | const measureWidth = ctx.measureText(cand).width;
330 | if (i === words.length || measureWidth > width * 0.6) {
331 | // render accumulated words
332 | ctx.fillText(cand, measureWidth / -2, 0);
333 | ctx.translate(0, textHeight * 1.2);
334 | words.splice(0, i);
335 | i = 0;
336 | }
337 | }
338 | }
339 |
340 | return () => {
341 | const data = ctx.canvas.toDataURL();
342 | if (debug) {
343 | const img = document.createElement('img');
344 | img.src = data;
345 | document.body.append(img);
346 | }
347 | appendSplash(orientation, data);
348 | return data;
349 | };
350 | }
351 |
352 | /**
353 | * @param {string} orientation
354 | * @param {string} data
355 | */
356 | function appendSplash(orientation, data) {
357 | const generatedSplash = /** @type {!HTMLLinkElement} */ (document.createElement('link'));
358 | generatedSplash.setAttribute('rel', 'apple-touch-startup-image');
359 | generatedSplash.setAttribute('media', `(orientation: ${orientation})`);
360 | generatedSplash.setAttribute('href', data);
361 | document.head.appendChild(generatedSplash);
362 | }
363 |
364 | // fetch previous (session) iOS image updates
365 | const rendered = store('iOS');
366 | if (!debug && rendered) {
367 | try {
368 | const prev = /** @type {!Object} */ (JSON.parse(rendered));
369 | appendSplash('portrait', prev['p']);
370 | appendSplash('landscape', prev['l']);
371 | appleTouchIcons.forEach((icon) => {
372 | const change = prev['i'][icon.href];
373 | if (change) {
374 | icon.href = change;
375 | }
376 | });
377 | return;
378 | } catch (e) {
379 | // ignore, some problem with the JSON
380 | }
381 | }
382 | const update = {'i': {}};
383 |
384 | /**
385 | * @param {?Image} applicationIcon
386 | * @param {function(): void} done
387 | */
388 | function renderBothSplash(applicationIcon, done) {
389 | const s = window.screen;
390 | const portrait = splashFor(s.width, s.height, 'portrait', applicationIcon);
391 | const landscape = splashFor(s.height, s.width, 'landscape', applicationIcon);
392 |
393 | // this is particularly egregious setTimeout use, but the .toDataURL() is one of the
394 | // "bottlenecks" of PWACompat, so don't elongate any single frame more than needed.
395 |
396 | setTimeout(() => {
397 | update['p'] = portrait();
398 | setTimeout(() => {
399 | update['l'] = landscape();
400 | done();
401 | }, 10);
402 | }, 10);
403 | }
404 |
405 | // fetches and redraws any remaining icons in appleTouchIcons (to have proper bg)
406 | function redrawRemainingIcons(done) {
407 | let left = appleTouchIcons.length + 1;
408 | const check = () => {
409 | if (!--left) {
410 | done();
411 | }
412 | };
413 | check();
414 | appleTouchIcons.forEach((icon) => {
415 | const img = new Image();
416 | img.crossOrigin = 'anonymous';
417 | img.onerror = check;
418 | img.onload = () => {
419 | img.onload = null;
420 | icon.href = updateTransparent(img, backgroundColor, true);
421 | update['i'][img.src] = icon.href;
422 | check();
423 | };
424 | img.src = icon.href;
425 | });
426 | }
427 |
428 | // write the update to sessionStorage
429 | function saveUpdate() {
430 | store('iOS', JSON.stringify(update));
431 | }
432 |
433 | // called repeatedly until a valid icon is found
434 | function fetchIconAndBuildSplash() {
435 | const icon = appleTouchIcons.shift();
436 | if (!icon) {
437 | renderBothSplash(null, saveUpdate); // ran out of icons, render without one
438 | return;
439 | }
440 |
441 | const img = new Image();
442 | img.crossOrigin = 'anonymous';
443 | img.onerror = () => void fetchIconAndBuildSplash(); // try again
444 | img.onload = () => {
445 | img.onload = null; // iOS Safari might call this many times
446 | renderBothSplash(img, () => {
447 | // ... if the icon used for splash changed, redraw others too
448 | const redrawn = manifest['background_color'] && updateTransparent(img, backgroundColor);
449 | if (redrawn) {
450 | icon.href = redrawn;
451 | update['i'][img.src] = redrawn;
452 | redrawRemainingIcons(saveUpdate);
453 | } else {
454 | saveUpdate();
455 | }
456 | });
457 | };
458 |
459 | img.src = icon.href; // trigger load
460 | }
461 | fetchIconAndBuildSplash();
462 | }
463 |
464 | function findAppleId(related) {
465 | let itunes;
466 | (related || [])
467 | .filter((app) => app['platform'] === 'itunes')
468 | .forEach((app) => {
469 | if (app['id']) {
470 | itunes = app['id'];
471 | } else {
472 | const match = app['url'].match(/id(\d+)/);
473 | if (match) {
474 | itunes = match[1];
475 | }
476 | }
477 | });
478 | return itunes;
479 | }
480 |
481 | function simpleOrientationFor(v) {
482 | const prefix = String(v || '').substr(0, 3);
483 | return {'por': 'portrait', 'lan': 'landscape'}[prefix] || '';
484 | }
485 |
486 | /**
487 | * @param {string} color
488 | * @param {boolean} viewportFitCover
489 | */
490 | function updateThemeColorRender(color, viewportFitCover) {
491 | if (!(isSafariMobile || isEdgePWA)) {
492 | return;
493 | }
494 |
495 | const themeIsLight = shouldUseLightForeground(color);
496 | if (isSafariMobile) {
497 | // nb. Safari 11.3+ gives a deprecation warning about this meta tag.
498 | const content = viewportFitCover ? 'black-translucent' : (themeIsLight ? 'black' : 'default');
499 | meta('apple-mobile-web-app-status-bar-style', content);
500 | } else {
501 | // Edge PWA
502 | const t = getEdgeTitleBar();
503 | if (!t) {
504 | return; // something went wrong, we had a UWP without titleBar
505 | }
506 | // Foreground is black if theme is light, otherwise white.
507 | const v = themeIsLight ? 255 : 0;
508 | t.foregroundColor = /** @type {WindowsColor} */ ({'r': v, 'g': v, 'b': v, 'a': 255});
509 | t.backgroundColor = colorToWindowsRGBA(color);
510 | }
511 | }
512 |
513 | /**
514 | * @return {!ApplicationViewTitleBar|undefined}
515 | */
516 | function getEdgeTitleBar() {
517 | try {
518 | return Windows.UI.ViewManagement.ApplicationView.getForCurrentView().titleBar;
519 | } catch (e) {
520 | // implicit return undefined
521 | }
522 | }
523 |
524 | /**
525 | * The Windows titlebar APIs expect an object of {r, g, b, a}.
526 | *
527 | * @param {string} color
528 | * @return {WindowsColor}
529 | */
530 | function colorToWindowsRGBA(color) {
531 | const data = readColor(color);
532 | return /** @type {WindowsColor} */ ({
533 | 'r': data[0],
534 | 'g': data[1],
535 | 'b': data[2],
536 | 'a': data[3],
537 | });
538 | }
539 |
540 | /**
541 | * @param {string} color
542 | * @return {!Uint8ClampedArray}
543 | */
544 | function readColor(color) {
545 | const c = contextForCanvas();
546 | c.fillStyle = color;
547 | c.fillRect(0, 0, 1, 1);
548 | return c.getImageData(0, 0, 1, 1).data || []; // incase this fails for some reason
549 | }
550 |
551 | /**
552 | * @param {string} color
553 | * @return {boolean}
554 | */
555 | function shouldUseLightForeground(color) {
556 | const pixelData = readColor(color);
557 |
558 | // From https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
559 | const data = pixelData.map((v) => {
560 | const f = v / 255;
561 | return (f < 0.03928) ? f / 12.92 : Math.pow((f + 0.055) / 1.055, 2.4);
562 | });
563 | const lum = 0.2126 * data[0] + 0.7152 * data[1] + 0.0722 * data[2];
564 | const contrast = Math.abs((1.05) / (lum + 0.05));
565 | return contrast > 3;
566 | }
567 |
568 | function updateTransparent(image, background, force=false) {
569 | const context = contextForCanvas(image);
570 | context.drawImage(image, 0, 0);
571 |
572 | // look for transparent pixel in top-left
573 | // TODO: Chrome actually checks the four corners for some cases.
574 | if (!force) {
575 | const imageData = context.getImageData(0, 0, 1, 1);
576 | if (imageData.data[3] === 255) {
577 | return;
578 | }
579 | }
580 |
581 | context.globalCompositeOperation = 'destination-over'; // only replace transparent areas
582 | context.fillStyle = background;
583 | context.fillRect(0, 0, image.width, image.height);
584 | return context.canvas.toDataURL();
585 | }
586 |
587 | function contextForCanvas({width, height} = {width: 1, height: 1}) {
588 | const canvas = document.createElement('canvas');
589 | canvas.width = width;
590 | canvas.height = height;
591 | return canvas.getContext('2d');
592 | }
593 |
594 | // actually run PWACompat here
595 | if (document.readyState === 'complete') {
596 | setup();
597 | } else {
598 | window.addEventListener('load', setup);
599 | }
600 | }());
601 |
--------------------------------------------------------------------------------
/src/test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | const assert = self.assert;
18 |
19 | const sources = new WeakMap();
20 | window.addEventListener('message', (ev) => {
21 | const resolve = sources.get(ev.source);
22 | if (!resolve) {
23 | throw new TypeError('unexpected source');
24 | }
25 | resolve(ev.data);
26 | });
27 |
28 | /**
29 | * @param {!Object} options.manifest
30 | * @param {!Object} options.override
31 | * @param {string} options.head
32 | * @param {number} options.delay
33 | * @return {!Promise}
34 | */
35 | function testManifest(options) {
36 | options = Object.assign({
37 | manifest: {},
38 | head: '',
39 | override: {},
40 | delay: 25,
41 | }, options);
42 |
43 | const rigsource = `
44 |
45 |
46 |
47 |
48 | ${options.head}
49 |
50 |
51 |
78 |
79 |
80 |
81 | `;
82 |
83 | const iframe = document.createElement('iframe');
84 | iframe.hidden = true;
85 | iframe.src = `data:text/html;base64,${btoa(rigsource)}`;
86 | iframe.sandbox = 'allow-scripts';
87 | document.body.appendChild(iframe);
88 |
89 | const p = new Promise((resolve, reject) => {
90 | sources.set(iframe.contentWindow, resolve);
91 | window.setTimeout(reject, 500);
92 | });
93 |
94 | const cleanup = () => iframe.remove();
95 | p.then(cleanup, cleanup);
96 |
97 | return p.then((all) => {
98 | // rehydrate DOM
99 | const frag = document.createDocumentFragment();
100 | all.forEach(({name, attr}) => {
101 | const node = document.createElement(name);
102 | for (const n in attr) {
103 | node.setAttribute(n, attr[n]);
104 | }
105 | frag.appendChild(node);
106 | });
107 | return frag;
108 | });
109 | }
110 |
111 | suite('pwacompat', () => {
112 | test('theme_color', async () => {
113 | const manifest = {
114 | 'theme_color': 'red',
115 | };
116 | let r = await testManifest({manifest});
117 | assert.isNotNull(r.querySelector('meta[name="theme-color"][content="red"]'));
118 |
119 | r = await testManifest({manifest, head: ' '});
120 | assert.isNotNull(r.querySelector('meta[name="theme-color"][content="blue"]'));
121 | assert.isNull(r.querySelector('meta[name="theme-color"][content="red"]'),
122 | 'red should not be created');
123 | });
124 |
125 | test('icons', async () => {
126 | const manifest = {
127 | 'icons': [
128 | {'src': 'logo-192.png', 'sizes': '192x192'},
129 | {'src': 'logo-128.png', 'sizes': '128x128'},
130 | ],
131 | };
132 | const r = await testManifest({manifest});
133 | assert.isNotNull(r.querySelector('link[rel="icon"][href="logo-128.png"][sizes="128x128"]'));
134 | });
135 |
136 | test('should add meta `mobile-web-app-capable`', async () => {
137 | const manifest = {
138 | display: 'standalone',
139 | };
140 | const r = await testManifest({manifest});
141 | assert.isNotNull(r.querySelector('meta[name="mobile-web-app-capable"][content="yes"]'));
142 | });
143 |
144 | test('should not add meta `mobile-web-app-capable` if it was present beforehand', async () => {
145 | const manifest = {
146 | display: 'standalone', // pwacompat should add 'meta[name="mobile-web-app-capable"][content="yes"]'
147 | };
148 | const r = await testManifest({manifest, head: ' '});
149 | assert.isNotNull(r.querySelector('meta[name="mobile-web-app-capable"][content="existing"]'));
150 | assert.isNull(r.querySelector('meta[name="mobile-web-app-capable"][content="yes"]'));
151 | assert.lengthOf(r.querySelectorAll('meta[name="mobile-web-app-capable"]'), 1, 'found only one node');
152 | });
153 |
154 | test('should not add link icon if it was present beforehand', async () => {
155 | const manifest = {
156 | 'icons': [
157 | {
158 | 'src': 'NEW-192.png',
159 | 'sizes': '192x192',
160 | },
161 | ],
162 | };
163 | const r = await testManifest({manifest, head: ' '});
164 | assert.isNotNull(r.querySelector('link[rel="icon"][href="EXISTING-192.png"][sizes="192x192"]'));
165 | assert.isNull(r.querySelector('link[rel="icon"][href="NEW-192.png"][sizes="192x192"]'));
166 | });
167 |
168 | test('iOS splash', async () => {
169 | const manifest = {
170 | 'short_name': 'Test',
171 | 'icons': [
172 | {
173 | 'src': window.location.origin + '/demo/logo-192.png',
174 | 'sizes': '192x192',
175 | },
176 | ],
177 | 'background_color': 'red',
178 | 'display': 'standalone',
179 | };
180 |
181 | const override = {
182 | vendor: 'Apple',
183 | userAgent: 'Mobile/',
184 | standalone: false,
185 | };
186 |
187 | const r = await testManifest({manifest, override, delay: 100});
188 |
189 | assert.isNotNull(r.querySelector('meta[name="apple-mobile-web-app-title"]'), 'should have title');
190 | assert.isNotNull(r.querySelector('meta[name="apple-mobile-web-app-capable"]'), 'should be capable');
191 |
192 | const images = r.querySelectorAll('link[rel="apple-touch-startup-image"]');
193 | assert.lengthOf(images, 2);
194 |
195 | const [portrait, landscape] = images;
196 | assert.strictEqual(portrait.media, '(orientation: portrait)');
197 | assert.strictEqual(landscape.media, '(orientation: landscape)');
198 |
199 | assert.notEqual(portrait.href, landscape.href);
200 |
201 | const portraitImage = new Image();
202 | portraitImage.src = portrait.href;
203 |
204 | const landscapeImage = new Image();
205 | landscapeImage.src = landscape.href;
206 |
207 | await Promise.resolve(); // wait for images to be ready
208 |
209 | assert.notStrictEqual(portraitImage.naturalWidth, 0);
210 | assert.strictEqual(portraitImage.naturalWidth, landscapeImage.naturalHeight);
211 | assert.strictEqual(portraitImage.naturalHeight, landscapeImage.naturalWidth);
212 |
213 | assert.strictEqual(portraitImage.naturalWidth, window.screen.width * window.devicePixelRatio);
214 | assert.strictEqual(landscapeImage.naturalHeight, window.screen.width * window.devicePixelRatio);
215 |
216 | const canvas = document.createElement('canvas');
217 | canvas.width = 1;
218 | canvas.height = 1;
219 | const context = canvas.getContext('2d');
220 |
221 | context.drawImage(portraitImage, 0, 0);
222 | const pixel = context.getImageData(0, 0, 1, 1);
223 | assert.deepStrictEqual(pixel.data, new Uint8ClampedArray([255, 0, 0, 255]), 'background should be red');
224 | });
225 |
226 | test('skip for installed iOS', async () => {
227 | const manifest = {
228 | 'short_name': 'Test',
229 | 'icons': [
230 | {
231 | 'src': window.location.origin + '/demo/logo-192.png',
232 | 'sizes': '192x192',
233 | },
234 | ],
235 | 'display': 'standalone',
236 | };
237 |
238 | const override = {
239 | vendor: 'Apple',
240 | userAgent: 'Mobile/',
241 | standalone: true,
242 | };
243 |
244 | const r = await testManifest({manifest, override, delay: 100});
245 | const all = r.querySelectorAll('*');
246 | assert.lengthOf(all, 1, 'should only have manifest itself');
247 | assert.strictEqual(all[0].rel, 'manifest');
248 |
249 | // This basically confirms that nothing else is added and we bail out early.
250 | });
251 |
252 | // TODO(samthor): Test Edge and non-iOS environments with overrides.
253 | });
254 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/color-name@^1.1.1":
6 | version "1.1.1"
7 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
8 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
9 |
10 | "@types/mime-types@^2.1.0":
11 | version "2.1.0"
12 | resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73"
13 | integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=
14 |
15 | agent-base@5:
16 | version "5.1.1"
17 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
18 | integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
19 |
20 | ansi-colors@3.2.3:
21 | version "3.2.3"
22 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
23 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
24 |
25 | ansi-regex@^3.0.0:
26 | version "3.0.0"
27 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
28 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
29 |
30 | ansi-regex@^4.1.0:
31 | version "4.1.0"
32 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
33 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
34 |
35 | ansi-styles@^3.2.0, ansi-styles@^3.2.1:
36 | version "3.2.1"
37 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
38 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
39 | dependencies:
40 | color-convert "^1.9.0"
41 |
42 | ansi-styles@^4.1.0:
43 | version "4.2.1"
44 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
45 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
46 | dependencies:
47 | "@types/color-name" "^1.1.1"
48 | color-convert "^2.0.1"
49 |
50 | anymatch@~3.1.1:
51 | version "3.1.1"
52 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
53 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
54 | dependencies:
55 | normalize-path "^3.0.0"
56 | picomatch "^2.0.4"
57 |
58 | arch@^2.1.0:
59 | version "2.1.1"
60 | resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e"
61 | integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==
62 |
63 | argparse@^1.0.7:
64 | version "1.0.10"
65 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
66 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
67 | dependencies:
68 | sprintf-js "~1.0.2"
69 |
70 | assertion-error@^1.0.1, assertion-error@^1.1.0:
71 | version "1.1.0"
72 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
73 |
74 | async-limiter@~1.0.0:
75 | version "1.0.1"
76 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
77 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
78 |
79 | balanced-match@^1.0.0:
80 | version "1.0.0"
81 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
82 |
83 | binary-extensions@^2.0.0:
84 | version "2.0.0"
85 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
86 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
87 |
88 | brace-expansion@^1.1.7:
89 | version "1.1.11"
90 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
91 | dependencies:
92 | balanced-match "^1.0.0"
93 | concat-map "0.0.1"
94 |
95 | braces@~3.0.2:
96 | version "3.0.2"
97 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
98 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
99 | dependencies:
100 | fill-range "^7.0.1"
101 |
102 | browser-stdout@1.3.1:
103 | version "1.3.1"
104 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
105 |
106 | buffer-crc32@~0.2.3:
107 | version "0.2.13"
108 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
109 | integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
110 |
111 | buffer-from@^1.0.0:
112 | version "1.1.1"
113 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
114 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
115 |
116 | bytes@^3.1.0:
117 | version "3.1.0"
118 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
119 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
120 |
121 | camelcase@^5.0.0:
122 | version "5.3.1"
123 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
124 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
125 |
126 | chai@^4:
127 | version "4.2.0"
128 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
129 | integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
130 | dependencies:
131 | assertion-error "^1.1.0"
132 | check-error "^1.0.2"
133 | deep-eql "^3.0.1"
134 | get-func-name "^2.0.0"
135 | pathval "^1.1.0"
136 | type-detect "^4.0.5"
137 |
138 | chai@^4.1.2:
139 | version "4.1.2"
140 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
141 | dependencies:
142 | assertion-error "^1.0.1"
143 | check-error "^1.0.1"
144 | deep-eql "^3.0.0"
145 | get-func-name "^2.0.0"
146 | pathval "^1.0.0"
147 | type-detect "^4.0.0"
148 |
149 | chalk@^2.4.2:
150 | version "2.4.2"
151 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
152 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
153 | dependencies:
154 | ansi-styles "^3.2.1"
155 | escape-string-regexp "^1.0.5"
156 | supports-color "^5.3.0"
157 |
158 | chalk@^3.0.0:
159 | version "3.0.0"
160 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
161 | integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
162 | dependencies:
163 | ansi-styles "^4.1.0"
164 | supports-color "^7.1.0"
165 |
166 | check-error@^1.0.1, check-error@^1.0.2:
167 | version "1.0.2"
168 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
169 |
170 | chokidar@3.3.0:
171 | version "3.3.0"
172 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6"
173 | integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==
174 | dependencies:
175 | anymatch "~3.1.1"
176 | braces "~3.0.2"
177 | glob-parent "~5.1.0"
178 | is-binary-path "~2.1.0"
179 | is-glob "~4.0.1"
180 | normalize-path "~3.0.0"
181 | readdirp "~3.2.0"
182 | optionalDependencies:
183 | fsevents "~2.1.1"
184 |
185 | clipboardy@^1.2.3:
186 | version "1.2.3"
187 | resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
188 | integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==
189 | dependencies:
190 | arch "^2.1.0"
191 | execa "^0.8.0"
192 |
193 | cliui@^5.0.0:
194 | version "5.0.0"
195 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
196 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
197 | dependencies:
198 | string-width "^3.1.0"
199 | strip-ansi "^5.2.0"
200 | wrap-ansi "^5.1.0"
201 |
202 | color-convert@^1.9.0:
203 | version "1.9.3"
204 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
205 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
206 | dependencies:
207 | color-name "1.1.3"
208 |
209 | color-convert@^2.0.1:
210 | version "2.0.1"
211 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
212 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
213 | dependencies:
214 | color-name "~1.1.4"
215 |
216 | color-name@1.1.3:
217 | version "1.1.3"
218 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
219 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
220 |
221 | color-name@~1.1.4:
222 | version "1.1.4"
223 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
224 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
225 |
226 | commander@2.15.1:
227 | version "2.15.1"
228 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
229 |
230 | concat-map@0.0.1:
231 | version "0.0.1"
232 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
233 |
234 | concat-stream@^1.6.2:
235 | version "1.6.2"
236 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
237 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
238 | dependencies:
239 | buffer-from "^1.0.0"
240 | inherits "^2.0.3"
241 | readable-stream "^2.2.2"
242 | typedarray "^0.0.6"
243 |
244 | core-util-is@~1.0.0:
245 | version "1.0.2"
246 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
247 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
248 |
249 | cross-spawn@^5.0.1:
250 | version "5.1.0"
251 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
252 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
253 | dependencies:
254 | lru-cache "^4.0.1"
255 | shebang-command "^1.2.0"
256 | which "^1.2.9"
257 |
258 | debug@3.1.0:
259 | version "3.1.0"
260 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
261 | dependencies:
262 | ms "2.0.0"
263 |
264 | debug@3.2.6:
265 | version "3.2.6"
266 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
267 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
268 | dependencies:
269 | ms "^2.1.1"
270 |
271 | debug@4, debug@^4.1.0:
272 | version "4.1.1"
273 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
274 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
275 | dependencies:
276 | ms "^2.1.1"
277 |
278 | debug@^2.6.9:
279 | version "2.6.9"
280 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
281 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
282 | dependencies:
283 | ms "2.0.0"
284 |
285 | decamelize@^1.2.0:
286 | version "1.2.0"
287 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
288 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
289 |
290 | deep-eql@^3.0.0, deep-eql@^3.0.1:
291 | version "3.0.1"
292 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
293 | dependencies:
294 | type-detect "^4.0.0"
295 |
296 | define-properties@^1.1.2, define-properties@^1.1.3:
297 | version "1.1.3"
298 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
299 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
300 | dependencies:
301 | object-keys "^1.0.12"
302 |
303 | dhost@^0.1.9:
304 | version "0.1.9"
305 | resolved "https://registry.yarnpkg.com/dhost/-/dhost-0.1.9.tgz#1421803a088a79b6a45ba63a5be51cf9d998cfa9"
306 | integrity sha512-/MYMqdeIst8n5h6/nUwGu1WqwU5zwQAIP9W9X2u2NjKqPIx0fBFdoCm+4BeQ5hSt8zdJMX2JJUqnHyM/+hXrHQ==
307 | dependencies:
308 | bytes "^3.1.0"
309 | chalk "^2.4.2"
310 | clipboardy "^1.2.3"
311 | he "^1.2.0"
312 | mime "^2.4.0"
313 | mri "^1.1.4"
314 |
315 | diff@3.5.0:
316 | version "3.5.0"
317 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
318 |
319 | emoji-regex@^7.0.1:
320 | version "7.0.3"
321 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
322 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
323 |
324 | es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
325 | version "1.17.5"
326 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9"
327 | integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==
328 | dependencies:
329 | es-to-primitive "^1.2.1"
330 | function-bind "^1.1.1"
331 | has "^1.0.3"
332 | has-symbols "^1.0.1"
333 | is-callable "^1.1.5"
334 | is-regex "^1.0.5"
335 | object-inspect "^1.7.0"
336 | object-keys "^1.1.1"
337 | object.assign "^4.1.0"
338 | string.prototype.trimleft "^2.1.1"
339 | string.prototype.trimright "^2.1.1"
340 |
341 | es-to-primitive@^1.2.1:
342 | version "1.2.1"
343 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
344 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
345 | dependencies:
346 | is-callable "^1.1.4"
347 | is-date-object "^1.0.1"
348 | is-symbol "^1.0.2"
349 |
350 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
351 | version "1.0.5"
352 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
353 |
354 | esprima@^4.0.0:
355 | version "4.0.1"
356 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
357 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
358 |
359 | execa@^0.8.0:
360 | version "0.8.0"
361 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
362 | integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=
363 | dependencies:
364 | cross-spawn "^5.0.1"
365 | get-stream "^3.0.0"
366 | is-stream "^1.1.0"
367 | npm-run-path "^2.0.0"
368 | p-finally "^1.0.0"
369 | signal-exit "^3.0.0"
370 | strip-eof "^1.0.0"
371 |
372 | extract-zip@^1.6.6:
373 | version "1.7.0"
374 | resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
375 | integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
376 | dependencies:
377 | concat-stream "^1.6.2"
378 | debug "^2.6.9"
379 | mkdirp "^0.5.4"
380 | yauzl "^2.10.0"
381 |
382 | fd-slicer@~1.1.0:
383 | version "1.1.0"
384 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
385 | integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
386 | dependencies:
387 | pend "~1.2.0"
388 |
389 | fill-range@^7.0.1:
390 | version "7.0.1"
391 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
392 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
393 | dependencies:
394 | to-regex-range "^5.0.1"
395 |
396 | find-up@3.0.0, find-up@^3.0.0:
397 | version "3.0.0"
398 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
399 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
400 | dependencies:
401 | locate-path "^3.0.0"
402 |
403 | flat@^4.1.0:
404 | version "4.1.0"
405 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
406 | integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
407 | dependencies:
408 | is-buffer "~2.0.3"
409 |
410 | fs.realpath@^1.0.0:
411 | version "1.0.0"
412 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
413 |
414 | fsevents@~2.1.1:
415 | version "2.1.3"
416 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
417 | integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
418 |
419 | function-bind@^1.1.1:
420 | version "1.1.1"
421 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
422 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
423 |
424 | get-caller-file@^2.0.1:
425 | version "2.0.5"
426 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
427 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
428 |
429 | get-func-name@^2.0.0:
430 | version "2.0.0"
431 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
432 |
433 | get-stream@^3.0.0:
434 | version "3.0.0"
435 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
436 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
437 |
438 | glob-parent@~5.1.0:
439 | version "5.1.1"
440 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
441 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
442 | dependencies:
443 | is-glob "^4.0.1"
444 |
445 | glob@7.1.2:
446 | version "7.1.2"
447 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
448 | dependencies:
449 | fs.realpath "^1.0.0"
450 | inflight "^1.0.4"
451 | inherits "2"
452 | minimatch "^3.0.4"
453 | once "^1.3.0"
454 | path-is-absolute "^1.0.0"
455 |
456 | glob@7.1.3:
457 | version "7.1.3"
458 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
459 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
460 | dependencies:
461 | fs.realpath "^1.0.0"
462 | inflight "^1.0.4"
463 | inherits "2"
464 | minimatch "^3.0.4"
465 | once "^1.3.0"
466 | path-is-absolute "^1.0.0"
467 |
468 | glob@^7.1.3:
469 | version "7.1.6"
470 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
471 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
472 | dependencies:
473 | fs.realpath "^1.0.0"
474 | inflight "^1.0.4"
475 | inherits "2"
476 | minimatch "^3.0.4"
477 | once "^1.3.0"
478 | path-is-absolute "^1.0.0"
479 |
480 | growl@1.10.5:
481 | version "1.10.5"
482 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
483 |
484 | has-flag@^3.0.0:
485 | version "3.0.0"
486 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
487 |
488 | has-flag@^4.0.0:
489 | version "4.0.0"
490 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
491 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
492 |
493 | has-symbols@^1.0.0, has-symbols@^1.0.1:
494 | version "1.0.1"
495 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
496 | integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
497 |
498 | has@^1.0.3:
499 | version "1.0.3"
500 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
501 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
502 | dependencies:
503 | function-bind "^1.1.1"
504 |
505 | he@1.1.1:
506 | version "1.1.1"
507 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
508 |
509 | he@1.2.0, he@^1.2.0:
510 | version "1.2.0"
511 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
512 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
513 |
514 | headless-test@^1.0.2:
515 | version "1.0.2"
516 | resolved "https://registry.yarnpkg.com/headless-test/-/headless-test-1.0.2.tgz#6237bf1d0300c026a8c088291364b75df34bf1ca"
517 | integrity sha512-4QbDxTYYnPXyzURvrHVFOWvUnVbDjYcxwbDzFAREGV4j3hFKsTzO1u/X04IOVIJue0lPdHSCTYiy7ze7kKNjPw==
518 | dependencies:
519 | chai "^4"
520 | chalk "^3.0.0"
521 | dhost "^0.1.9"
522 | mocha "^7"
523 | mri "^1"
524 | puppeteer "^2"
525 |
526 | https-proxy-agent@^4.0.0:
527 | version "4.0.0"
528 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
529 | integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
530 | dependencies:
531 | agent-base "5"
532 | debug "4"
533 |
534 | inflight@^1.0.4:
535 | version "1.0.6"
536 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
537 | dependencies:
538 | once "^1.3.0"
539 | wrappy "1"
540 |
541 | inherits@2:
542 | version "2.0.3"
543 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
544 |
545 | inherits@^2.0.3, inherits@~2.0.3:
546 | version "2.0.4"
547 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
548 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
549 |
550 | is-binary-path@~2.1.0:
551 | version "2.1.0"
552 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
553 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
554 | dependencies:
555 | binary-extensions "^2.0.0"
556 |
557 | is-buffer@~2.0.3:
558 | version "2.0.4"
559 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
560 | integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
561 |
562 | is-callable@^1.1.4, is-callable@^1.1.5:
563 | version "1.1.5"
564 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
565 | integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
566 |
567 | is-date-object@^1.0.1:
568 | version "1.0.2"
569 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
570 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
571 |
572 | is-extglob@^2.1.1:
573 | version "2.1.1"
574 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
575 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
576 |
577 | is-fullwidth-code-point@^2.0.0:
578 | version "2.0.0"
579 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
580 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
581 |
582 | is-glob@^4.0.1, is-glob@~4.0.1:
583 | version "4.0.1"
584 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
585 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
586 | dependencies:
587 | is-extglob "^2.1.1"
588 |
589 | is-number@^7.0.0:
590 | version "7.0.0"
591 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
592 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
593 |
594 | is-regex@^1.0.5:
595 | version "1.0.5"
596 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
597 | integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
598 | dependencies:
599 | has "^1.0.3"
600 |
601 | is-stream@^1.1.0:
602 | version "1.1.0"
603 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
604 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
605 |
606 | is-symbol@^1.0.2:
607 | version "1.0.3"
608 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
609 | integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
610 | dependencies:
611 | has-symbols "^1.0.1"
612 |
613 | isarray@~1.0.0:
614 | version "1.0.0"
615 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
616 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
617 |
618 | isexe@^2.0.0:
619 | version "2.0.0"
620 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
621 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
622 |
623 | js-yaml@3.13.1:
624 | version "3.13.1"
625 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
626 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
627 | dependencies:
628 | argparse "^1.0.7"
629 | esprima "^4.0.0"
630 |
631 | locate-path@^3.0.0:
632 | version "3.0.0"
633 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
634 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
635 | dependencies:
636 | p-locate "^3.0.0"
637 | path-exists "^3.0.0"
638 |
639 | lodash@^4.17.15:
640 | version "4.17.19"
641 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
642 | integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
643 |
644 | log-symbols@3.0.0:
645 | version "3.0.0"
646 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
647 | integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==
648 | dependencies:
649 | chalk "^2.4.2"
650 |
651 | lru-cache@^4.0.1:
652 | version "4.1.5"
653 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
654 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
655 | dependencies:
656 | pseudomap "^1.0.2"
657 | yallist "^2.1.2"
658 |
659 | mime-db@1.44.0:
660 | version "1.44.0"
661 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
662 | integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
663 |
664 | mime-types@^2.1.25:
665 | version "2.1.27"
666 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
667 | integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
668 | dependencies:
669 | mime-db "1.44.0"
670 |
671 | mime@^2.0.3, mime@^2.4.0:
672 | version "2.4.5"
673 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.5.tgz#d8de2ecb92982dedbb6541c9b6841d7f218ea009"
674 | integrity sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==
675 |
676 | minimatch@3.0.4, minimatch@^3.0.4:
677 | version "3.0.4"
678 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
679 | dependencies:
680 | brace-expansion "^1.1.7"
681 |
682 | minimist@0.0.8, minimist@^1.2.5:
683 | version "1.2.5"
684 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
685 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
686 |
687 | mkdirp@0.5.1:
688 | version "0.5.1"
689 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
690 | dependencies:
691 | minimist "0.0.8"
692 |
693 | mkdirp@0.5.5, mkdirp@^0.5.4:
694 | version "0.5.5"
695 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
696 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
697 | dependencies:
698 | minimist "^1.2.5"
699 |
700 | mocha@^5.2.0:
701 | version "5.2.0"
702 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
703 | dependencies:
704 | browser-stdout "1.3.1"
705 | commander "2.15.1"
706 | debug "3.1.0"
707 | diff "3.5.0"
708 | escape-string-regexp "1.0.5"
709 | glob "7.1.2"
710 | growl "1.10.5"
711 | he "1.1.1"
712 | minimatch "3.0.4"
713 | mkdirp "0.5.1"
714 | supports-color "5.4.0"
715 |
716 | mocha@^7:
717 | version "7.1.2"
718 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.2.tgz#8e40d198acf91a52ace122cd7599c9ab857b29e6"
719 | integrity sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==
720 | dependencies:
721 | ansi-colors "3.2.3"
722 | browser-stdout "1.3.1"
723 | chokidar "3.3.0"
724 | debug "3.2.6"
725 | diff "3.5.0"
726 | escape-string-regexp "1.0.5"
727 | find-up "3.0.0"
728 | glob "7.1.3"
729 | growl "1.10.5"
730 | he "1.2.0"
731 | js-yaml "3.13.1"
732 | log-symbols "3.0.0"
733 | minimatch "3.0.4"
734 | mkdirp "0.5.5"
735 | ms "2.1.1"
736 | node-environment-flags "1.0.6"
737 | object.assign "4.1.0"
738 | strip-json-comments "2.0.1"
739 | supports-color "6.0.0"
740 | which "1.3.1"
741 | wide-align "1.1.3"
742 | yargs "13.3.2"
743 | yargs-parser "13.1.2"
744 | yargs-unparser "1.6.0"
745 |
746 | mri@^1, mri@^1.1.4:
747 | version "1.1.5"
748 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.5.tgz#ce21dba2c69f74a9b7cf8a1ec62307e089e223e0"
749 | integrity sha512-d2RKzMD4JNyHMbnbWnznPaa8vbdlq/4pNZ3IgdaGrVbBhebBsGUUE/6qorTMYNS6TwuH3ilfOlD2bf4Igh8CKg==
750 |
751 | ms@2.0.0:
752 | version "2.0.0"
753 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
754 |
755 | ms@2.1.1:
756 | version "2.1.1"
757 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
758 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
759 |
760 | ms@^2.1.1:
761 | version "2.1.2"
762 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
763 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
764 |
765 | node-environment-flags@1.0.6:
766 | version "1.0.6"
767 | resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088"
768 | integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==
769 | dependencies:
770 | object.getownpropertydescriptors "^2.0.3"
771 | semver "^5.7.0"
772 |
773 | normalize-path@^3.0.0, normalize-path@~3.0.0:
774 | version "3.0.0"
775 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
776 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
777 |
778 | npm-run-path@^2.0.0:
779 | version "2.0.2"
780 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
781 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
782 | dependencies:
783 | path-key "^2.0.0"
784 |
785 | object-inspect@^1.7.0:
786 | version "1.7.0"
787 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
788 | integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
789 |
790 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
791 | version "1.1.1"
792 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
793 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
794 |
795 | object.assign@4.1.0, object.assign@^4.1.0:
796 | version "4.1.0"
797 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
798 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
799 | dependencies:
800 | define-properties "^1.1.2"
801 | function-bind "^1.1.1"
802 | has-symbols "^1.0.0"
803 | object-keys "^1.0.11"
804 |
805 | object.getownpropertydescriptors@^2.0.3:
806 | version "2.1.0"
807 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
808 | integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==
809 | dependencies:
810 | define-properties "^1.1.3"
811 | es-abstract "^1.17.0-next.1"
812 |
813 | once@^1.3.0:
814 | version "1.4.0"
815 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
816 | dependencies:
817 | wrappy "1"
818 |
819 | p-finally@^1.0.0:
820 | version "1.0.0"
821 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
822 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
823 |
824 | p-limit@^2.0.0:
825 | version "2.3.0"
826 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
827 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
828 | dependencies:
829 | p-try "^2.0.0"
830 |
831 | p-locate@^3.0.0:
832 | version "3.0.0"
833 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
834 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
835 | dependencies:
836 | p-limit "^2.0.0"
837 |
838 | p-try@^2.0.0:
839 | version "2.2.0"
840 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
841 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
842 |
843 | path-exists@^3.0.0:
844 | version "3.0.0"
845 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
846 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
847 |
848 | path-is-absolute@^1.0.0:
849 | version "1.0.1"
850 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
851 |
852 | path-key@^2.0.0:
853 | version "2.0.1"
854 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
855 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
856 |
857 | pathval@^1.0.0, pathval@^1.1.0:
858 | version "1.1.0"
859 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
860 |
861 | pend@~1.2.0:
862 | version "1.2.0"
863 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
864 | integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
865 |
866 | picomatch@^2.0.4:
867 | version "2.2.2"
868 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
869 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
870 |
871 | process-nextick-args@~2.0.0:
872 | version "2.0.1"
873 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
874 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
875 |
876 | progress@^2.0.1:
877 | version "2.0.3"
878 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
879 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
880 |
881 | proxy-from-env@^1.0.0:
882 | version "1.1.0"
883 | resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
884 | integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
885 |
886 | pseudomap@^1.0.2:
887 | version "1.0.2"
888 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
889 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
890 |
891 | puppeteer@^2:
892 | version "2.1.1"
893 | resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-2.1.1.tgz#ccde47c2a688f131883b50f2d697bd25189da27e"
894 | integrity sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==
895 | dependencies:
896 | "@types/mime-types" "^2.1.0"
897 | debug "^4.1.0"
898 | extract-zip "^1.6.6"
899 | https-proxy-agent "^4.0.0"
900 | mime "^2.0.3"
901 | mime-types "^2.1.25"
902 | progress "^2.0.1"
903 | proxy-from-env "^1.0.0"
904 | rimraf "^2.6.1"
905 | ws "^6.1.0"
906 |
907 | readable-stream@^2.2.2:
908 | version "2.3.7"
909 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
910 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
911 | dependencies:
912 | core-util-is "~1.0.0"
913 | inherits "~2.0.3"
914 | isarray "~1.0.0"
915 | process-nextick-args "~2.0.0"
916 | safe-buffer "~5.1.1"
917 | string_decoder "~1.1.1"
918 | util-deprecate "~1.0.1"
919 |
920 | readdirp@~3.2.0:
921 | version "3.2.0"
922 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839"
923 | integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==
924 | dependencies:
925 | picomatch "^2.0.4"
926 |
927 | require-directory@^2.1.1:
928 | version "2.1.1"
929 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
930 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
931 |
932 | require-main-filename@^2.0.0:
933 | version "2.0.0"
934 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
935 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
936 |
937 | rimraf@^2.6.1:
938 | version "2.7.1"
939 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
940 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
941 | dependencies:
942 | glob "^7.1.3"
943 |
944 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
945 | version "5.1.2"
946 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
947 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
948 |
949 | semver@^5.7.0:
950 | version "5.7.1"
951 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
952 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
953 |
954 | set-blocking@^2.0.0:
955 | version "2.0.0"
956 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
957 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
958 |
959 | shebang-command@^1.2.0:
960 | version "1.2.0"
961 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
962 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
963 | dependencies:
964 | shebang-regex "^1.0.0"
965 |
966 | shebang-regex@^1.0.0:
967 | version "1.0.0"
968 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
969 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
970 |
971 | signal-exit@^3.0.0:
972 | version "3.0.3"
973 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
974 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
975 |
976 | sprintf-js@~1.0.2:
977 | version "1.0.3"
978 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
979 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
980 |
981 | "string-width@^1.0.2 || 2":
982 | version "2.1.1"
983 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
984 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
985 | dependencies:
986 | is-fullwidth-code-point "^2.0.0"
987 | strip-ansi "^4.0.0"
988 |
989 | string-width@^3.0.0, string-width@^3.1.0:
990 | version "3.1.0"
991 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
992 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
993 | dependencies:
994 | emoji-regex "^7.0.1"
995 | is-fullwidth-code-point "^2.0.0"
996 | strip-ansi "^5.1.0"
997 |
998 | string.prototype.trimend@^1.0.0:
999 | version "1.0.1"
1000 | resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
1001 | integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
1002 | dependencies:
1003 | define-properties "^1.1.3"
1004 | es-abstract "^1.17.5"
1005 |
1006 | string.prototype.trimleft@^2.1.1:
1007 | version "2.1.2"
1008 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc"
1009 | integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==
1010 | dependencies:
1011 | define-properties "^1.1.3"
1012 | es-abstract "^1.17.5"
1013 | string.prototype.trimstart "^1.0.0"
1014 |
1015 | string.prototype.trimright@^2.1.1:
1016 | version "2.1.2"
1017 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3"
1018 | integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==
1019 | dependencies:
1020 | define-properties "^1.1.3"
1021 | es-abstract "^1.17.5"
1022 | string.prototype.trimend "^1.0.0"
1023 |
1024 | string.prototype.trimstart@^1.0.0:
1025 | version "1.0.1"
1026 | resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
1027 | integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
1028 | dependencies:
1029 | define-properties "^1.1.3"
1030 | es-abstract "^1.17.5"
1031 |
1032 | string_decoder@~1.1.1:
1033 | version "1.1.1"
1034 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
1035 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
1036 | dependencies:
1037 | safe-buffer "~5.1.0"
1038 |
1039 | strip-ansi@^4.0.0:
1040 | version "4.0.0"
1041 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
1042 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
1043 | dependencies:
1044 | ansi-regex "^3.0.0"
1045 |
1046 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
1047 | version "5.2.0"
1048 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
1049 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
1050 | dependencies:
1051 | ansi-regex "^4.1.0"
1052 |
1053 | strip-eof@^1.0.0:
1054 | version "1.0.0"
1055 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
1056 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
1057 |
1058 | strip-json-comments@2.0.1:
1059 | version "2.0.1"
1060 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
1061 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
1062 |
1063 | supports-color@5.4.0:
1064 | version "5.4.0"
1065 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
1066 | dependencies:
1067 | has-flag "^3.0.0"
1068 |
1069 | supports-color@6.0.0:
1070 | version "6.0.0"
1071 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
1072 | integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
1073 | dependencies:
1074 | has-flag "^3.0.0"
1075 |
1076 | supports-color@^5.3.0:
1077 | version "5.5.0"
1078 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1079 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1080 | dependencies:
1081 | has-flag "^3.0.0"
1082 |
1083 | supports-color@^7.1.0:
1084 | version "7.1.0"
1085 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
1086 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
1087 | dependencies:
1088 | has-flag "^4.0.0"
1089 |
1090 | to-regex-range@^5.0.1:
1091 | version "5.0.1"
1092 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1093 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1094 | dependencies:
1095 | is-number "^7.0.0"
1096 |
1097 | type-detect@^4.0.0, type-detect@^4.0.5:
1098 | version "4.0.8"
1099 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
1100 |
1101 | typedarray@^0.0.6:
1102 | version "0.0.6"
1103 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
1104 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
1105 |
1106 | util-deprecate@~1.0.1:
1107 | version "1.0.2"
1108 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1109 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1110 |
1111 | which-module@^2.0.0:
1112 | version "2.0.0"
1113 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
1114 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
1115 |
1116 | which@1.3.1, which@^1.2.9:
1117 | version "1.3.1"
1118 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1119 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1120 | dependencies:
1121 | isexe "^2.0.0"
1122 |
1123 | wide-align@1.1.3:
1124 | version "1.1.3"
1125 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
1126 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
1127 | dependencies:
1128 | string-width "^1.0.2 || 2"
1129 |
1130 | wrap-ansi@^5.1.0:
1131 | version "5.1.0"
1132 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
1133 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
1134 | dependencies:
1135 | ansi-styles "^3.2.0"
1136 | string-width "^3.0.0"
1137 | strip-ansi "^5.0.0"
1138 |
1139 | wrappy@1:
1140 | version "1.0.2"
1141 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1142 |
1143 | ws@^6.1.0:
1144 | version "6.2.1"
1145 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
1146 | integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
1147 | dependencies:
1148 | async-limiter "~1.0.0"
1149 |
1150 | y18n@^4.0.0:
1151 | version "4.0.0"
1152 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
1153 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
1154 |
1155 | yallist@^2.1.2:
1156 | version "2.1.2"
1157 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
1158 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
1159 |
1160 | yargs-parser@13.1.2, yargs-parser@^13.1.2:
1161 | version "13.1.2"
1162 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
1163 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
1164 | dependencies:
1165 | camelcase "^5.0.0"
1166 | decamelize "^1.2.0"
1167 |
1168 | yargs-unparser@1.6.0:
1169 | version "1.6.0"
1170 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
1171 | integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==
1172 | dependencies:
1173 | flat "^4.1.0"
1174 | lodash "^4.17.15"
1175 | yargs "^13.3.0"
1176 |
1177 | yargs@13.3.2, yargs@^13.3.0:
1178 | version "13.3.2"
1179 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
1180 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
1181 | dependencies:
1182 | cliui "^5.0.0"
1183 | find-up "^3.0.0"
1184 | get-caller-file "^2.0.1"
1185 | require-directory "^2.1.1"
1186 | require-main-filename "^2.0.0"
1187 | set-blocking "^2.0.0"
1188 | string-width "^3.0.0"
1189 | which-module "^2.0.0"
1190 | y18n "^4.0.0"
1191 | yargs-parser "^13.1.2"
1192 |
1193 | yauzl@^2.10.0:
1194 | version "2.10.0"
1195 | resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
1196 | integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
1197 | dependencies:
1198 | buffer-crc32 "~0.2.3"
1199 | fd-slicer "~1.1.0"
1200 |
--------------------------------------------------------------------------------