diff --git a/src/third_party/LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES b/src/third_party/LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES index 67318f8c4..4f596225e 100644 --- a/src/third_party/LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES +++ b/src/third_party/LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES @@ -1,18 +1,108 @@ -Name: ms +Name: @formatjs/fast-memoize +URL: https://github.com/formatjs/formatjs#readme +Version: 2.2.0 +License: MIT + +MIT License + +Copyright (c) 2021 FormatJS + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: @formatjs/icu-messageformat-parser +URL: https://github.com/formatjs/formatjs.git +Version: 2.6.2 +License: MIT + +MIT License + +Copyright (c) 2021 FormatJS + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: @formatjs/icu-skeleton-parser +URL: https://github.com/formatjs/formatjs.git +Version: 1.6.2 +License: MIT + +MIT License + +Copyright (c) 2021 FormatJS + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: @paulirish/trace_engine URL: N/A -Version: 2.1.2 +Version: 0.0.61 +License: BSD-3-Clause + +// Copyright 2014 The Chromium Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: @sentry/node +URL: https://github.com/getsentry/sentry-javascript/tree/master/packages/node +Version: 9.28.1 License: MIT -The MIT License (MIT) +MIT License -Copyright (c) 2016 Zeit, Inc. +Copyright (c) 2023 Functional Software, Inc. dba Sentry -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -28,428 +118,380 @@ SOFTWARE. -------------------- DEPENDENCY DIVIDER -------------------- -Name: debug -URL: git://github.com/debug-js/debug.git -Version: 4.3.4 -License: MIT +Name: axe-core +URL: https://www.deque.com/axe/ +Version: 4.11.0 +License: MPL-2.0 -(The MIT License) +Mozilla Public License, version 2.0 -Copyright (c) 2014-2017 TJ Holowaychuk -Copyright (c) 2018-2021 Josh Junon +1. Definitions -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the 'Software'), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +1.1. "Contributor" -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. +1.3. "Contribution" --------------------- DEPENDENCY DIVIDER -------------------- + means Covered Software of a particular Contributor. -Name: marky -URL: N/A -Version: 1.2.2 -License: Apache-2.0 +1.4. "Covered Software" -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1.5. "Incompatible With Secondary Licenses" + means -1. Definitions. + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or - "License" shall mean the terms and conditions for use, reproduction, and - distribution as defined by Sections 1 through 9 of this document. + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. - "Licensor" shall mean the copyright owner or entity authorized by the - copyright owner that is granting the License. +1.6. "Executable Form" - "Legal Entity" shall mean the union of the acting entity and all other - entities that control, are controlled by, or are under common control with - that entity. For the purposes of this definition, "control" means (i) the - power, direct or indirect, to cause the direction or management of such - entity, whether by contract or otherwise, or (ii) ownership of - fifty percent (50%) or more of the outstanding shares, or (iii) beneficial - ownership of such entity. + means any form of the work other than Source Code Form. - "You" (or "Your") shall mean an individual or Legal Entity exercising - permissions granted by this License. +1.7. "Larger Work" - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation source, - and configuration files. + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. - "Object" form shall mean any form resulting from mechanical transformation - or translation of a Source form, including but not limited to compiled - object code, generated documentation, and conversions to - other media types. +1.8. "License" - "Work" shall mean the work of authorship, whether in Source or Object - form, made available under the License, as indicated by a copyright notice - that is included in or attached to the work (an example is provided in the - Appendix below). + means this document. - "Derivative Works" shall mean any work, whether in Source or Object form, - that is based on (or derived from) the Work and for which the editorial - revisions, annotations, elaborations, or other modifications represent, - as a whole, an original work of authorship. For the purposes of this - License, Derivative Works shall not include works that remain separable - from, or merely link (or bind by name) to the interfaces of, the Work and - Derivative Works thereof. +1.9. "Licensable" - "Contribution" shall mean any work of authorship, including the original - version of the Work and any modifications or additions to that Work or - Derivative Works thereof, that is intentionally submitted to Licensor for - inclusion in the Work by the copyright owner or by an individual or - Legal Entity authorized to submit on behalf of the copyright owner. - For the purposes of this definition, "submitted" means any form of - electronic, verbal, or written communication sent to the Licensor or its - representatives, including but not limited to communication on electronic - mailing lists, source code control systems, and issue tracking systems - that are managed by, or on behalf of, the Licensor for the purpose of - discussing and improving the Work, but excluding communication that is - conspicuously marked or otherwise designated in writing by the copyright - owner as "Not a Contribution." + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. - "Contributor" shall mean Licensor and any individual or Legal Entity on - behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. +1.10. "Modifications" -2. Grant of Copyright License. + means any of the following: - Subject to the terms and conditions of this License, each Contributor - hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, - royalty-free, irrevocable copyright license to reproduce, prepare - Derivative Works of, publicly display, publicly perform, sublicense, - and distribute the Work and such Derivative Works in - Source or Object form. + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or -3. Grant of Patent License. + b. any new file in Source Code Form that contains any Covered Software. - Subject to the terms and conditions of this License, each Contributor - hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, - royalty-free, irrevocable (except as stated in this section) patent - license to make, have made, use, offer to sell, sell, import, and - otherwise transfer the Work, where such license applies only to those - patent claims licensable by such Contributor that are necessarily - infringed by their Contribution(s) alone or by combination of their - Contribution(s) with the Work to which such Contribution(s) was submitted. - If You institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work or a - Contribution incorporated within the Work constitutes direct or - contributory patent infringement, then any patent licenses granted to - You under this License for that Work shall terminate as of the date such - litigation is filed. +1.11. "Patent Claims" of a Contributor -4. Redistribution. + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. - You may reproduce and distribute copies of the Work or Derivative Works - thereof in any medium, with or without modifications, and in Source or - Object form, provided that You meet the following conditions: +1.12. "Secondary License" - 1. You must give any other recipients of the Work or Derivative Works a - copy of this License; and + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. - 2. You must cause any modified files to carry prominent notices stating - that You changed the files; and +1.13. "Source Code Form" - 3. You must retain, in the Source form of any Derivative Works that You - distribute, all copyright, patent, trademark, and attribution notices from - the Source form of the Work, excluding those notices that do not pertain - to any part of the Derivative Works; and + means the form of the work preferred for making modifications. - 4. If the Work includes a "NOTICE" text file as part of its distribution, - then any Derivative Works that You distribute must include a readable copy - of the attribution notices contained within such NOTICE file, excluding - those notices that do not pertain to any part of the Derivative Works, - in at least one of the following places: within a NOTICE text file - distributed as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, within a - display generated by the Derivative Works, if and wherever such - third-party notices normally appear. The contents of the NOTICE file are - for informational purposes only and do not modify the License. - You may add Your own attribution notices within Derivative Works that You - distribute, alongside or as an addendum to the NOTICE text from the Work, - provided that such additional attribution notices cannot be construed - as modifying the License. +1.14. "You" (or "Your") - You may add Your own copyright statement to Your modifications and may - provide additional or different license terms and conditions for use, - reproduction, or distribution of Your modifications, or for any such - Derivative Works as a whole, provided Your use, reproduction, and - distribution of the Work otherwise complies with the conditions - stated in this License. + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. -5. Submission of Contributions. - Unless You explicitly state otherwise, any Contribution intentionally - submitted for inclusion in the Work by You to the Licensor shall be under - the terms and conditions of this License, without any additional - terms or conditions. Notwithstanding the above, nothing herein shall - supersede or modify the terms of any separate license agreement you may - have executed with Licensor regarding such Contributions. +2. License Grants and Conditions -6. Trademarks. +2.1. Grants - This License does not grant permission to use the trade names, trademarks, - service marks, or product names of the Licensor, except as required for - reasonable and customary use in describing the origin of the Work and - reproducing the content of the NOTICE file. + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: -7. Disclaimer of Warranty. + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and - Unless required by applicable law or agreed to in writing, Licensor - provides the Work (and each Contributor provides its Contributions) - on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - either express or implied, including, without limitation, any warranties - or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS - FOR A PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any risks - associated with Your exercise of permissions under this License. + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. -8. Limitation of Liability. +2.2. Effective Date - In no event and under no legal theory, whether in tort - (including negligence), contract, or otherwise, unless required by - applicable law (such as deliberate and grossly negligent acts) or agreed - to in writing, shall any Contributor be liable to You for damages, - including any direct, indirect, special, incidental, or consequential - damages of any character arising as a result of this License or out of - the use or inability to use the Work (including but not limited to damages - for loss of goodwill, work stoppage, computer failure or malfunction, - or any and all other commercial damages or losses), even if such - Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - - While redistributing the Work or Derivative Works thereof, You may choose - to offer, and charge a fee for, acceptance of support, warranty, - indemnity, or other liability obligations and/or rights consistent with - this License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf of any - other Contributor, and only if You agree to indemnify, defend, and hold - each Contributor harmless for any liability incurred by, or claims - asserted against, such Contributor by reason of your accepting any such - warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - - To apply the Apache License to your work, attach the following boilerplate - notice, with the fields enclosed by brackets "[]" replaced with your own - identifying information. (Don't include the brackets!) The text should be - enclosed in the appropriate comment syntax for the file format. We also - recommend that a file or class name and description of purpose be included - on the same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2016 Nolan Lawson - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the License for the specific language governing - permissions and limitations under the License. - - - --------------------- DEPENDENCY DIVIDER -------------------- - -Name: lodash-es -URL: N/A -Version: 4.17.21 -License: MIT - -Copyright OpenJS Foundation and other contributors - -Based on Underscore.js, copyright Jeremy Ashkenas, -DocumentCloud and Investigative Reporters & Editors - -This software consists of voluntary contributions made by many -individuals. For exact contribution history, see the revision history -available at https://github.com/lodash/lodash - -The following license applies to all parts of this software except as -documented below: - -==== - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -==== - -Copyright and related rights for sample code are waived via CC0. Sample -code is defined as all source code displayed within the prose of the -documentation. - -CC0: http://creativecommons.org/publicdomain/zero/1.0/ - -==== - -Files located in the node_modules and vendor directories are externally -maintained libraries used by this software which have their own -licenses; we recommend you read them, as their terms may differ from the -terms above. - - --------------------- DEPENDENCY DIVIDER -------------------- - -Name: tslib -URL: N/A -Version: 2.6.2 -License: 0BSD - -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - --------------------- DEPENDENCY DIVIDER -------------------- - -Name: @formatjs/icu-messageformat-parser -URL: https://github.com/formatjs/formatjs.git -Version: 2.6.2 -License: MIT - -MIT License - -Copyright (c) 2021 FormatJS - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------- DEPENDENCY DIVIDER -------------------- - -Name: @formatjs/icu-skeleton-parser -URL: https://github.com/formatjs/formatjs.git -Version: 1.6.2 -License: MIT - -MIT License - -Copyright (c) 2021 FormatJS - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. +2.3. Limitations on Grant Scope --------------------- DEPENDENCY DIVIDER -------------------- + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: -Name: @formatjs/fast-memoize -URL: N/A -Version: 2.2.0 -License: MIT + a. for any code that a Contributor has removed from Covered Software; or -MIT License + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or -Copyright (c) 2021 FormatJS + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +2.4. Subsequent Licenses -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). +2.5. Representation --------------------- DEPENDENCY DIVIDER -------------------- + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. -Name: intl-messageformat -URL: N/A -Version: 10.5.3 -License: BSD-3-Clause +2.6. Fair Use -Copyright (c) 2021, Oath Inc. + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. -Licensed under the terms of the New BSD license. See below for terms. +2.7. Conditions -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. -- Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. -- Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. +3. Responsibilities -- Neither the name of Oath Inc. nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of Oath Inc. +3.1. Distribution of Source Form -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. -------------------- DEPENDENCY DIVIDER -------------------- -Name: lighthouse-stack-packs -URL: N/A -Version: 1.12.3 +Name: csp_evaluator +URL: https://csp-evaluator.withgoogle.com/ +Version: 1.1.5 License: Apache-2.0 @@ -575,127 +617,976 @@ License: Apache-2.0 that such additional attribution notices cannot be construed as modifying the License. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: debug +URL: git://github.com/debug-js/debug.git +Version: 4.3.4 +License: MIT + +(The MIT License) + +Copyright (c) 2014-2017 TJ Holowaychuk +Copyright (c) 2018-2021 Josh Junon + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the 'Software'), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: http-link-header +URL: https://github.com/jhermsmeier/node-http-link-header +Version: 1.1.1 +License: MIT + +# The MIT License (MIT) +Copyright (c) 2016 Jonas Hermsmeier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: intl-messageformat +URL: https://github.com/formatjs/formatjs +Version: 10.5.3 +License: BSD-3-Clause + +Copyright (c) 2021, Oath Inc. + +Licensed under the terms of the New BSD license. See below for terms. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +- Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +- Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +- Neither the name of Oath Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Oath Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: js-library-detector +URL: https://github.com/johnmichel/Library-Detector-for-Chrome#readme +Version: 6.7.0 +License: MIT + +The MIT License (MIT) +Copyright (c) 2010-2016 Andrew Bredow, John Michel, and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: legacy-javascript +URL: https://github.com/GoogleChrome/lighthouse#readme +Version: 0.0.1 +License: Apache-2.0 + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: lighthouse-logger +URL: https://github.com/GoogleChrome/lighthouse.git +Version: 2.0.2 +License: Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: lighthouse-stack-packs +URL: https://github.com/GoogleChrome/lighthouse-stack-packs#readme +Version: 1.12.3 +License: Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: lodash-es +URL: https://lodash.com/custom-builds +Version: 4.17.21 +License: MIT + +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: lookup-closest-locale +URL: https://github.com/format-message/format-message/tree/master/packages/lookup-closest-locale +Version: 6.2.0 +License: MIT + +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: marky +URL: https://github.com/nolanlawson/marky#readme +Version: 1.2.2 +License: Apache-2.0 + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and + distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the + copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other + entities that control, are controlled by, or are under common control with + that entity. For the purposes of this definition, "control" means (i) the + power, direct or indirect, to cause the direction or management of such + entity, whether by contract or otherwise, or (ii) ownership of + fifty percent (50%) or more of the outstanding shares, or (iii) beneficial + ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising + permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation source, + and configuration files. + + "Object" form shall mean any form resulting from mechanical transformation + or translation of a Source form, including but not limited to compiled + object code, generated documentation, and conversions to + other media types. + + "Work" shall mean the work of authorship, whether in Source or Object + form, made available under the License, as indicated by a copyright notice + that is included in or attached to the work (an example is provided in the + Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, + that is based on (or derived from) the Work and for which the editorial + revisions, annotations, elaborations, or other modifications represent, + as a whole, an original work of authorship. For the purposes of this + License, Derivative Works shall not include works that remain separable + from, or merely link (or bind by name) to the interfaces of, the Work and + Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original + version of the Work and any modifications or additions to that Work or + Derivative Works thereof, that is intentionally submitted to Licensor for + inclusion in the Work by the copyright owner or by an individual or + Legal Entity authorized to submit on behalf of the copyright owner. + For the purposes of this definition, "submitted" means any form of + electronic, verbal, or written communication sent to the Licensor or its + representatives, including but not limited to communication on electronic + mailing lists, source code control systems, and issue tracking systems + that are managed by, or on behalf of, the Licensor for the purpose of + discussing and improving the Work, but excluding communication that is + conspicuously marked or otherwise designated in writing by the copyright + owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on + behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. + + Subject to the terms and conditions of this License, each Contributor + hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare + Derivative Works of, publicly display, publicly perform, sublicense, + and distribute the Work and such Derivative Works in + Source or Object form. + +3. Grant of Patent License. + + Subject to the terms and conditions of this License, each Contributor + hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this section) patent + license to make, have made, use, offer to sell, sell, import, and + otherwise transfer the Work, where such license applies only to those + patent claims licensable by such Contributor that are necessarily + infringed by their Contribution(s) alone or by combination of their + Contribution(s) with the Work to which such Contribution(s) was submitted. + If You institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work or a + Contribution incorporated within the Work constitutes direct or + contributory patent infringement, then any patent licenses granted to + You under this License for that Work shall terminate as of the date such + litigation is filed. + +4. Redistribution. + + You may reproduce and distribute copies of the Work or Derivative Works + thereof in any medium, with or without modifications, and in Source or + Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a + copy of this License; and + + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + + 3. You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from + the Source form of the Work, excluding those notices that do not pertain + to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable copy + of the attribution notices contained within such NOTICE file, excluding + those notices that do not pertain to any part of the Derivative Works, + in at least one of the following places: within a NOTICE text file + distributed as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, within a + display generated by the Derivative Works, if and wherever such + third-party notices normally appear. The contents of the NOTICE file are + for informational purposes only and do not modify the License. + You may add Your own attribution notices within Derivative Works that You + distribute, alongside or as an addendum to the NOTICE text from the Work, + provided that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and may + provide additional or different license terms and conditions for use, + reproduction, or distribution of Your modifications, or for any such + Derivative Works as a whole, provided Your use, reproduction, and + distribution of the Work otherwise complies with the conditions + stated in this License. + +5. Submission of Contributions. + + Unless You explicitly state otherwise, any Contribution intentionally + submitted for inclusion in the Work by You to the Licensor shall be under + the terms and conditions of this License, without any additional + terms or conditions. Notwithstanding the above, nothing herein shall + supersede or modify the terms of any separate license agreement you may + have executed with Licensor regarding such Contributions. + +6. Trademarks. + + This License does not grant permission to use the trade names, trademarks, + service marks, or product names of the Licensor, except as required for + reasonable and customary use in describing the origin of the Work and + reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + + Unless required by applicable law or agreed to in writing, Licensor + provides the Work (and each Contributor provides its Contributions) + on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied, including, without limitation, any warranties + or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS + FOR A PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any risks + associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + + In no event and under no legal theory, whether in tort + (including negligence), contract, or otherwise, unless required by + applicable law (such as deliberate and grossly negligent acts) or agreed + to in writing, shall any Contributor be liable to You for damages, + including any direct, indirect, special, incidental, or consequential + damages of any character arising as a result of this License or out of + the use or inability to use the Work (including but not limited to damages + for loss of goodwill, work stoppage, computer failure or malfunction, + or any and all other commercial damages or losses), even if such + Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + + While redistributing the Work or Derivative Works thereof, You may choose + to offer, and charge a fee for, acceptance of support, warranty, + indemnity, or other liability obligations and/or rights consistent with + this License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf of any + other Contributor, and only if You agree to indemnify, defend, and hold + each Contributor harmless for any liability incurred by, or claims + asserted against, such Contributor by reason of your accepting any such + warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + + To apply the Apache License to your work, attach the following boilerplate + notice, with the fields enclosed by brackets "[]" replaced with your own + identifying information. (Don't include the brackets!) The text should be + enclosed in the appropriate comment syntax for the file format. We also + recommend that a file or class name and description of purpose be included + on the same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Nolan Lawson - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. + http://www.apache.org/licenses/LICENSE-2.0 - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the License for the specific language governing + permissions and limitations under the License. - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. +-------------------- DEPENDENCY DIVIDER -------------------- - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +Name: ms +URL: zeit/ms +Version: 2.1.2 +License: MIT - Copyright [yyyy] [name of copyright owner] +The MIT License (MIT) - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Copyright (c) 2016 Zeit, Inc. - http://www.apache.org/licenses/LICENSE-2.0 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -------------------- DEPENDENCY DIVIDER -------------------- -Name: lookup-closest-locale -URL: N/A -Version: 6.2.0 -License: MIT +Name: puppeteer-core +URL: https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core +Version: 24.23.0 +License: Apache-2.0 -------------------- DEPENDENCY DIVIDER -------------------- -Name: @paulirish/trace_engine -URL: N/A -Version: 0.0.61 -License: BSD-3-Clause +Name: robots-parser +URL: https://github.com/samclarke/robots-parser +Version: 3.0.1 +License: MIT -// Copyright 2014 The Chromium Authors -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +The MIT License (MIT) + +Copyright (c) 2014 Sam Clarke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. -------------------- DEPENDENCY DIVIDER -------------------- @@ -729,15 +1620,30 @@ SOFTWARE. -------------------- DEPENDENCY DIVIDER -------------------- -Name: legacy-javascript -URL: N/A -Version: 0.0.1 -License: Apache-2.0 +Name: tldts-core +URL: https://github.com/remusao/tldts#readme +Version: 7.0.17 +License: MIT + +Copyright (c) 2017 Thomas Parisot, 2018 Rémi Berson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + -------------------- DEPENDENCY DIVIDER -------------------- Name: tldts-icann -URL: N/A +URL: https://github.com/remusao/tldts#readme Version: 7.0.17 License: MIT @@ -758,41 +1664,31 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTH -------------------- DEPENDENCY DIVIDER -------------------- -Name: http-link-header -URL: N/A -Version: 1.1.1 -License: MIT - -# The MIT License (MIT) -Copyright (c) 2016 Jonas Hermsmeier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Name: tslib +URL: https://www.typescriptlang.org/ +Version: 2.6.2 +License: 0BSD -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Copyright (c) Microsoft Corporation. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. -------------------- DEPENDENCY DIVIDER -------------------- -Name: csp_evaluator -URL: N/A -Version: 1.1.5 +Name: web-features +URL: git+https://github.com/web-platform-dx/web-features.git +Version: 3.21.0 License: Apache-2.0 - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -994,32 +1890,3 @@ License: Apache-2.0 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - --------------------- DEPENDENCY DIVIDER -------------------- - -Name: robots-parser -URL: N/A -Version: 3.0.1 -License: MIT - -The MIT License (MIT) - -Copyright (c) 2014 Sam Clarke - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/third_party/lighthouse-devtools-mcp-bundle.js b/src/third_party/lighthouse-devtools-mcp-bundle.js index 9cbb0f59d..924c07178 100644 --- a/src/third_party/lighthouse-devtools-mcp-bundle.js +++ b/src/third_party/lighthouse-devtools-mcp-bundle.js @@ -1,5 +1,5 @@ /** - * Lighthouse v13.0.3-4-gd6e2a8e40 (Mar 04 2026) + * Lighthouse v13.0.3-17-g8c673f8b4 (Mar 31 2026) * * Automated auditing, performance metrics, and best practices for the web. * @@ -128,32 +128,6 @@ var init_base_gatherer = __esm({ } }); -// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace.js -var trace_exports = {}; -__export(trace_exports, { - default: () => trace_default -}); -var ShimGatherer, trace_default; -var init_trace = __esm({ - "lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace.js"() { - init_process_global(); - init_base_gatherer(); - ShimGatherer = class extends base_gatherer_default { - static { - __name(this, "ShimGatherer"); - } - meta = { supportedModes: ["navigation", "timespan", "snapshot"] }; - static getDefaultTraceCategories() { - return []; - } - getArtifact() { - return void 0; - } - }; - trace_default = ShimGatherer; - } -}); - // node_modules/debug/node_modules/ms/index.js var require_ms = __commonJS({ "node_modules/debug/node_modules/ms/index.js"(exports2, module2) { @@ -976,493 +950,1359 @@ var init_lighthouse_logger = __esm({ } }); -// node_modules/lodash-es/_freeGlobal.js -var freeGlobal, freeGlobal_default; -var init_freeGlobal = __esm({ - "node_modules/lodash-es/_freeGlobal.js"() { - init_process_global(); - freeGlobal = typeof global == "object" && global && global.Object === Object && global; - freeGlobal_default = freeGlobal; - } -}); - -// node_modules/lodash-es/_root.js -var freeSelf, root, root_default; -var init_root = __esm({ - "node_modules/lodash-es/_root.js"() { - init_process_global(); - init_freeGlobal(); - freeSelf = typeof self == "object" && self && self.Object === Object && self; - root = freeGlobal_default || freeSelf || Function("return this")(); - root_default = root; - } -}); - -// node_modules/lodash-es/_Symbol.js -var Symbol2, Symbol_default; -var init_Symbol = __esm({ - "node_modules/lodash-es/_Symbol.js"() { - init_process_global(); - init_root(); - Symbol2 = root_default.Symbol; - Symbol_default = Symbol2; - } -}); - -// node_modules/lodash-es/_getRawTag.js -function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; - try { - value[symToStringTag] = void 0; - var unmasked = true; - } catch (e) { - } - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; -} -var objectProto, hasOwnProperty, nativeObjectToString, symToStringTag, getRawTag_default; -var init_getRawTag = __esm({ - "node_modules/lodash-es/_getRawTag.js"() { - init_process_global(); - init_Symbol(); - objectProto = Object.prototype; - hasOwnProperty = objectProto.hasOwnProperty; - nativeObjectToString = objectProto.toString; - symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0; - __name(getRawTag, "getRawTag"); - getRawTag_default = getRawTag; - } -}); - -// node_modules/lodash-es/_objectToString.js -function objectToString(value) { - return nativeObjectToString2.call(value); -} -var objectProto2, nativeObjectToString2, objectToString_default; -var init_objectToString = __esm({ - "node_modules/lodash-es/_objectToString.js"() { - init_process_global(); - objectProto2 = Object.prototype; - nativeObjectToString2 = objectProto2.toString; - __name(objectToString, "objectToString"); - objectToString_default = objectToString; - } -}); - -// node_modules/lodash-es/_baseGetTag.js -function baseGetTag(value) { - if (value == null) { - return value === void 0 ? undefinedTag : nullTag; - } - return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value); -} -var nullTag, undefinedTag, symToStringTag2, baseGetTag_default; -var init_baseGetTag = __esm({ - "node_modules/lodash-es/_baseGetTag.js"() { - init_process_global(); - init_Symbol(); - init_getRawTag(); - init_objectToString(); - nullTag = "[object Null]"; - undefinedTag = "[object Undefined]"; - symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0; - __name(baseGetTag, "baseGetTag"); - baseGetTag_default = baseGetTag; - } -}); - -// node_modules/lodash-es/isObjectLike.js -function isObjectLike(value) { - return value != null && typeof value == "object"; -} -var isObjectLike_default; -var init_isObjectLike = __esm({ - "node_modules/lodash-es/isObjectLike.js"() { - init_process_global(); - __name(isObjectLike, "isObjectLike"); - isObjectLike_default = isObjectLike; - } -}); - -// node_modules/lodash-es/isArray.js -var isArray, isArray_default; -var init_isArray = __esm({ - "node_modules/lodash-es/isArray.js"() { - init_process_global(); - isArray = Array.isArray; - isArray_default = isArray; - } -}); - -// node_modules/lodash-es/isObject.js -function isObject(value) { - var type = typeof value; - return value != null && (type == "object" || type == "function"); -} -var isObject_default; -var init_isObject = __esm({ - "node_modules/lodash-es/isObject.js"() { - init_process_global(); - __name(isObject, "isObject"); - isObject_default = isObject; - } -}); - -// node_modules/lodash-es/isFunction.js -function isFunction(value) { - if (!isObject_default(value)) { - return false; - } - var tag = baseGetTag_default(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; -} -var asyncTag, funcTag, genTag, proxyTag, isFunction_default; -var init_isFunction = __esm({ - "node_modules/lodash-es/isFunction.js"() { - init_process_global(); - init_baseGetTag(); - init_isObject(); - asyncTag = "[object AsyncFunction]"; - funcTag = "[object Function]"; - genTag = "[object GeneratorFunction]"; - proxyTag = "[object Proxy]"; - __name(isFunction, "isFunction"); - isFunction_default = isFunction; - } -}); - -// node_modules/lodash-es/_coreJsData.js -var coreJsData, coreJsData_default; -var init_coreJsData = __esm({ - "node_modules/lodash-es/_coreJsData.js"() { - init_process_global(); - init_root(); - coreJsData = root_default["__core-js_shared__"]; - coreJsData_default = coreJsData; - } -}); - -// node_modules/lodash-es/_isMasked.js -function isMasked(func) { - return !!maskSrcKey && maskSrcKey in func; -} -var maskSrcKey, isMasked_default; -var init_isMasked = __esm({ - "node_modules/lodash-es/_isMasked.js"() { - init_process_global(); - init_coreJsData(); - maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData_default && coreJsData_default.keys && coreJsData_default.keys.IE_PROTO || ""); - return uid ? "Symbol(src)_1." + uid : ""; - })(); - __name(isMasked, "isMasked"); - isMasked_default = isMasked; - } -}); - -// node_modules/lodash-es/_toSource.js -function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) { - } - try { - return func + ""; - } catch (e) { - } - } - return ""; -} -var funcProto, funcToString, toSource_default; -var init_toSource = __esm({ - "node_modules/lodash-es/_toSource.js"() { - init_process_global(); - funcProto = Function.prototype; - funcToString = funcProto.toString; - __name(toSource, "toSource"); - toSource_default = toSource; - } -}); - -// node_modules/lodash-es/_baseIsNative.js -function baseIsNative(value) { - if (!isObject_default(value) || isMasked_default(value)) { - return false; - } - var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource_default(value)); -} -var reRegExpChar, reIsHostCtor, funcProto2, objectProto3, funcToString2, hasOwnProperty2, reIsNative, baseIsNative_default; -var init_baseIsNative = __esm({ - "node_modules/lodash-es/_baseIsNative.js"() { - init_process_global(); - init_isFunction(); - init_isMasked(); - init_isObject(); - init_toSource(); - reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - reIsHostCtor = /^\[object .+?Constructor\]$/; - funcProto2 = Function.prototype; - objectProto3 = Object.prototype; - funcToString2 = funcProto2.toString; - hasOwnProperty2 = objectProto3.hasOwnProperty; - reIsNative = RegExp( - "^" + funcToString2.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$" - ); - __name(baseIsNative, "baseIsNative"); - baseIsNative_default = baseIsNative; - } -}); - -// node_modules/lodash-es/_getValue.js -function getValue(object, key) { - return object == null ? void 0 : object[key]; -} -var getValue_default; -var init_getValue = __esm({ - "node_modules/lodash-es/_getValue.js"() { - init_process_global(); - __name(getValue, "getValue"); - getValue_default = getValue; - } -}); - -// node_modules/lodash-es/_getNative.js -function getNative(object, key) { - var value = getValue_default(object, key); - return baseIsNative_default(value) ? value : void 0; -} -var getNative_default; -var init_getNative = __esm({ - "node_modules/lodash-es/_getNative.js"() { - init_process_global(); - init_baseIsNative(); - init_getValue(); - __name(getNative, "getNative"); - getNative_default = getNative; - } -}); - -// node_modules/lodash-es/_WeakMap.js -var WeakMap2, WeakMap_default; -var init_WeakMap = __esm({ - "node_modules/lodash-es/_WeakMap.js"() { - init_process_global(); - init_getNative(); - init_root(); - WeakMap2 = getNative_default(root_default, "WeakMap"); - WeakMap_default = WeakMap2; - } -}); - -// node_modules/lodash-es/_isIndex.js -function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); -} -var MAX_SAFE_INTEGER, reIsUint, isIndex_default; -var init_isIndex = __esm({ - "node_modules/lodash-es/_isIndex.js"() { - init_process_global(); - MAX_SAFE_INTEGER = 9007199254740991; - reIsUint = /^(?:0|[1-9]\d*)$/; - __name(isIndex, "isIndex"); - isIndex_default = isIndex; - } -}); - -// node_modules/lodash-es/eq.js -function eq(value, other) { - return value === other || value !== value && other !== other; -} -var eq_default; -var init_eq = __esm({ - "node_modules/lodash-es/eq.js"() { - init_process_global(); - __name(eq, "eq"); - eq_default = eq; - } -}); - -// node_modules/lodash-es/isLength.js -function isLength(value) { - return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER2; -} -var MAX_SAFE_INTEGER2, isLength_default; -var init_isLength = __esm({ - "node_modules/lodash-es/isLength.js"() { - init_process_global(); - MAX_SAFE_INTEGER2 = 9007199254740991; - __name(isLength, "isLength"); - isLength_default = isLength; - } -}); - -// node_modules/lodash-es/isArrayLike.js -function isArrayLike(value) { - return value != null && isLength_default(value.length) && !isFunction_default(value); -} -var isArrayLike_default; -var init_isArrayLike = __esm({ - "node_modules/lodash-es/isArrayLike.js"() { - init_process_global(); - init_isFunction(); - init_isLength(); - __name(isArrayLike, "isArrayLike"); - isArrayLike_default = isArrayLike; - } -}); - -// node_modules/lodash-es/_isPrototype.js -function isPrototype(value) { - var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto4; - return value === proto; -} -var objectProto4, isPrototype_default; -var init_isPrototype = __esm({ - "node_modules/lodash-es/_isPrototype.js"() { - init_process_global(); - objectProto4 = Object.prototype; - __name(isPrototype, "isPrototype"); - isPrototype_default = isPrototype; - } -}); - -// node_modules/lodash-es/_baseTimes.js -function baseTimes(n, iteratee) { - var index = -1, result = Array(n); - while (++index < n) { - result[index] = iteratee(index); - } - return result; -} -var baseTimes_default; -var init_baseTimes = __esm({ - "node_modules/lodash-es/_baseTimes.js"() { - init_process_global(); - __name(baseTimes, "baseTimes"); - baseTimes_default = baseTimes; - } -}); - -// node_modules/lodash-es/_baseIsArguments.js -function baseIsArguments(value) { - return isObjectLike_default(value) && baseGetTag_default(value) == argsTag; -} -var argsTag, baseIsArguments_default; -var init_baseIsArguments = __esm({ - "node_modules/lodash-es/_baseIsArguments.js"() { - init_process_global(); - init_baseGetTag(); - init_isObjectLike(); - argsTag = "[object Arguments]"; - __name(baseIsArguments, "baseIsArguments"); - baseIsArguments_default = baseIsArguments; - } -}); - -// node_modules/lodash-es/isArguments.js -var objectProto5, hasOwnProperty3, propertyIsEnumerable, isArguments, isArguments_default; -var init_isArguments = __esm({ - "node_modules/lodash-es/isArguments.js"() { - init_process_global(); - init_baseIsArguments(); - init_isObjectLike(); - objectProto5 = Object.prototype; - hasOwnProperty3 = objectProto5.hasOwnProperty; - propertyIsEnumerable = objectProto5.propertyIsEnumerable; - isArguments = baseIsArguments_default(/* @__PURE__ */ (function() { - return arguments; - })()) ? baseIsArguments_default : function(value) { - return isObjectLike_default(value) && hasOwnProperty3.call(value, "callee") && !propertyIsEnumerable.call(value, "callee"); - }; - isArguments_default = isArguments; - } -}); - -// node_modules/lodash-es/stubFalse.js -function stubFalse() { - return false; -} -var stubFalse_default; -var init_stubFalse = __esm({ - "node_modules/lodash-es/stubFalse.js"() { - init_process_global(); - __name(stubFalse, "stubFalse"); - stubFalse_default = stubFalse; - } -}); - -// node_modules/lodash-es/isBuffer.js -var freeExports, freeModule, moduleExports, Buffer2, nativeIsBuffer, isBuffer, isBuffer_default; -var init_isBuffer = __esm({ - "node_modules/lodash-es/isBuffer.js"() { - init_process_global(); - init_root(); - init_stubFalse(); - freeExports = typeof exports == "object" && exports && !exports.nodeType && exports; - freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module; - moduleExports = freeModule && freeModule.exports === freeExports; - Buffer2 = moduleExports ? root_default.Buffer : void 0; - nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0; - isBuffer = nativeIsBuffer || stubFalse_default; - isBuffer_default = isBuffer; - } -}); - -// node_modules/lodash-es/_baseIsTypedArray.js -function baseIsTypedArray(value) { - return isObjectLike_default(value) && isLength_default(value.length) && !!typedArrayTags[baseGetTag_default(value)]; -} -var argsTag2, arrayTag, boolTag, dateTag, errorTag, funcTag2, mapTag, numberTag, objectTag, regexpTag, setTag, stringTag, weakMapTag, arrayBufferTag, dataViewTag, float32Tag, float64Tag, int8Tag, int16Tag, int32Tag, uint8Tag, uint8ClampedTag, uint16Tag, uint32Tag, typedArrayTags, baseIsTypedArray_default; -var init_baseIsTypedArray = __esm({ - "node_modules/lodash-es/_baseIsTypedArray.js"() { +// core/lib/tracehouse/trace-processor.js +var ACCEPTABLE_NAVIGATION_URL_REGEX, BASE_RESPONSE_LATENCY, SCHEDULABLE_TASK_TITLE_LH, SCHEDULABLE_TASK_TITLE_ALT1, SCHEDULABLE_TASK_TITLE_ALT2, SCHEDULABLE_TASK_TITLE_ALT3, TraceProcessor; +var init_trace_processor = __esm({ + "core/lib/tracehouse/trace-processor.js"() { + "use strict"; init_process_global(); - init_baseGetTag(); - init_isLength(); - init_isObjectLike(); - argsTag2 = "[object Arguments]"; - arrayTag = "[object Array]"; - boolTag = "[object Boolean]"; - dateTag = "[object Date]"; - errorTag = "[object Error]"; - funcTag2 = "[object Function]"; - mapTag = "[object Map]"; - numberTag = "[object Number]"; - objectTag = "[object Object]"; - regexpTag = "[object RegExp]"; - setTag = "[object Set]"; - stringTag = "[object String]"; - weakMapTag = "[object WeakMap]"; - arrayBufferTag = "[object ArrayBuffer]"; - dataViewTag = "[object DataView]"; - float32Tag = "[object Float32Array]"; - float64Tag = "[object Float64Array]"; - int8Tag = "[object Int8Array]"; - int16Tag = "[object Int16Array]"; - int32Tag = "[object Int32Array]"; - uint8Tag = "[object Uint8Array]"; - uint8ClampedTag = "[object Uint8ClampedArray]"; - uint16Tag = "[object Uint16Array]"; - uint32Tag = "[object Uint32Array]"; - typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag2] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag2] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - __name(baseIsTypedArray, "baseIsTypedArray"); - baseIsTypedArray_default = baseIsTypedArray; - } -}); - -// node_modules/lodash-es/_baseUnary.js + init_lighthouse_logger(); + /** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + ACCEPTABLE_NAVIGATION_URL_REGEX = /^(chrome|https?):/; + BASE_RESPONSE_LATENCY = 16; + SCHEDULABLE_TASK_TITLE_LH = "RunTask"; + SCHEDULABLE_TASK_TITLE_ALT1 = "ThreadControllerImpl::RunTask"; + SCHEDULABLE_TASK_TITLE_ALT2 = "ThreadControllerImpl::DoWork"; + SCHEDULABLE_TASK_TITLE_ALT3 = "TaskQueueManager::ProcessTaskFromWorkQueue"; + TraceProcessor = class _TraceProcessor { + static { + __name(this, "TraceProcessor"); + } + static get TIMESPAN_MARKER_ID() { + return "__lighthouseTimespanStart__"; + } + /** + * @return {Error} + */ + static createNoNavstartError() { + return new Error("No navigationStart event found"); + } + /** + * @return {Error} + */ + static createNoResourceSendRequestError() { + return new Error("No ResourceSendRequest event found"); + } + /** + * @return {Error} + */ + static createNoTracingStartedError() { + return new Error("No tracingStartedInBrowser event found"); + } + /** + * @return {Error} + */ + static createNoFirstContentfulPaintError() { + return new Error("No FirstContentfulPaint event found"); + } + /** + * @return {Error} + */ + static createNoLighthouseMarkerError() { + return new Error("No Lighthouse timespan marker event found"); + } + /** + * Returns true if the event is a navigation start event of a document whose URL seems valid. + * + * @param {LH.TraceEvent} event + * @return {boolean} + */ + static _isNavigationStartOfInterest(event) { + if (event.name !== "navigationStart") return false; + if (event.args.data?.documentLoaderURL === void 0) return true; + if (!event.args.data?.documentLoaderURL) return false; + return ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL); + } + /** + * This method sorts a group of trace events that have the same timestamp. We want to... + * + * 1. Put E events first, we finish off our existing events before we start new ones. + * 2. Order B/X events by their duration, we want parents to start before child events. + * 3. If we don't have any of this to go on, just use the position in the original array (stable sort). + * + * Note that the typical group size with the same timestamp will be quite small (<10 or so events), + * and the number of groups typically ~1% of total trace, so the same ultra-performance-sensitive consideration + * given to functions that run on entire traces does not necessarily apply here. + * + * @param {number[]} tsGroupIndices + * @param {number[]} timestampSortedIndices + * @param {number} indexOfTsGroupIndicesStart + * @param {LH.TraceEvent[]} traceEvents + * @return {number[]} + */ + static _sortTimestampEventGroup(tsGroupIndices, timestampSortedIndices, indexOfTsGroupIndicesStart, traceEvents) { + const lookupArrayIndexByTsIndex = /* @__PURE__ */ __name((i) => timestampSortedIndices[i], "lookupArrayIndexByTsIndex"); + const lookupEventByTsIndex = /* @__PURE__ */ __name((i) => traceEvents[lookupArrayIndexByTsIndex(i)], "lookupEventByTsIndex"); + const eEventIndices = []; + const bxEventIndices = []; + const otherEventIndices = []; + for (const tsIndex of tsGroupIndices) { + const arrayIndex = lookupArrayIndexByTsIndex(tsIndex); + const event = lookupEventByTsIndex(tsIndex); + if (event.ph === "E") eEventIndices.push(arrayIndex); + else if (event.ph === "X" || event.ph === "B") bxEventIndices.push(arrayIndex); + else otherEventIndices.push(arrayIndex); + } + const effectiveDuration = /* @__PURE__ */ new Map(); + for (const index of bxEventIndices) { + const event = traceEvents[index]; + if (event.ph === "X") { + effectiveDuration.set(index, event.dur); + } else { + let duration = Number.MAX_SAFE_INTEGER; + let additionalNestedEventsWithSameName = 0; + const startIndex = indexOfTsGroupIndicesStart + tsGroupIndices.length; + for (let j = startIndex; j < timestampSortedIndices.length; j++) { + const potentialMatchingEvent = lookupEventByTsIndex(j); + const eventMatches = potentialMatchingEvent.name === event.name && potentialMatchingEvent.pid === event.pid && potentialMatchingEvent.tid === event.tid; + if (!eventMatches) continue; + if (potentialMatchingEvent.ph === "E" && additionalNestedEventsWithSameName === 0) { + duration = potentialMatchingEvent.ts - event.ts; + break; + } else if (potentialMatchingEvent.ph === "E") { + additionalNestedEventsWithSameName--; + } else if (potentialMatchingEvent.ph === "B") { + additionalNestedEventsWithSameName++; + } + } + effectiveDuration.set(index, duration); + } + } + bxEventIndices.sort((indexA, indexB) => (effectiveDuration.get(indexB) || 0) - (effectiveDuration.get(indexA) || 0) || indexA - indexB); + otherEventIndices.sort((indexA, indexB) => indexA - indexB); + return [...eEventIndices, ...bxEventIndices, ...otherEventIndices]; + } + /** + * Sorts and filters trace events by timestamp and respecting the nesting structure inherent to + * parent/child event relationships. + * + * @param {LH.TraceEvent[]} traceEvents + * @param {(e: LH.TraceEvent) => boolean} filter + */ + static filteredTraceSort(traceEvents, filter) { + const indices = []; + for (let srcIndex = 0; srcIndex < traceEvents.length; srcIndex++) { + if (filter(traceEvents[srcIndex])) { + indices.push(srcIndex); + } + } + indices.sort((indexA, indexB) => traceEvents[indexA].ts - traceEvents[indexB].ts); + for (let i = 0; i < indices.length - 1; i++) { + const ts = traceEvents[indices[i]].ts; + const tsGroupIndices = [i]; + for (let j = i + 1; j < indices.length; j++) { + if (traceEvents[indices[j]].ts !== ts) break; + tsGroupIndices.push(j); + } + if (tsGroupIndices.length === 1) continue; + const finalIndexOrder = _TraceProcessor._sortTimestampEventGroup( + tsGroupIndices, + indices, + i, + traceEvents + ); + indices.splice(i, finalIndexOrder.length, ...finalIndexOrder); + i += tsGroupIndices.length - 1; + } + const sorted2 = []; + for (let i = 0; i < indices.length; i++) { + sorted2.push(traceEvents[indices[i]]); + } + return sorted2; + } + /** + * There should *always* be at least one top level event, having 0 typically means something is + * drastically wrong with the trace and we should just give up early and loudly. + * + * @param {LH.TraceEvent[]} events + */ + static assertHasToplevelEvents(events) { + const hasToplevelTask = events.some(this.isScheduleableTask); + if (!hasToplevelTask) { + throw new Error("Could not find any top level events"); + } + } + /** + * Calculate duration at specified percentiles for given population of + * durations. + * If one of the durations overlaps the end of the window, the full + * duration should be in the duration array, but the length not included + * within the window should be given as `clippedLength`. For instance, if a + * 50ms duration occurs 10ms before the end of the window, `50` should be in + * the `durations` array, and `clippedLength` should be set to 40. + * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview + * @param {!Array} durations Array of durations, sorted in ascending order. + * @param {number} totalTime Total time (in ms) of interval containing durations. + * @param {!Array} percentiles Array of percentiles of interest, in ascending order. + * @param {number=} clippedLength Optional length clipped from a duration overlapping end of window. Default of 0. + * @return {!Array<{percentile: number, time: number}>} + * @private + */ + static _riskPercentiles(durations, totalTime, percentiles, clippedLength = 0) { + let busyTime = 0; + for (let i = 0; i < durations.length; i++) { + busyTime += durations[i]; + } + busyTime -= clippedLength; + let completedTime = totalTime - busyTime; + let duration = 0; + let cdfTime = completedTime; + const results = []; + let durationIndex = -1; + let remainingCount = durations.length + 1; + if (clippedLength > 0) { + remainingCount--; + } + for (const percentile of percentiles) { + const percentileTime = percentile * totalTime; + while (cdfTime < percentileTime && durationIndex < durations.length - 1) { + completedTime += duration; + remainingCount -= duration < 0 ? -1 : 1; + if (clippedLength > 0 && clippedLength < durations[durationIndex + 1]) { + duration = -clippedLength; + clippedLength = 0; + } else { + durationIndex++; + duration = durations[durationIndex]; + } + cdfTime = completedTime + Math.abs(duration) * remainingCount; + } + results.push({ + percentile, + time: Math.max(0, (percentileTime - completedTime) / remainingCount) + BASE_RESPONSE_LATENCY + }); + } + return results; + } + /** + * Calculates the maximum queueing time (in ms) of high priority tasks for + * selected percentiles within a window of the main thread. + * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview + * @param {Array} events + * @param {number} startTime Start time (in ms relative to timeOrigin) of range of interest. + * @param {number} endTime End time (in ms relative to timeOrigin) of range of interest. + * @param {!Array=} percentiles Optional array of percentiles to compute. Defaults to [0.5, 0.75, 0.9, 0.99, 1]. + * @return {!Array<{percentile: number, time: number}>} + */ + static getRiskToResponsiveness(events, startTime, endTime, percentiles = [0.5, 0.75, 0.9, 0.99, 1]) { + const totalTime = endTime - startTime; + percentiles.sort((a, b) => a - b); + const ret = this.getMainThreadTopLevelEventDurations(events, startTime, endTime); + return this._riskPercentiles( + ret.durations, + totalTime, + percentiles, + ret.clippedLength + ); + } + /** + * Provides durations in ms of all main thread top-level events + * @param {Array} topLevelEvents + * @param {number} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0. + * @param {number} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end. + * @return {{durations: Array, clippedLength: number}} + */ + static getMainThreadTopLevelEventDurations(topLevelEvents, startTime = 0, endTime = Infinity) { + const durations = []; + let clippedLength = 0; + for (const event of topLevelEvents) { + if (event.end < startTime || event.start > endTime) { + continue; + } + let duration = event.duration; + let eventStart = event.start; + if (eventStart < startTime) { + eventStart = startTime; + duration = event.end - startTime; + } + if (event.end > endTime) { + clippedLength = duration - (endTime - eventStart); + } + durations.push(duration); + } + durations.sort((a, b) => a - b); + return { + durations, + clippedLength + }; + } + /** + * Provides the top level events on the main thread with timestamps in ms relative to timeOrigin. + * start. + * @param {LH.Artifacts.ProcessedTrace} trace + * @param {number=} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0. + * @param {number=} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end. + * @return {Array} + */ + static getMainThreadTopLevelEvents(trace, startTime = 0, endTime = Infinity) { + const topLevelEvents = []; + let prevToplevel = void 0; + for (const event of trace.mainThreadEvents) { + if (!this.isScheduleableTask(event) || !event.dur) continue; + const start = (event.ts - trace.timeOriginEvt.ts) / 1e3; + const end = (event.ts + event.dur - trace.timeOriginEvt.ts) / 1e3; + if (start > endTime || end < startTime) continue; + if (prevToplevel && start < prevToplevel.end) { + prevToplevel.end = start - 1e-3; + } + prevToplevel = { + start, + end, + duration: event.dur / 1e3 + }; + topLevelEvents.push(prevToplevel); + } + return topLevelEvents; + } + /** + * @param {LH.TraceEvent[]} events + * @return {{startingPid: number, frameId: string}} + */ + static findMainFrameIds(events) { + const startedInBrowserEvt = events.find((e) => e.name === "TracingStartedInBrowser"); + if (startedInBrowserEvt?.args.data?.frames) { + const mainFrame = startedInBrowserEvt.args.data.frames.find((frame) => !frame.parent); + const frameId = mainFrame?.frame; + const pid = mainFrame?.processId; + if (pid && frameId) { + return { + startingPid: pid, + frameId + }; + } + } + const startedInPageEvt = events.find((e) => e.name === "TracingStartedInPage"); + if (startedInPageEvt?.args?.data) { + const frameId = startedInPageEvt.args.data.page; + if (frameId) { + return { + startingPid: startedInPageEvt.pid, + frameId + }; + } + } + const navStartEvt = events.find( + (e) => this._isNavigationStartOfInterest(e) && e.args.data?.isLoadingMainFrame + ); + const firstResourceSendEvt = events.find((e) => e.name === "ResourceSendRequest"); + if (navStartEvt?.args?.data && firstResourceSendEvt && firstResourceSendEvt.pid === navStartEvt.pid && firstResourceSendEvt.tid === navStartEvt.tid) { + const frameId = navStartEvt.args.frame; + if (frameId) { + return { + startingPid: navStartEvt.pid, + frameId + }; + } + } + throw this.createNoTracingStartedError(); + } + /** + * If there were any cross-origin navigations, there'll be more than one pid returned + * @param {{startingPid: number, frameId: string}} mainFrameInfo + * @param {LH.TraceEvent[]} keyEvents + * @return {Map} Map where keys are process IDs and their values are thread IDs + */ + static findMainFramePidTids(mainFrameInfo, keyEvents) { + const frameProcessEvts = keyEvents.filter( + (evt) => ( + // ProcessReadyInBrowser is used when a processID isn't available when the FrameCommittedInBrowser trace event is emitted. + // In that case. FrameCommittedInBrowser has no processId, but a processPseudoId. and the ProcessReadyInBrowser event declares the proper processId. + (evt.name === "FrameCommittedInBrowser" || evt.name === "ProcessReadyInBrowser") && evt.args?.data?.frame === mainFrameInfo.frameId && evt?.args?.data?.processId + ) + ); + const mainFramePids = frameProcessEvts.length ? frameProcessEvts.map((e) => e?.args?.data?.processId) : [mainFrameInfo.startingPid]; + const pidToTid = /* @__PURE__ */ new Map(); + for (const pid of new Set(mainFramePids)) { + const threadEvents = keyEvents.filter( + (e) => e.cat === "__metadata" && e.pid === pid && e.ph === "M" && e.name === "thread_name" + ); + let threadNameEvt = threadEvents.find((e) => e.args.name === "CrRendererMain"); + if (!threadNameEvt) { + threadNameEvt = threadEvents.find((e) => e.args.name === "CrBrowserMain"); + } + const tid = threadNameEvt?.tid; + if (!tid) { + throw new Error("Unable to determine tid for renderer process"); + } + pidToTid.set(pid, tid); + } + return pidToTid; + } + /** + * @param {LH.TraceEvent} evt + * @return {boolean} + */ + static isScheduleableTask(evt) { + return evt.name === SCHEDULABLE_TASK_TITLE_LH || evt.name === SCHEDULABLE_TASK_TITLE_ALT1 || evt.name === SCHEDULABLE_TASK_TITLE_ALT2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT3; + } + /** + * @param {LH.TraceEvent} evt + * @return {evt is LCPEvent} + */ + static isLCPEvent(evt) { + if (evt.name !== "largestContentfulPaint::Invalidate" && evt.name !== "largestContentfulPaint::Candidate") return false; + return Boolean(evt.args?.frame); + } + /** + * @param {LH.TraceEvent} evt + * @return {evt is LCPCandidateEvent} + */ + static isLCPCandidateEvent(evt) { + return Boolean( + evt.name === "largestContentfulPaint::Candidate" && evt.args?.frame && evt.args.data && evt.args.data.size !== void 0 + ); + } + /** + * The associated frame ID is set in different locations for different trace events. + * This function checks all known locations for the frame ID and returns `undefined` if it's not found. + * + * @param {LH.TraceEvent} evt + * @return {string|undefined} + */ + static getFrameId(evt) { + return evt.args?.data?.frame || evt.args.data?.frameID || evt.args.frame; + } + /** + * Returns the maximum LCP event across all frames in `events`. + * Sets `invalidated` flag if LCP of every frame is invalidated. + * + * LCP's trace event was first introduced in m78. We can't surface an LCP for older Chrome versions. + * LCP comes from a frame's latest `largestContentfulPaint::Candidate`, but it can be invalidated by a `largestContentfulPaint::Invalidate` event. + * + * @param {LH.TraceEvent[]} events + * @param {LH.TraceEvent} timeOriginEvent + * @return {{lcp: LCPEvent | undefined, invalidated: boolean}} + */ + static computeValidLCPAllFrames(events, timeOriginEvent) { + const lcpEvents = events.filter(this.isLCPEvent).reverse(); + const finalLcpEventsByFrame = /* @__PURE__ */ new Map(); + for (const e of lcpEvents) { + if (e.ts <= timeOriginEvent.ts) break; + const frame = e.args.frame; + if (finalLcpEventsByFrame.has(frame)) continue; + finalLcpEventsByFrame.set(frame, e); + } + let maxLcpAcrossFrames; + for (const lcp of finalLcpEventsByFrame.values()) { + if (!this.isLCPCandidateEvent(lcp)) continue; + if (!maxLcpAcrossFrames || lcp.args.data.size > maxLcpAcrossFrames.args.data.size) { + maxLcpAcrossFrames = lcp; + } + } + return { + lcp: maxLcpAcrossFrames, + // LCP events were found, but final LCP event of every frame was an invalidate event. + invalidated: Boolean(!maxLcpAcrossFrames && finalLcpEventsByFrame.size) + }; + } + /** + * @param {Array<{id: string, url: string, parent?: string}>} frames + * @return {Map} + */ + static resolveRootFrames(frames2) { + const parentFrames = /* @__PURE__ */ new Map(); + for (const frame of frames2) { + if (!frame.parent) continue; + parentFrames.set(frame.id, frame.parent); + } + const frameIdToRootFrameId = /* @__PURE__ */ new Map(); + for (const frame of frames2) { + let cur = frame.id; + while (parentFrames.has(cur)) { + cur = /** @type {string} */ + parentFrames.get(cur); + } + if (cur === void 0) { + throw new Error("Unexpected undefined frameId"); + } + frameIdToRootFrameId.set(frame.id, cur); + } + return frameIdToRootFrameId; + } + /** + * Finds key trace events, identifies main process/thread, and returns timings of trace events + * in milliseconds since the time origin in addition to the standard microsecond monotonic timestamps. + * @param {LH.Trace} trace + * @param {{timeOriginDeterminationMethod?: TimeOriginDeterminationMethod}} [options] + * @return {LH.Artifacts.ProcessedTrace} + */ + static processTrace(trace, options) { + const { timeOriginDeterminationMethod = "auto" } = options || {}; + const keyEvents = this.filteredTraceSort(trace.traceEvents, (e) => { + return e.cat.includes("blink.user_timing") || e.cat.includes("loading") || e.cat.includes("devtools.timeline") || e.cat === "__metadata"; + }); + const mainFrameInfo = this.findMainFrameIds(keyEvents); + const rendererPidToTid = this.findMainFramePidTids(mainFrameInfo, keyEvents); + const processEvents = _TraceProcessor.filteredTraceSort(trace.traceEvents, (e) => rendererPidToTid.has(e.pid)); + const framesById = /* @__PURE__ */ new Map(); + const tracingStartedFrames = keyEvents.find((e) => e.name === "TracingStartedInBrowser")?.args?.data?.frames; + if (tracingStartedFrames) { + for (const frame of tracingStartedFrames) { + framesById.set(frame.frame, { + id: frame.frame, + url: frame.url, + parent: frame.parent + }); + } + } + keyEvents.filter( + /** @return {evt is FrameCommittedEvent} */ + (evt) => { + return Boolean( + evt.name === "FrameCommittedInBrowser" && evt.args.data?.frame && evt.args.data.url !== void 0 + ); + } + ).forEach((evt) => { + framesById.set(evt.args.data.frame, { + id: evt.args.data.frame, + url: evt.args.data.url, + parent: evt.args.data.parent + }); + }); + const frames2 = [...framesById.values()]; + const frameIdToRootFrameId = this.resolveRootFrames(frames2); + const inspectedTreeFrameIds = [...frameIdToRootFrameId.entries()].filter(([, rootFrameId]) => rootFrameId === mainFrameInfo.frameId).map(([child]) => child); + function associatedToMainFrame(e) { + const frameId = _TraceProcessor.getFrameId(e); + return frameId === mainFrameInfo.frameId; + } + __name(associatedToMainFrame, "associatedToMainFrame"); + function associatedToAllFrames(e) { + const frameId = _TraceProcessor.getFrameId(e); + return frameId ? inspectedTreeFrameIds.includes(frameId) : false; + } + __name(associatedToAllFrames, "associatedToAllFrames"); + const frameEvents = keyEvents.filter((e) => associatedToMainFrame(e)); + let frameTreeEvents = []; + if (frameIdToRootFrameId.has(mainFrameInfo.frameId)) { + frameTreeEvents = keyEvents.filter((e) => associatedToAllFrames(e)); + } else { + lighthouse_logger_default.warn( + "TraceProcessor", + "frameTreeEvents may be incomplete, make sure the trace has frame events" + ); + frameIdToRootFrameId.set(mainFrameInfo.frameId, mainFrameInfo.frameId); + frameTreeEvents = frameEvents; + } + const timeOriginEvt = this.computeTimeOrigin( + { keyEvents, frameEvents, mainFrameInfo }, + timeOriginDeterminationMethod + ); + const mainThreadEvents = processEvents.filter((e) => e.tid === rendererPidToTid.get(e.pid)); + const traceEnd = this.computeTraceEnd(trace.traceEvents, timeOriginEvt); + return { + frames: frames2, + mainThreadEvents, + frameEvents, + frameTreeEvents, + processEvents, + mainFrameInfo, + timeOriginEvt, + timings: { + timeOrigin: 0, + traceEnd: traceEnd.timing + }, + timestamps: { + timeOrigin: timeOriginEvt.ts, + traceEnd: traceEnd.timestamp + }, + _keyEvents: keyEvents, + _rendererPidToTid: rendererPidToTid + }; + } + /** + * Finds key navigation trace events and computes timings of events in milliseconds since the time + * origin in addition to the standard microsecond monotonic timestamps. + * @param {LH.Artifacts.ProcessedTrace} processedTrace + * @return {LH.Artifacts.ProcessedNavigation} + */ + static processNavigation(processedTrace) { + const { frameEvents, frameTreeEvents, timeOriginEvt, timings, timestamps } = processedTrace; + const frameTimings = this.computeNavigationTimingsForFrame(frameEvents, { timeOriginEvt }); + const fcpAllFramesEvt = frameTreeEvents.find( + (e) => e.name === "firstContentfulPaint" && e.ts > timeOriginEvt.ts + ); + if (!fcpAllFramesEvt) { + throw this.createNoFirstContentfulPaintError(); + } + const lcpAllFramesEvt = this.computeValidLCPAllFrames(frameTreeEvents, timeOriginEvt).lcp; + const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, "getTiming"); + const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), "maybeGetTiming"); + return { + timings: { + timeOrigin: timings.timeOrigin, + firstPaint: frameTimings.timings.firstPaint, + firstContentfulPaint: frameTimings.timings.firstContentfulPaint, + firstContentfulPaintAllFrames: getTiming(fcpAllFramesEvt.ts), + largestContentfulPaint: frameTimings.timings.largestContentfulPaint, + largestContentfulPaintAllFrames: maybeGetTiming(lcpAllFramesEvt?.ts), + load: frameTimings.timings.load, + domContentLoaded: frameTimings.timings.domContentLoaded, + traceEnd: timings.traceEnd + }, + timestamps: { + timeOrigin: timestamps.timeOrigin, + firstPaint: frameTimings.timestamps.firstPaint, + firstContentfulPaint: frameTimings.timestamps.firstContentfulPaint, + firstContentfulPaintAllFrames: fcpAllFramesEvt.ts, + largestContentfulPaint: frameTimings.timestamps.largestContentfulPaint, + largestContentfulPaintAllFrames: lcpAllFramesEvt?.ts, + load: frameTimings.timestamps.load, + domContentLoaded: frameTimings.timestamps.domContentLoaded, + traceEnd: timestamps.traceEnd + }, + firstPaintEvt: frameTimings.firstPaintEvt, + firstContentfulPaintEvt: frameTimings.firstContentfulPaintEvt, + firstContentfulPaintAllFramesEvt: fcpAllFramesEvt, + largestContentfulPaintEvt: frameTimings.largestContentfulPaintEvt, + largestContentfulPaintAllFramesEvt: lcpAllFramesEvt, + loadEvt: frameTimings.loadEvt, + domContentLoadedEvt: frameTimings.domContentLoadedEvt, + lcpInvalidated: frameTimings.lcpInvalidated + }; + } + /** + * Computes the last observable timestamp in a set of trace events. + * + * @param {Array} events + * @param {LH.TraceEvent} timeOriginEvt + * @return {{timing: number, timestamp: number}} + */ + static computeTraceEnd(events, timeOriginEvt) { + let maxTs = -Infinity; + for (const event of events) { + maxTs = Math.max(event.ts + (event.dur || 0), maxTs); + } + return { timestamp: maxTs, timing: (maxTs - timeOriginEvt.ts) / 1e3 }; + } + /** + * Computes the time origin using the specified method. + * + * - firstResourceSendRequest + * Uses the time that the very first network request is sent in the main frame. + * Eventually should be used in place of lastNavigationStart as the default for navigations. + * This method includes the cost of all redirects when evaluating a navigation (which matches lantern behavior). + * The only difference between firstResourceSendRequest and the first `navigationStart` is + * the unload time of `about:blank` (which is a Lighthouse implementation detail and shouldn't be included). + * + * - lastNavigationStart + * Uses the time of the last `navigationStart` event in the main frame. + * The historical time origin of Lighthouse from 2016-Present. + * This method excludes the cost of client-side redirects when evaluating a navigation. + * Can also be skewed by several hundred milliseconds or even seconds when the browser takes a long + * time to unload `about:blank`. + * + * @param {{keyEvents: Array, frameEvents: Array, mainFrameInfo: {frameId: string}}} traceEventSubsets + * @param {TimeOriginDeterminationMethod} method + * @return {LH.TraceEvent} + */ + static computeTimeOrigin(traceEventSubsets, method) { + const lastNavigationStart = /* @__PURE__ */ __name(() => { + const frameEvents = traceEventSubsets.frameEvents; + return frameEvents.filter(this._isNavigationStartOfInterest).pop(); + }, "lastNavigationStart"); + const lighthouseMarker = /* @__PURE__ */ __name(() => { + const frameEvents = traceEventSubsets.keyEvents; + return frameEvents.find( + (evt) => evt.name === "clock_sync" && evt.args.sync_id === _TraceProcessor.TIMESPAN_MARKER_ID + ); + }, "lighthouseMarker"); + switch (method) { + case "firstResourceSendRequest": { + const fetchStart = traceEventSubsets.keyEvents.find((event) => { + if (event.name !== "ResourceSendRequest") return false; + const data31 = event.args.data || {}; + return data31.frame === traceEventSubsets.mainFrameInfo.frameId; + }); + if (!fetchStart) throw this.createNoResourceSendRequestError(); + return fetchStart; + } + case "lastNavigationStart": { + const navigationStart = lastNavigationStart(); + if (!navigationStart) throw this.createNoNavstartError(); + return navigationStart; + } + case "lighthouseMarker": { + const marker = lighthouseMarker(); + if (!marker) throw this.createNoLighthouseMarkerError(); + return marker; + } + case "auto": { + const marker = lighthouseMarker() || lastNavigationStart(); + if (!marker) throw this.createNoNavstartError(); + return marker; + } + } + } + /** + * Computes timings of trace events of key trace events in milliseconds since the time origin + * in addition to the standard microsecond monotonic timestamps. + * @param {Array} frameEvents + * @param {{timeOriginEvt: LH.TraceEvent}} options + */ + static computeNavigationTimingsForFrame(frameEvents, options) { + const { timeOriginEvt } = options; + const firstPaint = frameEvents.find((e) => e.name === "firstPaint" && e.ts > timeOriginEvt.ts); + const firstContentfulPaint = frameEvents.find( + (e) => e.name === "firstContentfulPaint" && e.ts > timeOriginEvt.ts + ); + if (!firstContentfulPaint) { + throw this.createNoFirstContentfulPaintError(); + } + const lcpResult = this.computeValidLCPAllFrames(frameEvents, timeOriginEvt); + const load = frameEvents.find((e) => e.name === "loadEventEnd" && e.ts > timeOriginEvt.ts); + const domContentLoaded = frameEvents.find( + (e) => e.name === "domContentLoadedEventEnd" && e.ts > timeOriginEvt.ts + ); + const getTimestamp = /* @__PURE__ */ __name((event) => event?.ts, "getTimestamp"); + const timestamps = { + timeOrigin: timeOriginEvt.ts, + firstPaint: getTimestamp(firstPaint), + firstContentfulPaint: firstContentfulPaint.ts, + largestContentfulPaint: getTimestamp(lcpResult.lcp), + load: getTimestamp(load), + domContentLoaded: getTimestamp(domContentLoaded) + }; + const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, "getTiming"); + const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), "maybeGetTiming"); + const timings = { + timeOrigin: 0, + firstPaint: maybeGetTiming(timestamps.firstPaint), + firstContentfulPaint: getTiming(timestamps.firstContentfulPaint), + largestContentfulPaint: maybeGetTiming(timestamps.largestContentfulPaint), + load: maybeGetTiming(timestamps.load), + domContentLoaded: maybeGetTiming(timestamps.domContentLoaded) + }; + return { + timings, + timestamps, + timeOriginEvt, + firstPaintEvt: firstPaint, + firstContentfulPaintEvt: firstContentfulPaint, + largestContentfulPaintEvt: lcpResult.lcp, + loadEvt: load, + domContentLoadedEvt: domContentLoaded, + lcpInvalidated: lcpResult.invalidated + }; + } + }; + } +}); + +// core/gather/gatherers/trace.js +var trace_exports = {}; +__export(trace_exports, { + default: () => trace_default +}); +var Trace, trace_default; +var init_trace = __esm({ + "core/gather/gatherers/trace.js"() { + "use strict"; + init_process_global(); + init_base_gatherer(); + init_trace_processor(); + /** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + Trace = class _Trace extends base_gatherer_default { + static { + __name(this, "Trace"); + } + /** @type {LH.Trace} */ + _trace = { traceEvents: [] }; + static getDefaultTraceCategories() { + return [ + // Exclude default categories. We'll be selective to minimize trace size + "-*", + // Used instead of 'toplevel' in Chrome 71+ + "disabled-by-default-lighthouse", + // Used for Cumulative Layout Shift metric + "loading", + // All compile/execute events are captured by parent events in devtools.timeline.. + // But the v8 category provides some nice context for only <0.5% of the trace size + "v8", + // Same situation here. This category is there for RunMicrotasks only, but with other teams + // accidentally excluding microtasks, we don't want to assume a parent event will always exist + "v8.execute", + // For extracting UserTiming marks/measures + "blink.user_timing", + // Not mandatory but not used much + "blink.console", + // Most of the events we need are from these two categories + "devtools.timeline", + "disabled-by-default-devtools.timeline", + // Up to 450 (https://goo.gl/rBfhn4) JPGs added to the trace + "disabled-by-default-devtools.screenshot", + // This doesn't add its own events, but adds a `stackTrace` property to devtools.timeline events + "disabled-by-default-devtools.timeline.stack", + // Additional categories used by devtools. Not used by Lighthouse, but included to facilitate + // loading traces from Lighthouse into the Performance panel. + "disabled-by-default-devtools.timeline.frame", + "latencyInfo", + // Enhanced traces. + "disabled-by-default-devtools.target-rundown", + "disabled-by-default-devtools.v8-source-rundown-sources", + "disabled-by-default-devtools.v8-source-rundown", + // Required for Baseline Audit to detect feature usage. + "blink.webdx_feature_usage" + // Not used by Lighthouse (yet) but included for users that want JS samples when looking at + // a trace collected by Lighthouse (e.g. "View Trace" workflow in DevTools) + // TODO: Re-enable after investigating b/325659693 + // 'disabled-by-default-v8.cpu_profiler', + ]; + } + /** + * @param {LH.Gatherer.ProtocolSession} session + * @return {Promise} + */ + static async endTraceAndCollectEvents(session) { + const traceEvents = []; + const dataListener = /* @__PURE__ */ __name(function(data31) { + traceEvents.push(...data31.value); + }, "dataListener"); + session.on("Tracing.dataCollected", dataListener); + return new Promise((resolve, reject) => { + session.once("Tracing.tracingComplete", (_) => { + session.off("Tracing.dataCollected", dataListener); + resolve({ traceEvents }); + }); + session.sendCommand("Tracing.end").catch(reject); + }); + } + static symbol = Symbol("Trace"); + /** @type {LH.Gatherer.GathererMeta} */ + meta = { + symbol: _Trace.symbol, + supportedModes: ["timespan", "navigation"] + }; + /** + * @param {LH.Gatherer.Context} passContext + */ + async startSensitiveInstrumentation({ driver, gatherMode, settings }) { + const traceCategories2 = _Trace.getDefaultTraceCategories().concat(settings.additionalTraceCategories || []); + await driver.defaultSession.sendCommand("Page.enable"); + await driver.defaultSession.sendCommand("Tracing.start", { + categories: traceCategories2.join(","), + options: "sampling-frequency=10000" + // 1000 is default and too slow. + }); + if (gatherMode === "timespan") { + await driver.defaultSession.sendCommand( + "Tracing.recordClockSyncMarker", + { syncId: TraceProcessor.TIMESPAN_MARKER_ID } + ); + } + } + /** + * @param {LH.Gatherer.Context} passContext + */ + async stopSensitiveInstrumentation({ driver }) { + this._trace = await _Trace.endTraceAndCollectEvents(driver.defaultSession); + } + getDebugData() { + return this._trace; + } + getArtifact() { + return this._trace; + } + }; + trace_default = Trace; + } +}); + +// node_modules/lodash-es/_freeGlobal.js +var freeGlobal, freeGlobal_default; +var init_freeGlobal = __esm({ + "node_modules/lodash-es/_freeGlobal.js"() { + init_process_global(); + freeGlobal = typeof global == "object" && global && global.Object === Object && global; + freeGlobal_default = freeGlobal; + } +}); + +// node_modules/lodash-es/_root.js +var freeSelf, root, root_default; +var init_root = __esm({ + "node_modules/lodash-es/_root.js"() { + init_process_global(); + init_freeGlobal(); + freeSelf = typeof self == "object" && self && self.Object === Object && self; + root = freeGlobal_default || freeSelf || Function("return this")(); + root_default = root; + } +}); + +// node_modules/lodash-es/_Symbol.js +var Symbol2, Symbol_default; +var init_Symbol = __esm({ + "node_modules/lodash-es/_Symbol.js"() { + init_process_global(); + init_root(); + Symbol2 = root_default.Symbol; + Symbol_default = Symbol2; + } +}); + +// node_modules/lodash-es/_getRawTag.js +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; + try { + value[symToStringTag] = void 0; + var unmasked = true; + } catch (e) { + } + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} +var objectProto, hasOwnProperty, nativeObjectToString, symToStringTag, getRawTag_default; +var init_getRawTag = __esm({ + "node_modules/lodash-es/_getRawTag.js"() { + init_process_global(); + init_Symbol(); + objectProto = Object.prototype; + hasOwnProperty = objectProto.hasOwnProperty; + nativeObjectToString = objectProto.toString; + symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0; + __name(getRawTag, "getRawTag"); + getRawTag_default = getRawTag; + } +}); + +// node_modules/lodash-es/_objectToString.js +function objectToString(value) { + return nativeObjectToString2.call(value); +} +var objectProto2, nativeObjectToString2, objectToString_default; +var init_objectToString = __esm({ + "node_modules/lodash-es/_objectToString.js"() { + init_process_global(); + objectProto2 = Object.prototype; + nativeObjectToString2 = objectProto2.toString; + __name(objectToString, "objectToString"); + objectToString_default = objectToString; + } +}); + +// node_modules/lodash-es/_baseGetTag.js +function baseGetTag(value) { + if (value == null) { + return value === void 0 ? undefinedTag : nullTag; + } + return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value); +} +var nullTag, undefinedTag, symToStringTag2, baseGetTag_default; +var init_baseGetTag = __esm({ + "node_modules/lodash-es/_baseGetTag.js"() { + init_process_global(); + init_Symbol(); + init_getRawTag(); + init_objectToString(); + nullTag = "[object Null]"; + undefinedTag = "[object Undefined]"; + symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0; + __name(baseGetTag, "baseGetTag"); + baseGetTag_default = baseGetTag; + } +}); + +// node_modules/lodash-es/isObjectLike.js +function isObjectLike(value) { + return value != null && typeof value == "object"; +} +var isObjectLike_default; +var init_isObjectLike = __esm({ + "node_modules/lodash-es/isObjectLike.js"() { + init_process_global(); + __name(isObjectLike, "isObjectLike"); + isObjectLike_default = isObjectLike; + } +}); + +// node_modules/lodash-es/isArray.js +var isArray, isArray_default; +var init_isArray = __esm({ + "node_modules/lodash-es/isArray.js"() { + init_process_global(); + isArray = Array.isArray; + isArray_default = isArray; + } +}); + +// node_modules/lodash-es/isObject.js +function isObject(value) { + var type = typeof value; + return value != null && (type == "object" || type == "function"); +} +var isObject_default; +var init_isObject = __esm({ + "node_modules/lodash-es/isObject.js"() { + init_process_global(); + __name(isObject, "isObject"); + isObject_default = isObject; + } +}); + +// node_modules/lodash-es/isFunction.js +function isFunction(value) { + if (!isObject_default(value)) { + return false; + } + var tag = baseGetTag_default(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} +var asyncTag, funcTag, genTag, proxyTag, isFunction_default; +var init_isFunction = __esm({ + "node_modules/lodash-es/isFunction.js"() { + init_process_global(); + init_baseGetTag(); + init_isObject(); + asyncTag = "[object AsyncFunction]"; + funcTag = "[object Function]"; + genTag = "[object GeneratorFunction]"; + proxyTag = "[object Proxy]"; + __name(isFunction, "isFunction"); + isFunction_default = isFunction; + } +}); + +// node_modules/lodash-es/_coreJsData.js +var coreJsData, coreJsData_default; +var init_coreJsData = __esm({ + "node_modules/lodash-es/_coreJsData.js"() { + init_process_global(); + init_root(); + coreJsData = root_default["__core-js_shared__"]; + coreJsData_default = coreJsData; + } +}); + +// node_modules/lodash-es/_isMasked.js +function isMasked(func) { + return !!maskSrcKey && maskSrcKey in func; +} +var maskSrcKey, isMasked_default; +var init_isMasked = __esm({ + "node_modules/lodash-es/_isMasked.js"() { + init_process_global(); + init_coreJsData(); + maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData_default && coreJsData_default.keys && coreJsData_default.keys.IE_PROTO || ""); + return uid ? "Symbol(src)_1." + uid : ""; + })(); + __name(isMasked, "isMasked"); + isMasked_default = isMasked; + } +}); + +// node_modules/lodash-es/_toSource.js +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) { + } + try { + return func + ""; + } catch (e) { + } + } + return ""; +} +var funcProto, funcToString, toSource_default; +var init_toSource = __esm({ + "node_modules/lodash-es/_toSource.js"() { + init_process_global(); + funcProto = Function.prototype; + funcToString = funcProto.toString; + __name(toSource, "toSource"); + toSource_default = toSource; + } +}); + +// node_modules/lodash-es/_baseIsNative.js +function baseIsNative(value) { + if (!isObject_default(value) || isMasked_default(value)) { + return false; + } + var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource_default(value)); +} +var reRegExpChar, reIsHostCtor, funcProto2, objectProto3, funcToString2, hasOwnProperty2, reIsNative, baseIsNative_default; +var init_baseIsNative = __esm({ + "node_modules/lodash-es/_baseIsNative.js"() { + init_process_global(); + init_isFunction(); + init_isMasked(); + init_isObject(); + init_toSource(); + reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + reIsHostCtor = /^\[object .+?Constructor\]$/; + funcProto2 = Function.prototype; + objectProto3 = Object.prototype; + funcToString2 = funcProto2.toString; + hasOwnProperty2 = objectProto3.hasOwnProperty; + reIsNative = RegExp( + "^" + funcToString2.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$" + ); + __name(baseIsNative, "baseIsNative"); + baseIsNative_default = baseIsNative; + } +}); + +// node_modules/lodash-es/_getValue.js +function getValue(object, key) { + return object == null ? void 0 : object[key]; +} +var getValue_default; +var init_getValue = __esm({ + "node_modules/lodash-es/_getValue.js"() { + init_process_global(); + __name(getValue, "getValue"); + getValue_default = getValue; + } +}); + +// node_modules/lodash-es/_getNative.js +function getNative(object, key) { + var value = getValue_default(object, key); + return baseIsNative_default(value) ? value : void 0; +} +var getNative_default; +var init_getNative = __esm({ + "node_modules/lodash-es/_getNative.js"() { + init_process_global(); + init_baseIsNative(); + init_getValue(); + __name(getNative, "getNative"); + getNative_default = getNative; + } +}); + +// node_modules/lodash-es/_WeakMap.js +var WeakMap2, WeakMap_default; +var init_WeakMap = __esm({ + "node_modules/lodash-es/_WeakMap.js"() { + init_process_global(); + init_getNative(); + init_root(); + WeakMap2 = getNative_default(root_default, "WeakMap"); + WeakMap_default = WeakMap2; + } +}); + +// node_modules/lodash-es/_isIndex.js +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); +} +var MAX_SAFE_INTEGER, reIsUint, isIndex_default; +var init_isIndex = __esm({ + "node_modules/lodash-es/_isIndex.js"() { + init_process_global(); + MAX_SAFE_INTEGER = 9007199254740991; + reIsUint = /^(?:0|[1-9]\d*)$/; + __name(isIndex, "isIndex"); + isIndex_default = isIndex; + } +}); + +// node_modules/lodash-es/eq.js +function eq(value, other) { + return value === other || value !== value && other !== other; +} +var eq_default; +var init_eq = __esm({ + "node_modules/lodash-es/eq.js"() { + init_process_global(); + __name(eq, "eq"); + eq_default = eq; + } +}); + +// node_modules/lodash-es/isLength.js +function isLength(value) { + return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER2; +} +var MAX_SAFE_INTEGER2, isLength_default; +var init_isLength = __esm({ + "node_modules/lodash-es/isLength.js"() { + init_process_global(); + MAX_SAFE_INTEGER2 = 9007199254740991; + __name(isLength, "isLength"); + isLength_default = isLength; + } +}); + +// node_modules/lodash-es/isArrayLike.js +function isArrayLike(value) { + return value != null && isLength_default(value.length) && !isFunction_default(value); +} +var isArrayLike_default; +var init_isArrayLike = __esm({ + "node_modules/lodash-es/isArrayLike.js"() { + init_process_global(); + init_isFunction(); + init_isLength(); + __name(isArrayLike, "isArrayLike"); + isArrayLike_default = isArrayLike; + } +}); + +// node_modules/lodash-es/_isPrototype.js +function isPrototype(value) { + var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto4; + return value === proto; +} +var objectProto4, isPrototype_default; +var init_isPrototype = __esm({ + "node_modules/lodash-es/_isPrototype.js"() { + init_process_global(); + objectProto4 = Object.prototype; + __name(isPrototype, "isPrototype"); + isPrototype_default = isPrototype; + } +}); + +// node_modules/lodash-es/_baseTimes.js +function baseTimes(n, iteratee) { + var index = -1, result = Array(n); + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} +var baseTimes_default; +var init_baseTimes = __esm({ + "node_modules/lodash-es/_baseTimes.js"() { + init_process_global(); + __name(baseTimes, "baseTimes"); + baseTimes_default = baseTimes; + } +}); + +// node_modules/lodash-es/_baseIsArguments.js +function baseIsArguments(value) { + return isObjectLike_default(value) && baseGetTag_default(value) == argsTag; +} +var argsTag, baseIsArguments_default; +var init_baseIsArguments = __esm({ + "node_modules/lodash-es/_baseIsArguments.js"() { + init_process_global(); + init_baseGetTag(); + init_isObjectLike(); + argsTag = "[object Arguments]"; + __name(baseIsArguments, "baseIsArguments"); + baseIsArguments_default = baseIsArguments; + } +}); + +// node_modules/lodash-es/isArguments.js +var objectProto5, hasOwnProperty3, propertyIsEnumerable, isArguments, isArguments_default; +var init_isArguments = __esm({ + "node_modules/lodash-es/isArguments.js"() { + init_process_global(); + init_baseIsArguments(); + init_isObjectLike(); + objectProto5 = Object.prototype; + hasOwnProperty3 = objectProto5.hasOwnProperty; + propertyIsEnumerable = objectProto5.propertyIsEnumerable; + isArguments = baseIsArguments_default(/* @__PURE__ */ (function() { + return arguments; + })()) ? baseIsArguments_default : function(value) { + return isObjectLike_default(value) && hasOwnProperty3.call(value, "callee") && !propertyIsEnumerable.call(value, "callee"); + }; + isArguments_default = isArguments; + } +}); + +// node_modules/lodash-es/stubFalse.js +function stubFalse() { + return false; +} +var stubFalse_default; +var init_stubFalse = __esm({ + "node_modules/lodash-es/stubFalse.js"() { + init_process_global(); + __name(stubFalse, "stubFalse"); + stubFalse_default = stubFalse; + } +}); + +// node_modules/lodash-es/isBuffer.js +var freeExports, freeModule, moduleExports, Buffer2, nativeIsBuffer, isBuffer, isBuffer_default; +var init_isBuffer = __esm({ + "node_modules/lodash-es/isBuffer.js"() { + init_process_global(); + init_root(); + init_stubFalse(); + freeExports = typeof exports == "object" && exports && !exports.nodeType && exports; + freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module; + moduleExports = freeModule && freeModule.exports === freeExports; + Buffer2 = moduleExports ? root_default.Buffer : void 0; + nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0; + isBuffer = nativeIsBuffer || stubFalse_default; + isBuffer_default = isBuffer; + } +}); + +// node_modules/lodash-es/_baseIsTypedArray.js +function baseIsTypedArray(value) { + return isObjectLike_default(value) && isLength_default(value.length) && !!typedArrayTags[baseGetTag_default(value)]; +} +var argsTag2, arrayTag, boolTag, dateTag, errorTag, funcTag2, mapTag, numberTag, objectTag, regexpTag, setTag, stringTag, weakMapTag, arrayBufferTag, dataViewTag, float32Tag, float64Tag, int8Tag, int16Tag, int32Tag, uint8Tag, uint8ClampedTag, uint16Tag, uint32Tag, typedArrayTags, baseIsTypedArray_default; +var init_baseIsTypedArray = __esm({ + "node_modules/lodash-es/_baseIsTypedArray.js"() { + init_process_global(); + init_baseGetTag(); + init_isLength(); + init_isObjectLike(); + argsTag2 = "[object Arguments]"; + arrayTag = "[object Array]"; + boolTag = "[object Boolean]"; + dateTag = "[object Date]"; + errorTag = "[object Error]"; + funcTag2 = "[object Function]"; + mapTag = "[object Map]"; + numberTag = "[object Number]"; + objectTag = "[object Object]"; + regexpTag = "[object RegExp]"; + setTag = "[object Set]"; + stringTag = "[object String]"; + weakMapTag = "[object WeakMap]"; + arrayBufferTag = "[object ArrayBuffer]"; + dataViewTag = "[object DataView]"; + float32Tag = "[object Float32Array]"; + float64Tag = "[object Float64Array]"; + int8Tag = "[object Int8Array]"; + int16Tag = "[object Int16Array]"; + int32Tag = "[object Int32Array]"; + uint8Tag = "[object Uint8Array]"; + uint8ClampedTag = "[object Uint8ClampedArray]"; + uint16Tag = "[object Uint16Array]"; + uint32Tag = "[object Uint32Array]"; + typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag2] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag2] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + __name(baseIsTypedArray, "baseIsTypedArray"); + baseIsTypedArray_default = baseIsTypedArray; + } +}); + +// node_modules/lodash-es/_baseUnary.js function baseUnary(func) { return function(value) { return func(value); @@ -8993,7 +9833,7 @@ var require_amp = __commonJS({ "node_modules/lighthouse-stack-packs/packs/amp.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using WebP in the context of AMP. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "modern-image-formats": "Consider displaying all [`amp-img`](https://amp.dev/documentation/components/amp-img/?format=websites) components in WebP formats while specifying an appropriate fallback for other browsers. [Learn more](https://amp.dev/documentation/components/amp-img/#example:-specifying-a-fallback-image).", /** Additional description of a Lighthouse audit that tells the user how images are automatically lazy loaded for the AMP framewok. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9011,7 +9851,7 @@ var require_amp = __commonJS({ id: "amp", title: "AMP", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9021,7 +9861,7 @@ var require_angular = __commonJS({ "node_modules/lighthouse-stack-packs/packs/angular.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "total-byte-weight": "Apply [route-level code splitting](https://web.dev/route-level-code-splitting-in-angular/) to minimize the size of your JavaScript bundles. Also, consider precaching assets with the [Angular service worker](https://web.dev/precaching-with-the-angular-service-worker/).", /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS and JS files in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9039,7 +9879,7 @@ var require_angular = __commonJS({ id: "angular", title: "Angular", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9049,7 +9889,7 @@ var require_drupal = __commonJS({ "node_modules/lighthouse-stack-packs/packs/drupal.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "unused-css-rules": "Consider removing unused CSS rules and only attach the needed `Drupal` libraries to the relevant page or component in a page. See the [`Drupal` documentation](https://www.drupal.org/docs/develop/theming-drupal/adding-assets-css-js-to-a-drupal-theme-via-librariesyml#define) for details. To identify attached libraries that are adding extraneous CSS, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage) in Chrome DevTools. You can identify the theme/module responsible from the URL of the stylesheet when CSS aggregation is disabled in your `Drupal` site. Look out for themes/modules that have many stylesheets in the list which have a lot of red in code coverage. A theme/module should only attach a stylesheet library if it is actually used on the page.", /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9089,7 +9929,7 @@ var require_drupal = __commonJS({ id: "drupal", title: "Drupal", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9099,7 +9939,7 @@ var require_ezoic = __commonJS({ "node_modules/lighthouse-stack-packs/packs/ezoic.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Remove Unused CSS is a setting name. */ "unused-css-rules": "Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Remove Unused CSS` to help with this issue. It will identify the CSS classes that are actually used on each page of your site, and remove any others to keep the file size small.", /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Next-Gen Formats is a setting name.*/ @@ -9131,7 +9971,7 @@ var require_ezoic = __commonJS({ id: "ezoic", title: "Ezoic", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9141,7 +9981,7 @@ var require_gatsby = __commonJS({ "node_modules/lighthouse-stack-packs/packs/gatsby.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can remove unused CSS rules by configuring the Gatsby plugin `gatsby-plugin-purgecss` which sets up PurgeCSS */ "unused-css-rules": "Use the `PurgeCSS` `Gatsby` plugin to remove unused rules from stylesheets. [Learn more](https://purgecss.com/plugins/gatsby.html).", /** Additional description of a Lighthouse audit that tells the user to use the gatsby-plugin-image component to automatically optimize image format */ @@ -9165,7 +10005,7 @@ var require_gatsby = __commonJS({ id: "gatsby", title: "Gatsby", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9182,7 +10022,7 @@ var require_joomla = __commonJS({ */ var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "unused-css-rules": "Consider reducing, or switching, the number of [Joomla extensions](https://extensions.joomla.org/) loading unused CSS in your page. To identify extensions that are adding extraneous CSS, try running [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. You can identify the theme/plugin responsible from the URL of the stylesheet. Look out for plugins that have many stylesheets in the list which have a lot of red in code coverage. A plugin should only enqueue a stylesheet if it is actually used on the page.", /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9216,7 +10056,7 @@ var require_joomla = __commonJS({ id: "joomla", title: "Joomla", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9226,7 +10066,7 @@ var require_magento = __commonJS({ "node_modules/lighthouse-stack-packs/packs/magento.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "modern-image-formats": "Consider searching the [Magento Marketplace](https://marketplace.magento.com/catalogsearch/result/?q=webp) for a variety of third-party extensions to leverage newer image formats.", /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9256,7 +10096,7 @@ var require_magento = __commonJS({ id: "magento", title: "Magento", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9267,7 +10107,7 @@ var require_next = __commonJS({ init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can remove unusused CSS rules by configuring a plugin named PurgeCSS. */ "unused-css-rules": "Consider setting up `PurgeCSS` in `Next.js` configuration to remove unused rules from stylesheets. [Learn more](https://purgecss.com/guides/next.html).", /** Additional description of a Lighthouse audit that tells the user to use the next/image component to automatically optimize image format. */ @@ -9297,7 +10137,7 @@ var require_next = __commonJS({ id: "next.js", title: "Next.js", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9309,7 +10149,7 @@ var require_nitropack = __commonJS({ var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Reduce Unused CSS` is the name of a feature and becomes link text to additional documentation.*/ "unused-css-rules": "Enable [`Reduce Unused CSS`](https://support.nitropack.io/hc/en-us/articles/360020418457-Reduce-Unused-CSS) to remove CSS rules that are not applicable to this page.", /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Image Optimization` is the name of a feature and becomes link text to additional documentation. `WebP` is the name of a standardized image format for the web.*/ @@ -9339,7 +10179,7 @@ var require_nitropack = __commonJS({ id: "nitropack", title: "NitroPack", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9349,7 +10189,7 @@ var require_nuxt = __commonJS({ "node_modules/lighthouse-stack-packs/packs/nuxt.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to serve modern formats like WebP. */ "modern-image-formats": 'Use the `nuxt/image` component and set `format="webp"`. [Learn more](https://image.nuxt.com/usage/nuxt-img#format).', /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to defer loading images which are not shown on screen. */ @@ -9367,7 +10207,7 @@ var require_nuxt = __commonJS({ id: "nuxt", title: "Nuxt", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9377,7 +10217,7 @@ var require_octobercms = __commonJS({ "node_modules/lighthouse-stack-packs/packs/octobercms.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "unused-css-rules": "Consider reviewing the [plugins](https://octobercms.com/plugins) loading unused CSS on the website. To identify plugins that add unnecessary CSS, run [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. Identify the theme/plugin responsible from the stylesheet URL. Look for plugins with many stylesheets with lots of red in code coverage. A plugin should only add a stylesheet if it is actually used on the web page.", /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9411,7 +10251,7 @@ var require_octobercms = __commonJS({ id: "octobercms", title: "October CMS", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9423,7 +10263,7 @@ var require_react = __commonJS({ var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "unminified-css": "If your build system minifies CSS files automatically, ensure that you are deploying the production build of your application. You can check this with the React Developer Tools extension. [Learn more](https://reactjs.org/docs/optimizing-performance.html#use-the-production-build).", /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ @@ -9443,7 +10283,7 @@ var require_react = __commonJS({ id: "react", title: "React", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9454,7 +10294,7 @@ var require_wix = __commonJS({ init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user to optimize image formats, in the context of the Wix CMS platform. */ "modern-image-formats": "Upload images using `Wix Media Manager` to ensure they are automatically served as WebP. Find [more ways to optimize](https://support.wix.com/en/article/site-performance-optimizing-your-media) your site's media.", /** Additional description of a Lighthouse audit that tells the user to defer loading of non-critical third-party libraries, in the context of the Wix CMS platform. */ @@ -9470,7 +10310,7 @@ var require_wix = __commonJS({ id: "wix", title: "Wix", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9480,7 +10320,7 @@ var require_wordpress = __commonJS({ "node_modules/lighthouse-stack-packs/packs/wordpress.js"(exports2, module2) { init_process_global(); var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */ "unused-css-rules": "Consider reducing, or switching, the number of [WordPress plugins](https://wordpress.org/plugins/) loading unused CSS in your page. To identify plugins that are adding extraneous CSS, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage/) in Chrome DevTools. You can identify the theme/plugin responsible from the URL of the stylesheet. Look out for plugins that have many stylesheets in the list which have a lot of red in code coverage. A plugin should only enqueue a stylesheet if it is actually used on the page.", /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. */ @@ -9514,7 +10354,7 @@ var require_wordpress = __commonJS({ id: "wordpress", title: "WordPress", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9526,7 +10366,7 @@ var require_wp_rocket = __commonJS({ var icon = `data:image/svg+xml,`; - var UIStrings125 = { + var UIStrings126 = { /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Remove Unused CSS is a name of the feature */ "unused-css-rules": `Enable [Remove Unused CSS](https://docs.wp-rocket.me/article/1529-remove-unused-css) in 'WP Rocket' to fix this issue. It reduces page size by removing all CSS and stylesheets that are not used while keeping only the used CSS for each page.`, /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. `Imagify` is an image optimization add-on */ @@ -9552,7 +10392,7 @@ var require_wp_rocket = __commonJS({ id: "wp-rocket", title: "WP Rocket", icon, - UIStrings: UIStrings125 + UIStrings: UIStrings126 }; } }); @@ -9821,6 +10661,7 @@ var init_root2 = __esm({ "speedline-core": "^1.4.3", "third-party-web": "^0.27.0", "tldts-icann": "^7.0.17", + "web-features": "^3.21.0", "ws": "^7.0.0", "yargs": "^17.3.1", "yargs-parser": "^21.0.0" @@ -10890,17 +11731,17 @@ var init_NetworkNode = __esm({ }); // node_modules/@paulirish/trace_engine/models/trace/lantern/graph/PageDependencyGraph.js -var SCHEDULABLE_TASK_TITLE_LH, SCHEDULABLE_TASK_TITLE_ALT1, SCHEDULABLE_TASK_TITLE_ALT2, SCHEDULABLE_TASK_TITLE_ALT3, SIGNIFICANT_DUR_THRESHOLD_MS, IGNORED_MIME_TYPES_REGEX, PageDependencyGraph; +var SCHEDULABLE_TASK_TITLE_LH2, SCHEDULABLE_TASK_TITLE_ALT12, SCHEDULABLE_TASK_TITLE_ALT22, SCHEDULABLE_TASK_TITLE_ALT32, SIGNIFICANT_DUR_THRESHOLD_MS, IGNORED_MIME_TYPES_REGEX, PageDependencyGraph; var init_PageDependencyGraph = __esm({ "node_modules/@paulirish/trace_engine/models/trace/lantern/graph/PageDependencyGraph.js"() { init_process_global(); init_core(); init_CPUNode(); init_NetworkNode(); - SCHEDULABLE_TASK_TITLE_LH = "RunTask"; - SCHEDULABLE_TASK_TITLE_ALT1 = "ThreadControllerImpl::RunTask"; - SCHEDULABLE_TASK_TITLE_ALT2 = "ThreadControllerImpl::DoWork"; - SCHEDULABLE_TASK_TITLE_ALT3 = "TaskQueueManager::ProcessTaskFromWorkQueue"; + SCHEDULABLE_TASK_TITLE_LH2 = "RunTask"; + SCHEDULABLE_TASK_TITLE_ALT12 = "ThreadControllerImpl::RunTask"; + SCHEDULABLE_TASK_TITLE_ALT22 = "ThreadControllerImpl::DoWork"; + SCHEDULABLE_TASK_TITLE_ALT32 = "TaskQueueManager::ProcessTaskFromWorkQueue"; SIGNIFICANT_DUR_THRESHOLD_MS = 10; IGNORED_MIME_TYPES_REGEX = /^video/; PageDependencyGraph = class _PageDependencyGraph { @@ -10959,7 +11800,7 @@ var init_PageDependencyGraph = __esm({ return { nodes, idToNodeMap, urlToNodeMap, frameIdToNodeMap }; } static isScheduleableTask(evt) { - return evt.name === SCHEDULABLE_TASK_TITLE_LH || evt.name === SCHEDULABLE_TASK_TITLE_ALT1 || evt.name === SCHEDULABLE_TASK_TITLE_ALT2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT3; + return evt.name === SCHEDULABLE_TASK_TITLE_LH2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT12 || evt.name === SCHEDULABLE_TASK_TITLE_ALT22 || evt.name === SCHEDULABLE_TASK_TITLE_ALT32; } /** * There should *always* be at least one top level event, having 0 typically means something is @@ -29168,1517 +30009,774 @@ function createLanternRequest(parsedTrace, workerThreads, request) { initiatorRequest: void 0 }; } -function chooseInitiatorRequest(request, requestsByURL) { - if (request.redirectSource) { - return request.redirectSource; - } - const initiatorURL = graph_exports.PageDependencyGraph.getNetworkInitiators(request)[0]; - let candidates = requestsByURL.get(initiatorURL) || []; - candidates = candidates.filter((c) => { - return c.responseHeadersEndTime <= request.rendererStartTime && c.finished && !c.failed; - }); - if (candidates.length > 1) { - const nonPrefetchCandidates = candidates.filter((cand) => cand.resourceType !== types_exports.NetworkRequestTypes.Other); - if (nonPrefetchCandidates.length) { - candidates = nonPrefetchCandidates; - } - } - if (candidates.length > 1) { - const sameFrameCandidates = candidates.filter((cand) => cand.frameId === request.frameId); - if (sameFrameCandidates.length) { - candidates = sameFrameCandidates; - } - } - if (candidates.length > 1 && request.initiator.type === "parser") { - const documentCandidates = candidates.filter((cand) => cand.resourceType === types_exports.NetworkRequestTypes.Document); - if (documentCandidates.length) { - candidates = documentCandidates; - } - } - if (candidates.length > 1) { - const linkPreloadCandidates = candidates.filter((c) => c.isLinkPreload); - if (linkPreloadCandidates.length) { - const nonPreloadCandidates = candidates.filter((c) => !c.isLinkPreload); - const allPreloaded = nonPreloadCandidates.every((c) => c.fromDiskCache || c.fromMemoryCache); - if (nonPreloadCandidates.length && allPreloaded) { - candidates = linkPreloadCandidates; - } - } - } - return candidates.length === 1 ? candidates[0] : null; -} -function linkInitiators(lanternRequests) { - const requestsByURL = /* @__PURE__ */ new Map(); - for (const request of lanternRequests) { - const requests = requestsByURL.get(request.url) || []; - requests.push(request); - requestsByURL.set(request.url, requests); - } - for (const request of lanternRequests) { - const initiatorRequest = chooseInitiatorRequest(request, requestsByURL); - if (initiatorRequest) { - request.initiatorRequest = initiatorRequest; - } - } -} -function createNetworkRequests(trace, data31, startTime = 0, endTime = Number.POSITIVE_INFINITY) { - const workerThreads = findWorkerThreads(trace); - const lanternRequestsNoRedirects = []; - for (const request of data31.NetworkRequests.byTime) { - if (request.ts >= startTime && request.ts < endTime) { - const lanternRequest = createLanternRequest(data31, workerThreads, request); - if (lanternRequest) { - lanternRequestsNoRedirects.push(lanternRequest); - } - } - } - const lanternRequests = []; - for (const request of [...lanternRequestsNoRedirects]) { - if (!request.rawRequest) { - continue; - } - const redirects = request.rawRequest.args.data.redirects; - if (!redirects.length) { - lanternRequests.push(request); - continue; - } - const requestChain = []; - for (const redirect of redirects) { - const redirectedRequest = structuredClone(request); - redirectedRequest.networkRequestTime = redirect.ts / 1e3; - redirectedRequest.rendererStartTime = redirectedRequest.networkRequestTime; - redirectedRequest.networkEndTime = (redirect.ts + redirect.dur) / 1e3; - redirectedRequest.responseHeadersEndTime = redirectedRequest.networkEndTime; - redirectedRequest.timing = { - requestTime: redirectedRequest.networkRequestTime / 1e3, - receiveHeadersStart: redirectedRequest.responseHeadersEndTime, - receiveHeadersEnd: redirectedRequest.responseHeadersEndTime, - proxyStart: -1, - proxyEnd: -1, - dnsStart: -1, - dnsEnd: -1, - connectStart: -1, - connectEnd: -1, - sslStart: -1, - sslEnd: -1, - sendStart: -1, - sendEnd: -1, - workerStart: -1, - workerReady: -1, - workerFetchStart: -1, - workerRespondWithSettled: -1, - pushStart: -1, - pushEnd: -1 - }; - redirectedRequest.url = redirect.url; - redirectedRequest.parsedURL = createParsedUrl(redirect.url); - redirectedRequest.statusCode = 302; - redirectedRequest.resourceType = void 0; - redirectedRequest.transferSize = 400; - requestChain.push(redirectedRequest); - lanternRequests.push(redirectedRequest); - } - requestChain.push(request); - lanternRequests.push(request); - for (let i = 0; i < requestChain.length; i++) { - const request2 = requestChain[i]; - if (i > 0) { - request2.redirectSource = requestChain[i - 1]; - request2.redirects = requestChain.slice(0, i); - } - if (i !== requestChain.length - 1) { - request2.redirectDestination = requestChain[i + 1]; - } - } - for (let i = 1; i < requestChain.length; i++) { - requestChain[i].requestId = `${requestChain[i - 1].requestId}:redirect`; - } - } - linkInitiators(lanternRequests); - return lanternRequests; -} -function collectMainThreadEvents(trace, data31) { - const Meta = data31.Meta; - const mainFramePids = Meta.mainFrameNavigations.length ? new Set(Meta.mainFrameNavigations.map((nav) => nav.pid)) : Meta.topLevelRendererIds; - const rendererPidToTid = /* @__PURE__ */ new Map(); - for (const pid of mainFramePids) { - const threads = Meta.threadsInProcess.get(pid) ?? []; - let found = false; - for (const [tid, thread] of threads) { - if (thread.args.name === "CrRendererMain") { - rendererPidToTid.set(pid, tid); - found = true; - break; - } +function chooseInitiatorRequest(request, requestsByURL) { + if (request.redirectSource) { + return request.redirectSource; + } + const initiatorURL = graph_exports.PageDependencyGraph.getNetworkInitiators(request)[0]; + let candidates = requestsByURL.get(initiatorURL) || []; + candidates = candidates.filter((c) => { + return c.responseHeadersEndTime <= request.rendererStartTime && c.finished && !c.failed; + }); + if (candidates.length > 1) { + const nonPrefetchCandidates = candidates.filter((cand) => cand.resourceType !== types_exports.NetworkRequestTypes.Other); + if (nonPrefetchCandidates.length) { + candidates = nonPrefetchCandidates; } - if (found) { - continue; + } + if (candidates.length > 1) { + const sameFrameCandidates = candidates.filter((cand) => cand.frameId === request.frameId); + if (sameFrameCandidates.length) { + candidates = sameFrameCandidates; } - for (const [tid, thread] of threads) { - if (thread.args.name === "CrBrowserMain") { - rendererPidToTid.set(pid, tid); - found = true; - break; - } + } + if (candidates.length > 1 && request.initiator.type === "parser") { + const documentCandidates = candidates.filter((cand) => cand.resourceType === types_exports.NetworkRequestTypes.Document); + if (documentCandidates.length) { + candidates = documentCandidates; } } - return trace.traceEvents.filter((e) => rendererPidToTid.get(e.pid) === e.tid); -} -function createGraph(requests, trace, data31, url) { - const mainThreadEvents = collectMainThreadEvents(trace, data31); - if (!url) { - url = { - requestedUrl: requests[0].url, - mainDocumentUrl: "" - }; - let request = requests[0]; - while (request.redirectDestination) { - request = request.redirectDestination; + if (candidates.length > 1) { + const linkPreloadCandidates = candidates.filter((c) => c.isLinkPreload); + if (linkPreloadCandidates.length) { + const nonPreloadCandidates = candidates.filter((c) => !c.isLinkPreload); + const allPreloaded = nonPreloadCandidates.every((c) => c.fromDiskCache || c.fromMemoryCache); + if (nonPreloadCandidates.length && allPreloaded) { + candidates = linkPreloadCandidates; + } } - url.mainDocumentUrl = request.url; } - return graph_exports.PageDependencyGraph.createGraph(mainThreadEvents, requests, url); + return candidates.length === 1 ? candidates[0] : null; } -var init_LanternComputationData = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/LanternComputationData.js"() { - init_process_global(); - init_handlers(); - init_lantern(); - __name(createProcessedNavigation, "createProcessedNavigation"); - __name(createParsedUrl, "createParsedUrl"); - __name(findWorkerThreads, "findWorkerThreads"); - __name(createLanternRequest, "createLanternRequest"); - __name(chooseInitiatorRequest, "chooseInitiatorRequest"); - __name(linkInitiators, "linkInitiators"); - __name(createNetworkRequests, "createNetworkRequests"); - __name(collectMainThreadEvents, "collectMainThreadEvents"); - __name(createGraph, "createGraph"); +function linkInitiators(lanternRequests) { + const requestsByURL = /* @__PURE__ */ new Map(); + for (const request of lanternRequests) { + const requests = requestsByURL.get(request.url) || []; + requests.push(request); + requestsByURL.set(request.url, requests); } -}); - -// node_modules/@paulirish/trace_engine/models/trace/Processor.js -function calculateProgress(value, phase) { - if (phase === 0.8) { - return value * (0.8 - 0.2) + 0.2; + for (const request of lanternRequests) { + const initiatorRequest = chooseInitiatorRequest(request, requestsByURL); + if (initiatorRequest) { + request.initiatorRequest = initiatorRequest; + } } - return value * phase; } -function sortHandlers(traceHandlers) { - const sortedMap = /* @__PURE__ */ new Map(); - const visited = /* @__PURE__ */ new Set(); - const visitHandler = /* @__PURE__ */ __name((handlerName) => { - if (sortedMap.has(handlerName)) { - return; - } - if (visited.has(handlerName)) { - let stackPath = ""; - for (const handler2 of visited) { - if (stackPath || handler2 === handlerName) { - stackPath += `${handler2}->`; - } +function createNetworkRequests(trace, data31, startTime = 0, endTime = Number.POSITIVE_INFINITY) { + const workerThreads = findWorkerThreads(trace); + const lanternRequestsNoRedirects = []; + for (const request of data31.NetworkRequests.byTime) { + if (request.ts >= startTime && request.ts < endTime) { + const lanternRequest = createLanternRequest(data31, workerThreads, request); + if (lanternRequest) { + lanternRequestsNoRedirects.push(lanternRequest); } - stackPath += handlerName; - throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`); - } - visited.add(handlerName); - const handler = traceHandlers[handlerName]; - if (!handler) { - return; - } - const deps17 = handler.deps?.(); - if (deps17) { - deps17.forEach(visitHandler); } - sortedMap.set(handlerName, handler); - }, "visitHandler"); - for (const handlerName of Object.keys(traceHandlers)) { - visitHandler(handlerName); } - return sortedMap; -} -var _a2, TraceParseProgressEvent, TraceProcessor; -var init_Processor = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/Processor.js"() { - init_process_global(); - init_handlers(); - init_helpers2(); - init_insights(); - init_lantern(); - init_LanternComputationData(); - init_types2(); - TraceParseProgressEvent = class _TraceParseProgressEvent extends Event { - static { - __name(this, "TraceParseProgressEvent"); - } - data; - static eventName = "traceparseprogress"; - constructor(data31, init2 = { bubbles: true }) { - super(_TraceParseProgressEvent.eventName, init2); - this.data = data31; - } - }; - __name(calculateProgress, "calculateProgress"); - TraceProcessor = class extends EventTarget { - static { - __name(this, "TraceProcessor"); - } - // We force the Meta handler to be enabled, so the TraceHandlers type here is - // the model handlers the user passes in and the Meta handler. - #traceHandlers; - #status = "IDLE"; - #modelConfiguration = Configuration_exports.defaults(); - #data = null; - #insights = null; - static createWithAllHandlers() { - return new _a2(ModelHandlers_exports, Configuration_exports.defaults()); - } - /** - * This function is kept for testing with `stub`. - */ - static getInsightRunners() { - return { ...Models_exports }; - } - constructor(traceHandlers, modelConfiguration) { - super(); - this.#verifyHandlers(traceHandlers); - this.#traceHandlers = { - Meta: ModelHandlers_exports.Meta, - ...traceHandlers - }; - if (modelConfiguration) { - this.#modelConfiguration = modelConfiguration; - } - this.#passConfigToHandlers(); - } - #passConfigToHandlers() { - for (const handler of Object.values(this.#traceHandlers)) { - if ("handleUserConfig" in handler && handler.handleUserConfig) { - handler.handleUserConfig(this.#modelConfiguration); - } - } - } - /** - * When the user passes in a set of handlers, we want to ensure that we have all - * the required handlers. Handlers can depend on other handlers, so if the user - * passes in FooHandler which depends on BarHandler, they must also pass in - * BarHandler too. This method verifies that all dependencies are met, and - * throws if not. - **/ - #verifyHandlers(providedHandlers) { - if (Object.keys(providedHandlers).length === Object.keys(ModelHandlers_exports).length) { - return; - } - const requiredHandlerKeys = /* @__PURE__ */ new Set(); - for (const [handlerName, handler] of Object.entries(providedHandlers)) { - requiredHandlerKeys.add(handlerName); - const deps17 = "deps" in handler ? handler.deps() : []; - for (const depName of deps17) { - requiredHandlerKeys.add(depName); - } - } - const providedHandlerKeys = new Set(Object.keys(providedHandlers)); - requiredHandlerKeys.delete("Meta"); - for (const requiredKey of requiredHandlerKeys) { - if (!providedHandlerKeys.has(requiredKey)) { - throw new Error(`Required handler ${requiredKey} not provided.`); - } - } - } - reset() { - if (this.#status === "PARSING") { - throw new Error("Trace processor can't reset while parsing."); - } - const handlers = Object.values(this.#traceHandlers); - for (const handler of handlers) { - handler.reset(); - } - this.#data = null; - this.#insights = null; - this.#status = "IDLE"; - } - async parse(traceEvents, options) { - if (this.#status !== "IDLE") { - throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`); - } - if (typeof options.isCPUProfile === "undefined" && options.metadata) { - options.isCPUProfile = options.metadata.dataOrigin === File_exports.DataOrigin.CPU_PROFILE; - } - options.logger?.start("total"); - try { - this.#status = "PARSING"; - options.logger?.start("parse"); - await this.#computeParsedTrace(traceEvents, options); - options.logger?.end("parse"); - if (this.#data && !options.isCPUProfile) { - options.logger?.start("insights"); - this.#computeInsights(this.#data, traceEvents, options); - options.logger?.end("insights"); - } - this.#status = "FINISHED_PARSING"; - } catch (e) { - this.#status = "ERRORED_WHILE_PARSING"; - throw e; - } finally { - options.logger?.end("total"); - } - } - /** - * Run all the handlers and set the result to `#data`. - */ - async #computeParsedTrace(traceEvents, options) { - const eventsPerChunk = 5e4; - const sortedHandlers = [...sortHandlers(this.#traceHandlers).entries()]; - for (const [, handler] of sortedHandlers) { - handler.reset(); - } - options.logger?.start("parse:handleEvent"); - for (let i = 0; i < traceEvents.length; ++i) { - if (i % eventsPerChunk === 0 && i) { - const percent = calculateProgress( - i / traceEvents.length, - 0.2 - /* ProgressPhase.HANDLE_EVENT */ - ); - this.dispatchEvent(new TraceParseProgressEvent({ percent })); - await new Promise((resolve) => setTimeout(resolve, 0)); - } - const event = traceEvents[i]; - for (let j = 0; j < sortedHandlers.length; ++j) { - const [, handler] = sortedHandlers[j]; - handler.handleEvent(event); - } - } - options.logger?.end("parse:handleEvent"); - const finalizeOptions = { - ...options, - allTraceEvents: traceEvents - }; - for (let i = 0; i < sortedHandlers.length; i++) { - const [name, handler] = sortedHandlers[i]; - if (handler.finalize) { - options.logger?.start(`parse:${name}:finalize`); - await new Promise((resolve) => setTimeout(resolve, 0)); - await handler.finalize(finalizeOptions); - options.logger?.end(`parse:${name}:finalize`); - } - const percent = calculateProgress( - i / sortedHandlers.length, - 0.8 - /* ProgressPhase.FINALIZE */ - ); - this.dispatchEvent(new TraceParseProgressEvent({ percent })); - } - options.logger?.start("parse:handler.data()"); - const parsedTrace = {}; - for (const [name, handler] of Object.entries(this.#traceHandlers)) { - Object.assign(parsedTrace, { [name]: handler.data() }); - } - options.logger?.end("parse:handler.data()"); - this.dispatchEvent(new TraceParseProgressEvent({ - percent: 1 - /* ProgressPhase.CLONE */ - })); - this.#data = parsedTrace; - } - get data() { - if (this.#status !== "FINISHED_PARSING") { - return null; - } - return this.#data; - } - get insights() { - if (this.#status !== "FINISHED_PARSING") { - return null; - } - return this.#insights; - } - #createLanternContext(data31, traceEvents, frameId, navigationId, options) { - if (!data31.NetworkRequests || !data31.Workers || !data31.PageLoadMetrics) { - return; - } - if (!data31.NetworkRequests.byTime.length) { - throw new core_exports.LanternError("No network requests found in trace"); - } - const navStarts = data31.Meta.navigationsByFrameId.get(frameId); - const navStartIndex = navStarts?.findIndex((n) => n.args.data?.navigationId === navigationId); - if (!navStarts || navStartIndex === void 0 || navStartIndex === -1) { - throw new core_exports.LanternError("Could not find navigation start"); - } - const startTime = navStarts[navStartIndex].ts; - const endTime = navStartIndex + 1 < navStarts.length ? navStarts[navStartIndex + 1].ts : Number.POSITIVE_INFINITY; - const boundedTraceEvents = traceEvents.filter((e) => e.ts >= startTime && e.ts < endTime); - const trace = { - traceEvents: boundedTraceEvents - }; - const requests = createNetworkRequests(trace, data31, startTime, endTime); - const graph2 = createGraph(requests, trace, data31); - const processedNavigation = createProcessedNavigation(data31, frameId, navigationId); - const networkAnalysis = core_exports.NetworkAnalyzer.analyze(requests); - if (!networkAnalysis) { - return; - } - const lanternSettings = { - // TODO(crbug.com/372674229): if devtools throttling was on, does this network analysis capture - // that? Do we need to set 'devtools' throttlingMethod? - networkAnalysis, - throttlingMethod: "provided", - ...options.lanternSettings - }; - const simulator = simulation_exports.Simulator.createSimulator(lanternSettings); - const computeData = { graph: graph2, simulator, processedNavigation }; - const fcpResult = metrics_exports.FirstContentfulPaint.compute(computeData); - const lcpResult = metrics_exports.LargestContentfulPaint.compute(computeData, { fcpResult }); - const interactiveResult = metrics_exports.Interactive.compute(computeData, { lcpResult }); - const tbtResult = metrics_exports.TotalBlockingTime.compute(computeData, { fcpResult, interactiveResult }); - const metrics = { - firstContentfulPaint: fcpResult, - interactive: interactiveResult, - largestContentfulPaint: lcpResult, - totalBlockingTime: tbtResult - }; - return { requests, graph: graph2, simulator, metrics }; - } - /** - * Sort the insight models based on the impact of each insight's estimated savings, additionally weighted by the - * worst metrics according to field data (if present). - */ - sortInsightSet(insightSet, metadata) { - const baselineOrder = { - INPBreakdown: null, - LCPBreakdown: null, - LCPDiscovery: null, - CLSCulprits: null, - RenderBlocking: null, - NetworkDependencyTree: null, - ImageDelivery: null, - DocumentLatency: null, - FontDisplay: null, - Viewport: null, - DOMSize: null, - ThirdParties: null, - DuplicatedJavaScript: null, - SlowCSSSelector: null, - ForcedReflow: null, - Cache: null, - ModernHTTP: null, - LegacyJavaScript: null - }; - const weights = Common_exports.calculateMetricWeightsForSorting(insightSet, metadata); - const observedLcpMicro = Common_exports.getLCP(insightSet)?.value; - const observedLcp = observedLcpMicro ? Timing_exports3.microToMilli(observedLcpMicro) : Timing_exports.Milli(0); - const observedCls = Common_exports.getCLS(insightSet).value; - const observedInpMicro = Common_exports.getINP(insightSet)?.value; - const observedInp = observedInpMicro ? Timing_exports3.microToMilli(observedInpMicro) : Timing_exports.Milli(200); - const observedLcpScore = observedLcp !== void 0 ? Common_exports.evaluateLCPMetricScore(observedLcp) : void 0; - const observedInpScore = Common_exports.evaluateINPMetricScore(observedInp); - const observedClsScore = Common_exports.evaluateCLSMetricScore(observedCls); - const insightToSortingRank = /* @__PURE__ */ new Map(); - for (const [name, model2] of Object.entries(insightSet.model)) { - const lcp = model2.metricSavings?.LCP ?? 0; - const inp = model2.metricSavings?.INP ?? 0; - const cls = model2.metricSavings?.CLS ?? 0; - const lcpPostSavings = observedLcp !== void 0 ? Math.max(0, observedLcp - lcp) : void 0; - const inpPostSavings = Math.max(0, observedInp - inp); - const clsPostSavings = Math.max(0, observedCls - cls); - let score = 0; - if (weights.lcp && lcp && observedLcpScore !== void 0 && lcpPostSavings !== void 0) { - score += weights.lcp * (Common_exports.evaluateLCPMetricScore(lcpPostSavings) - observedLcpScore); - } - if (weights.inp && inp && observedInpScore !== void 0) { - score += weights.inp * (Common_exports.evaluateINPMetricScore(inpPostSavings) - observedInpScore); - } - if (weights.cls && cls && observedClsScore !== void 0) { - score += weights.cls * (Common_exports.evaluateCLSMetricScore(clsPostSavings) - observedClsScore); - } - insightToSortingRank.set(name, score); - } - const baselineOrderKeys = Object.keys(baselineOrder); - const orderedKeys = Object.keys(insightSet.model); - orderedKeys.sort((a, b) => { - const a1 = baselineOrderKeys.indexOf(a); - const b1 = baselineOrderKeys.indexOf(b); - if (a1 >= 0 && b1 >= 0) { - return a1 - b1; - } - if (a1 >= 0) { - return -1; - } - if (b1 >= 0) { - return 1; - } - return 0; - }); - orderedKeys.sort((a, b) => (insightToSortingRank.get(b) ?? 0) - (insightToSortingRank.get(a) ?? 0)); - const newModel = {}; - for (const key of orderedKeys) { - const model2 = insightSet.model[key]; - newModel[key] = model2; - } - insightSet.model = newModel; - } - #computeInsightSet(data31, context) { - const logger = context.options.logger; - let id, urlString, navigation2; - if (context.navigation) { - id = context.navigationId; - urlString = data31.Meta.finalDisplayUrlByNavigationId.get(context.navigationId) ?? data31.Meta.mainFrameURL; - navigation2 = context.navigation; - } else { - id = TraceEvents_exports.NO_NAVIGATION; - urlString = data31.Meta.finalDisplayUrlByNavigationId.get("") ?? data31.Meta.mainFrameURL; - } - const insightSetModel = {}; - for (const [name, insight] of Object.entries(_a2.getInsightRunners())) { - let model2; - try { - logger?.start(`insights:${name}`); - model2 = insight.generateInsight(data31, context); - model2.frameId = context.frameId; - const navId = context.navigation?.args.data?.navigationId; - if (navId) { - model2.navigationId = navId; - } - model2.createOverlays = () => { - return insight.createOverlays(model2); - }; - } catch (err) { - model2 = err; - } finally { - logger?.end(`insights:${name}`); - } - Object.assign(insightSetModel, { [name]: model2 }); - } - const isNavigation = id === TraceEvents_exports.NO_NAVIGATION; - const trivialThreshold = Timing_exports3.milliToMicro(Timing_exports.Milli(5e3)); - const everyInsightPasses = Object.values(insightSetModel).filter((model2) => !(model2 instanceof Error)).every((model2) => model2.state === "pass"); - const noLcp = !insightSetModel.LCPBreakdown.lcpEvent; - const noInp = !insightSetModel.INPBreakdown.longestInteractionEvent; - const noLayoutShifts = insightSetModel.CLSCulprits.shifts?.size === 0; - const shouldExclude = isNavigation && context.bounds.range < trivialThreshold && everyInsightPasses && noLcp && noInp && noLayoutShifts; - if (shouldExclude) { - return; - } - let url; - try { - url = new URL(urlString); - } catch { - return; - } - const insightSet = { - id, - url, - navigation: navigation2, - frameId: context.frameId, - bounds: context.bounds, - model: insightSetModel - }; - if (!this.#insights) { - this.#insights = /* @__PURE__ */ new Map(); - } - this.#insights.set(insightSet.id, insightSet); - this.sortInsightSet(insightSet, context.options.metadata ?? null); + const lanternRequests = []; + for (const request of [...lanternRequestsNoRedirects]) { + if (!request.rawRequest) { + continue; + } + const redirects = request.rawRequest.args.data.redirects; + if (!redirects.length) { + lanternRequests.push(request); + continue; + } + const requestChain = []; + for (const redirect of redirects) { + const redirectedRequest = structuredClone(request); + redirectedRequest.networkRequestTime = redirect.ts / 1e3; + redirectedRequest.rendererStartTime = redirectedRequest.networkRequestTime; + redirectedRequest.networkEndTime = (redirect.ts + redirect.dur) / 1e3; + redirectedRequest.responseHeadersEndTime = redirectedRequest.networkEndTime; + redirectedRequest.timing = { + requestTime: redirectedRequest.networkRequestTime / 1e3, + receiveHeadersStart: redirectedRequest.responseHeadersEndTime, + receiveHeadersEnd: redirectedRequest.responseHeadersEndTime, + proxyStart: -1, + proxyEnd: -1, + dnsStart: -1, + dnsEnd: -1, + connectStart: -1, + connectEnd: -1, + sslStart: -1, + sslEnd: -1, + sendStart: -1, + sendEnd: -1, + workerStart: -1, + workerReady: -1, + workerFetchStart: -1, + workerRespondWithSettled: -1, + pushStart: -1, + pushEnd: -1 + }; + redirectedRequest.url = redirect.url; + redirectedRequest.parsedURL = createParsedUrl(redirect.url); + redirectedRequest.statusCode = 302; + redirectedRequest.resourceType = void 0; + redirectedRequest.transferSize = 400; + requestChain.push(redirectedRequest); + lanternRequests.push(redirectedRequest); + } + requestChain.push(request); + lanternRequests.push(request); + for (let i = 0; i < requestChain.length; i++) { + const request2 = requestChain[i]; + if (i > 0) { + request2.redirectSource = requestChain[i - 1]; + request2.redirects = requestChain.slice(0, i); } - /** - * Run all the insights and set the result to `#insights`. - */ - #computeInsights(data31, traceEvents, options) { - this.#insights = /* @__PURE__ */ new Map(); - const navigations = data31.Meta.mainFrameNavigations.filter((navigation2) => navigation2.args.frame && navigation2.args.data?.navigationId); - this.#computeInsightsForInitialTracePeriod(data31, navigations, options); - for (const [index, navigation2] of navigations.entries()) { - const min = navigation2.ts; - const max = index + 1 < navigations.length ? navigations[index + 1].ts : data31.Meta.traceBounds.max; - const bounds = Timing_exports3.traceWindowFromMicroSeconds(min, max); - this.#computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options); - } + if (i !== requestChain.length - 1) { + request2.redirectDestination = requestChain[i + 1]; } - /** - * Computes insights for the period before the first navigation, or for the entire trace if no navigations exist. - */ - #computeInsightsForInitialTracePeriod(data31, navigations, options) { - const bounds = navigations.length > 0 ? Timing_exports3.traceWindowFromMicroSeconds(data31.Meta.traceBounds.min, navigations[0].ts) : data31.Meta.traceBounds; - const context = { - options, - bounds, - frameId: data31.Meta.mainFrameId - // No navigation or lantern context applies to this initial/no-navigation period. - }; - this.#computeInsightSet(data31, context); + } + for (let i = 1; i < requestChain.length; i++) { + requestChain[i].requestId = `${requestChain[i - 1].requestId}:redirect`; + } + } + linkInitiators(lanternRequests); + return lanternRequests; +} +function collectMainThreadEvents(trace, data31) { + const Meta = data31.Meta; + const mainFramePids = Meta.mainFrameNavigations.length ? new Set(Meta.mainFrameNavigations.map((nav) => nav.pid)) : Meta.topLevelRendererIds; + const rendererPidToTid = /* @__PURE__ */ new Map(); + for (const pid of mainFramePids) { + const threads = Meta.threadsInProcess.get(pid) ?? []; + let found = false; + for (const [tid, thread] of threads) { + if (thread.args.name === "CrRendererMain") { + rendererPidToTid.set(pid, tid); + found = true; + break; } - /** - * Computes insights for a specific navigation event. - */ - #computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options) { - const frameId = navigation2.args.frame; - const navigationId = navigation2.args.data?.navigationId; - let lantern; - try { - options.logger?.start("insights:createLanternContext"); - lantern = this.#createLanternContext(data31, traceEvents, frameId, navigationId, options); - } catch (e) { - const expectedErrors = [ - "mainDocumentRequest not found", - "missing metric scores for main frame", - "missing metric: FCP", - "missing metric: LCP", - "No network requests found in trace", - "Trace is too old" - ]; - if (!(e instanceof core_exports.LanternError)) { - console.error(e); - } else if (!expectedErrors.some((err) => e.message === err)) { - console.error(e); - } - } finally { - options.logger?.end("insights:createLanternContext"); - } - const context = { - options, - bounds, - frameId, - navigation: navigation2, - navigationId, - lantern - }; - this.#computeInsightSet(data31, context); + } + if (found) { + continue; + } + for (const [tid, thread] of threads) { + if (thread.args.name === "CrBrowserMain") { + rendererPidToTid.set(pid, tid); + found = true; + break; } + } + } + return trace.traceEvents.filter((e) => rendererPidToTid.get(e.pid) === e.tid); +} +function createGraph(requests, trace, data31, url) { + const mainThreadEvents = collectMainThreadEvents(trace, data31); + if (!url) { + url = { + requestedUrl: requests[0].url, + mainDocumentUrl: "" }; - _a2 = TraceProcessor; - __name(sortHandlers, "sortHandlers"); + let request = requests[0]; + while (request.redirectDestination) { + request = request.redirectDestination; + } + url.mainDocumentUrl = request.url; } -}); - -// node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js -var init_ModelImpl = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js"() { + return graph_exports.PageDependencyGraph.createGraph(mainThreadEvents, requests, url); +} +var init_LanternComputationData = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/LanternComputationData.js"() { init_process_global(); - init_platform(); init_handlers(); - init_helpers2(); - init_Processor(); - init_types2(); - } -}); - -// node_modules/@paulirish/trace_engine/core/common/common.js -var init_common = __esm({ - "node_modules/@paulirish/trace_engine/core/common/common.js"() { - init_process_global(); + init_lantern(); + __name(createProcessedNavigation, "createProcessedNavigation"); + __name(createParsedUrl, "createParsedUrl"); + __name(findWorkerThreads, "findWorkerThreads"); + __name(createLanternRequest, "createLanternRequest"); + __name(chooseInitiatorRequest, "chooseInitiatorRequest"); + __name(linkInitiators, "linkInitiators"); + __name(createNetworkRequests, "createNetworkRequests"); + __name(collectMainThreadEvents, "collectMainThreadEvents"); + __name(createGraph, "createGraph"); } }); -// node_modules/@paulirish/trace_engine/models/trace/Styles.js -var EventCategory; -var init_Styles = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/Styles.js"() { - init_process_global(); - init_handlers(); - init_helpers2(); - init_types2(); - (function(EventCategory2) { - EventCategory2["DRAWING"] = "drawing"; - EventCategory2["RASTERIZING"] = "rasterizing"; - EventCategory2["LAYOUT"] = "layout"; - EventCategory2["LOADING"] = "loading"; - EventCategory2["EXPERIENCE"] = "experience"; - EventCategory2["SCRIPTING"] = "scripting"; - EventCategory2["MESSAGING"] = "messaging"; - EventCategory2["RENDERING"] = "rendering"; - EventCategory2["PAINTING"] = "painting"; - EventCategory2["GPU"] = "gpu"; - EventCategory2["ASYNC"] = "async"; - EventCategory2["OTHER"] = "other"; - EventCategory2["IDLE"] = "idle"; - })(EventCategory || (EventCategory = {})); +// node_modules/@paulirish/trace_engine/models/trace/Processor.js +function calculateProgress(value, phase) { + if (phase === 0.8) { + return value * (0.8 - 0.2) + 0.2; } -}); - -// node_modules/@paulirish/trace_engine/models/trace/Name.js -var init_Name = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/Name.js"() { - init_process_global(); - init_common(); - init_handlers(); - init_Styles(); - init_types2(); + return value * phase; +} +function sortHandlers(traceHandlers) { + const sortedMap = /* @__PURE__ */ new Map(); + const visited = /* @__PURE__ */ new Set(); + const visitHandler = /* @__PURE__ */ __name((handlerName) => { + if (sortedMap.has(handlerName)) { + return; + } + if (visited.has(handlerName)) { + let stackPath = ""; + for (const handler2 of visited) { + if (stackPath || handler2 === handlerName) { + stackPath += `${handler2}->`; + } + } + stackPath += handlerName; + throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`); + } + visited.add(handlerName); + const handler = traceHandlers[handlerName]; + if (!handler) { + return; + } + const deps17 = handler.deps?.(); + if (deps17) { + deps17.forEach(visitHandler); + } + sortedMap.set(handlerName, handler); + }, "visitHandler"); + for (const handlerName of Object.keys(traceHandlers)) { + visitHandler(handlerName); } -}); - -// node_modules/@paulirish/trace_engine/models/trace/trace.js -var init_trace2 = __esm({ - "node_modules/@paulirish/trace_engine/models/trace/trace.js"() { + return sortedMap; +} +var _a2, TraceParseProgressEvent, TraceProcessor2; +var init_Processor = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/Processor.js"() { init_process_global(); - init_EntityMapper(); - init_EventsSerializer(); - init_extras(); init_handlers(); init_helpers2(); init_insights(); init_lantern(); - init_LanternComputationData(); - init_ModelImpl(); - init_Name(); - init_Processor(); - init_Styles(); - init_types2(); - } -}); - -// core/lib/lantern/lantern.js -var init_lantern2 = __esm({ - "core/lib/lantern/lantern.js"() { - "use strict"; - init_process_global(); - init_lantern(); - init_trace2(); - /** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - } -}); - -// core/lib/tracehouse/trace-processor.js -var ACCEPTABLE_NAVIGATION_URL_REGEX, BASE_RESPONSE_LATENCY, SCHEDULABLE_TASK_TITLE_LH2, SCHEDULABLE_TASK_TITLE_ALT12, SCHEDULABLE_TASK_TITLE_ALT22, SCHEDULABLE_TASK_TITLE_ALT32, TraceProcessor2; -var init_trace_processor = __esm({ - "core/lib/tracehouse/trace-processor.js"() { - "use strict"; - init_process_global(); - init_lighthouse_logger(); - /** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - ACCEPTABLE_NAVIGATION_URL_REGEX = /^(chrome|https?):/; - BASE_RESPONSE_LATENCY = 16; - SCHEDULABLE_TASK_TITLE_LH2 = "RunTask"; - SCHEDULABLE_TASK_TITLE_ALT12 = "ThreadControllerImpl::RunTask"; - SCHEDULABLE_TASK_TITLE_ALT22 = "ThreadControllerImpl::DoWork"; - SCHEDULABLE_TASK_TITLE_ALT32 = "TaskQueueManager::ProcessTaskFromWorkQueue"; - TraceProcessor2 = class _TraceProcessor { - static { - __name(this, "TraceProcessor"); - } - static get TIMESPAN_MARKER_ID() { - return "__lighthouseTimespanStart__"; - } - /** - * @return {Error} - */ - static createNoNavstartError() { - return new Error("No navigationStart event found"); - } - /** - * @return {Error} - */ - static createNoResourceSendRequestError() { - return new Error("No ResourceSendRequest event found"); - } - /** - * @return {Error} - */ - static createNoTracingStartedError() { - return new Error("No tracingStartedInBrowser event found"); - } - /** - * @return {Error} - */ - static createNoFirstContentfulPaintError() { - return new Error("No FirstContentfulPaint event found"); - } - /** - * @return {Error} - */ - static createNoLighthouseMarkerError() { - return new Error("No Lighthouse timespan marker event found"); - } - /** - * Returns true if the event is a navigation start event of a document whose URL seems valid. - * - * @param {LH.TraceEvent} event - * @return {boolean} - */ - static _isNavigationStartOfInterest(event) { - if (event.name !== "navigationStart") return false; - if (event.args.data?.documentLoaderURL === void 0) return true; - if (!event.args.data?.documentLoaderURL) return false; - return ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL); - } - /** - * This method sorts a group of trace events that have the same timestamp. We want to... - * - * 1. Put E events first, we finish off our existing events before we start new ones. - * 2. Order B/X events by their duration, we want parents to start before child events. - * 3. If we don't have any of this to go on, just use the position in the original array (stable sort). - * - * Note that the typical group size with the same timestamp will be quite small (<10 or so events), - * and the number of groups typically ~1% of total trace, so the same ultra-performance-sensitive consideration - * given to functions that run on entire traces does not necessarily apply here. - * - * @param {number[]} tsGroupIndices - * @param {number[]} timestampSortedIndices - * @param {number} indexOfTsGroupIndicesStart - * @param {LH.TraceEvent[]} traceEvents - * @return {number[]} - */ - static _sortTimestampEventGroup(tsGroupIndices, timestampSortedIndices, indexOfTsGroupIndicesStart, traceEvents) { - const lookupArrayIndexByTsIndex = /* @__PURE__ */ __name((i) => timestampSortedIndices[i], "lookupArrayIndexByTsIndex"); - const lookupEventByTsIndex = /* @__PURE__ */ __name((i) => traceEvents[lookupArrayIndexByTsIndex(i)], "lookupEventByTsIndex"); - const eEventIndices = []; - const bxEventIndices = []; - const otherEventIndices = []; - for (const tsIndex of tsGroupIndices) { - const arrayIndex = lookupArrayIndexByTsIndex(tsIndex); - const event = lookupEventByTsIndex(tsIndex); - if (event.ph === "E") eEventIndices.push(arrayIndex); - else if (event.ph === "X" || event.ph === "B") bxEventIndices.push(arrayIndex); - else otherEventIndices.push(arrayIndex); - } - const effectiveDuration = /* @__PURE__ */ new Map(); - for (const index of bxEventIndices) { - const event = traceEvents[index]; - if (event.ph === "X") { - effectiveDuration.set(index, event.dur); - } else { - let duration = Number.MAX_SAFE_INTEGER; - let additionalNestedEventsWithSameName = 0; - const startIndex = indexOfTsGroupIndicesStart + tsGroupIndices.length; - for (let j = startIndex; j < timestampSortedIndices.length; j++) { - const potentialMatchingEvent = lookupEventByTsIndex(j); - const eventMatches = potentialMatchingEvent.name === event.name && potentialMatchingEvent.pid === event.pid && potentialMatchingEvent.tid === event.tid; - if (!eventMatches) continue; - if (potentialMatchingEvent.ph === "E" && additionalNestedEventsWithSameName === 0) { - duration = potentialMatchingEvent.ts - event.ts; - break; - } else if (potentialMatchingEvent.ph === "E") { - additionalNestedEventsWithSameName--; - } else if (potentialMatchingEvent.ph === "B") { - additionalNestedEventsWithSameName++; - } - } - effectiveDuration.set(index, duration); - } - } - bxEventIndices.sort((indexA, indexB) => (effectiveDuration.get(indexB) || 0) - (effectiveDuration.get(indexA) || 0) || indexA - indexB); - otherEventIndices.sort((indexA, indexB) => indexA - indexB); - return [...eEventIndices, ...bxEventIndices, ...otherEventIndices]; - } - /** - * Sorts and filters trace events by timestamp and respecting the nesting structure inherent to - * parent/child event relationships. - * - * @param {LH.TraceEvent[]} traceEvents - * @param {(e: LH.TraceEvent) => boolean} filter - */ - static filteredTraceSort(traceEvents, filter) { - const indices = []; - for (let srcIndex = 0; srcIndex < traceEvents.length; srcIndex++) { - if (filter(traceEvents[srcIndex])) { - indices.push(srcIndex); - } - } - indices.sort((indexA, indexB) => traceEvents[indexA].ts - traceEvents[indexB].ts); - for (let i = 0; i < indices.length - 1; i++) { - const ts = traceEvents[indices[i]].ts; - const tsGroupIndices = [i]; - for (let j = i + 1; j < indices.length; j++) { - if (traceEvents[indices[j]].ts !== ts) break; - tsGroupIndices.push(j); - } - if (tsGroupIndices.length === 1) continue; - const finalIndexOrder = _TraceProcessor._sortTimestampEventGroup( - tsGroupIndices, - indices, - i, - traceEvents - ); - indices.splice(i, finalIndexOrder.length, ...finalIndexOrder); - i += tsGroupIndices.length - 1; - } - const sorted2 = []; - for (let i = 0; i < indices.length; i++) { - sorted2.push(traceEvents[indices[i]]); - } - return sorted2; - } - /** - * There should *always* be at least one top level event, having 0 typically means something is - * drastically wrong with the trace and we should just give up early and loudly. - * - * @param {LH.TraceEvent[]} events - */ - static assertHasToplevelEvents(events) { - const hasToplevelTask = events.some(this.isScheduleableTask); - if (!hasToplevelTask) { - throw new Error("Could not find any top level events"); - } - } - /** - * Calculate duration at specified percentiles for given population of - * durations. - * If one of the durations overlaps the end of the window, the full - * duration should be in the duration array, but the length not included - * within the window should be given as `clippedLength`. For instance, if a - * 50ms duration occurs 10ms before the end of the window, `50` should be in - * the `durations` array, and `clippedLength` should be set to 40. - * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview - * @param {!Array} durations Array of durations, sorted in ascending order. - * @param {number} totalTime Total time (in ms) of interval containing durations. - * @param {!Array} percentiles Array of percentiles of interest, in ascending order. - * @param {number=} clippedLength Optional length clipped from a duration overlapping end of window. Default of 0. - * @return {!Array<{percentile: number, time: number}>} - * @private - */ - static _riskPercentiles(durations, totalTime, percentiles, clippedLength = 0) { - let busyTime = 0; - for (let i = 0; i < durations.length; i++) { - busyTime += durations[i]; - } - busyTime -= clippedLength; - let completedTime = totalTime - busyTime; - let duration = 0; - let cdfTime = completedTime; - const results = []; - let durationIndex = -1; - let remainingCount = durations.length + 1; - if (clippedLength > 0) { - remainingCount--; - } - for (const percentile of percentiles) { - const percentileTime = percentile * totalTime; - while (cdfTime < percentileTime && durationIndex < durations.length - 1) { - completedTime += duration; - remainingCount -= duration < 0 ? -1 : 1; - if (clippedLength > 0 && clippedLength < durations[durationIndex + 1]) { - duration = -clippedLength; - clippedLength = 0; - } else { - durationIndex++; - duration = durations[durationIndex]; - } - cdfTime = completedTime + Math.abs(duration) * remainingCount; - } - results.push({ - percentile, - time: Math.max(0, (percentileTime - completedTime) / remainingCount) + BASE_RESPONSE_LATENCY - }); - } - return results; + init_LanternComputationData(); + init_types2(); + TraceParseProgressEvent = class _TraceParseProgressEvent extends Event { + static { + __name(this, "TraceParseProgressEvent"); } - /** - * Calculates the maximum queueing time (in ms) of high priority tasks for - * selected percentiles within a window of the main thread. - * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview - * @param {Array} events - * @param {number} startTime Start time (in ms relative to timeOrigin) of range of interest. - * @param {number} endTime End time (in ms relative to timeOrigin) of range of interest. - * @param {!Array=} percentiles Optional array of percentiles to compute. Defaults to [0.5, 0.75, 0.9, 0.99, 1]. - * @return {!Array<{percentile: number, time: number}>} - */ - static getRiskToResponsiveness(events, startTime, endTime, percentiles = [0.5, 0.75, 0.9, 0.99, 1]) { - const totalTime = endTime - startTime; - percentiles.sort((a, b) => a - b); - const ret = this.getMainThreadTopLevelEventDurations(events, startTime, endTime); - return this._riskPercentiles( - ret.durations, - totalTime, - percentiles, - ret.clippedLength - ); + data; + static eventName = "traceparseprogress"; + constructor(data31, init2 = { bubbles: true }) { + super(_TraceParseProgressEvent.eventName, init2); + this.data = data31; + } + }; + __name(calculateProgress, "calculateProgress"); + TraceProcessor2 = class extends EventTarget { + static { + __name(this, "TraceProcessor"); + } + // We force the Meta handler to be enabled, so the TraceHandlers type here is + // the model handlers the user passes in and the Meta handler. + #traceHandlers; + #status = "IDLE"; + #modelConfiguration = Configuration_exports.defaults(); + #data = null; + #insights = null; + static createWithAllHandlers() { + return new _a2(ModelHandlers_exports, Configuration_exports.defaults()); } /** - * Provides durations in ms of all main thread top-level events - * @param {Array} topLevelEvents - * @param {number} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0. - * @param {number} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end. - * @return {{durations: Array, clippedLength: number}} + * This function is kept for testing with `stub`. */ - static getMainThreadTopLevelEventDurations(topLevelEvents, startTime = 0, endTime = Infinity) { - const durations = []; - let clippedLength = 0; - for (const event of topLevelEvents) { - if (event.end < startTime || event.start > endTime) { - continue; - } - let duration = event.duration; - let eventStart = event.start; - if (eventStart < startTime) { - eventStart = startTime; - duration = event.end - startTime; - } - if (event.end > endTime) { - clippedLength = duration - (endTime - eventStart); - } - durations.push(duration); - } - durations.sort((a, b) => a - b); - return { - durations, - clippedLength + static getInsightRunners() { + return { ...Models_exports }; + } + constructor(traceHandlers, modelConfiguration) { + super(); + this.#verifyHandlers(traceHandlers); + this.#traceHandlers = { + Meta: ModelHandlers_exports.Meta, + ...traceHandlers }; + if (modelConfiguration) { + this.#modelConfiguration = modelConfiguration; + } + this.#passConfigToHandlers(); } - /** - * Provides the top level events on the main thread with timestamps in ms relative to timeOrigin. - * start. - * @param {LH.Artifacts.ProcessedTrace} trace - * @param {number=} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0. - * @param {number=} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end. - * @return {Array} - */ - static getMainThreadTopLevelEvents(trace, startTime = 0, endTime = Infinity) { - const topLevelEvents = []; - let prevToplevel = void 0; - for (const event of trace.mainThreadEvents) { - if (!this.isScheduleableTask(event) || !event.dur) continue; - const start = (event.ts - trace.timeOriginEvt.ts) / 1e3; - const end = (event.ts + event.dur - trace.timeOriginEvt.ts) / 1e3; - if (start > endTime || end < startTime) continue; - if (prevToplevel && start < prevToplevel.end) { - prevToplevel.end = start - 1e-3; + #passConfigToHandlers() { + for (const handler of Object.values(this.#traceHandlers)) { + if ("handleUserConfig" in handler && handler.handleUserConfig) { + handler.handleUserConfig(this.#modelConfiguration); } - prevToplevel = { - start, - end, - duration: event.dur / 1e3 - }; - topLevelEvents.push(prevToplevel); } - return topLevelEvents; } /** - * @param {LH.TraceEvent[]} events - * @return {{startingPid: number, frameId: string}} - */ - static findMainFrameIds(events) { - const startedInBrowserEvt = events.find((e) => e.name === "TracingStartedInBrowser"); - if (startedInBrowserEvt?.args.data?.frames) { - const mainFrame = startedInBrowserEvt.args.data.frames.find((frame) => !frame.parent); - const frameId = mainFrame?.frame; - const pid = mainFrame?.processId; - if (pid && frameId) { - return { - startingPid: pid, - frameId - }; + * When the user passes in a set of handlers, we want to ensure that we have all + * the required handlers. Handlers can depend on other handlers, so if the user + * passes in FooHandler which depends on BarHandler, they must also pass in + * BarHandler too. This method verifies that all dependencies are met, and + * throws if not. + **/ + #verifyHandlers(providedHandlers) { + if (Object.keys(providedHandlers).length === Object.keys(ModelHandlers_exports).length) { + return; + } + const requiredHandlerKeys = /* @__PURE__ */ new Set(); + for (const [handlerName, handler] of Object.entries(providedHandlers)) { + requiredHandlerKeys.add(handlerName); + const deps17 = "deps" in handler ? handler.deps() : []; + for (const depName of deps17) { + requiredHandlerKeys.add(depName); } } - const startedInPageEvt = events.find((e) => e.name === "TracingStartedInPage"); - if (startedInPageEvt?.args?.data) { - const frameId = startedInPageEvt.args.data.page; - if (frameId) { - return { - startingPid: startedInPageEvt.pid, - frameId - }; + const providedHandlerKeys = new Set(Object.keys(providedHandlers)); + requiredHandlerKeys.delete("Meta"); + for (const requiredKey of requiredHandlerKeys) { + if (!providedHandlerKeys.has(requiredKey)) { + throw new Error(`Required handler ${requiredKey} not provided.`); } } - const navStartEvt = events.find( - (e) => this._isNavigationStartOfInterest(e) && e.args.data?.isLoadingMainFrame - ); - const firstResourceSendEvt = events.find((e) => e.name === "ResourceSendRequest"); - if (navStartEvt?.args?.data && firstResourceSendEvt && firstResourceSendEvt.pid === navStartEvt.pid && firstResourceSendEvt.tid === navStartEvt.tid) { - const frameId = navStartEvt.args.frame; - if (frameId) { - return { - startingPid: navStartEvt.pid, - frameId - }; + } + reset() { + if (this.#status === "PARSING") { + throw new Error("Trace processor can't reset while parsing."); + } + const handlers = Object.values(this.#traceHandlers); + for (const handler of handlers) { + handler.reset(); + } + this.#data = null; + this.#insights = null; + this.#status = "IDLE"; + } + async parse(traceEvents, options) { + if (this.#status !== "IDLE") { + throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`); + } + if (typeof options.isCPUProfile === "undefined" && options.metadata) { + options.isCPUProfile = options.metadata.dataOrigin === File_exports.DataOrigin.CPU_PROFILE; + } + options.logger?.start("total"); + try { + this.#status = "PARSING"; + options.logger?.start("parse"); + await this.#computeParsedTrace(traceEvents, options); + options.logger?.end("parse"); + if (this.#data && !options.isCPUProfile) { + options.logger?.start("insights"); + this.#computeInsights(this.#data, traceEvents, options); + options.logger?.end("insights"); } + this.#status = "FINISHED_PARSING"; + } catch (e) { + this.#status = "ERRORED_WHILE_PARSING"; + throw e; + } finally { + options.logger?.end("total"); } - throw this.createNoTracingStartedError(); } /** - * If there were any cross-origin navigations, there'll be more than one pid returned - * @param {{startingPid: number, frameId: string}} mainFrameInfo - * @param {LH.TraceEvent[]} keyEvents - * @return {Map} Map where keys are process IDs and their values are thread IDs + * Run all the handlers and set the result to `#data`. */ - static findMainFramePidTids(mainFrameInfo, keyEvents) { - const frameProcessEvts = keyEvents.filter( - (evt) => ( - // ProcessReadyInBrowser is used when a processID isn't available when the FrameCommittedInBrowser trace event is emitted. - // In that case. FrameCommittedInBrowser has no processId, but a processPseudoId. and the ProcessReadyInBrowser event declares the proper processId. - (evt.name === "FrameCommittedInBrowser" || evt.name === "ProcessReadyInBrowser") && evt.args?.data?.frame === mainFrameInfo.frameId && evt?.args?.data?.processId - ) - ); - const mainFramePids = frameProcessEvts.length ? frameProcessEvts.map((e) => e?.args?.data?.processId) : [mainFrameInfo.startingPid]; - const pidToTid = /* @__PURE__ */ new Map(); - for (const pid of new Set(mainFramePids)) { - const threadEvents = keyEvents.filter( - (e) => e.cat === "__metadata" && e.pid === pid && e.ph === "M" && e.name === "thread_name" - ); - let threadNameEvt = threadEvents.find((e) => e.args.name === "CrRendererMain"); - if (!threadNameEvt) { - threadNameEvt = threadEvents.find((e) => e.args.name === "CrBrowserMain"); + async #computeParsedTrace(traceEvents, options) { + const eventsPerChunk = 5e4; + const sortedHandlers = [...sortHandlers(this.#traceHandlers).entries()]; + for (const [, handler] of sortedHandlers) { + handler.reset(); + } + options.logger?.start("parse:handleEvent"); + for (let i = 0; i < traceEvents.length; ++i) { + if (i % eventsPerChunk === 0 && i) { + const percent = calculateProgress( + i / traceEvents.length, + 0.2 + /* ProgressPhase.HANDLE_EVENT */ + ); + this.dispatchEvent(new TraceParseProgressEvent({ percent })); + await new Promise((resolve) => setTimeout(resolve, 0)); } - const tid = threadNameEvt?.tid; - if (!tid) { - throw new Error("Unable to determine tid for renderer process"); + const event = traceEvents[i]; + for (let j = 0; j < sortedHandlers.length; ++j) { + const [, handler] = sortedHandlers[j]; + handler.handleEvent(event); } - pidToTid.set(pid, tid); } - return pidToTid; - } - /** - * @param {LH.TraceEvent} evt - * @return {boolean} - */ - static isScheduleableTask(evt) { - return evt.name === SCHEDULABLE_TASK_TITLE_LH2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT12 || evt.name === SCHEDULABLE_TASK_TITLE_ALT22 || evt.name === SCHEDULABLE_TASK_TITLE_ALT32; - } - /** - * @param {LH.TraceEvent} evt - * @return {evt is LCPEvent} - */ - static isLCPEvent(evt) { - if (evt.name !== "largestContentfulPaint::Invalidate" && evt.name !== "largestContentfulPaint::Candidate") return false; - return Boolean(evt.args?.frame); + options.logger?.end("parse:handleEvent"); + const finalizeOptions = { + ...options, + allTraceEvents: traceEvents + }; + for (let i = 0; i < sortedHandlers.length; i++) { + const [name, handler] = sortedHandlers[i]; + if (handler.finalize) { + options.logger?.start(`parse:${name}:finalize`); + await new Promise((resolve) => setTimeout(resolve, 0)); + await handler.finalize(finalizeOptions); + options.logger?.end(`parse:${name}:finalize`); + } + const percent = calculateProgress( + i / sortedHandlers.length, + 0.8 + /* ProgressPhase.FINALIZE */ + ); + this.dispatchEvent(new TraceParseProgressEvent({ percent })); + } + options.logger?.start("parse:handler.data()"); + const parsedTrace = {}; + for (const [name, handler] of Object.entries(this.#traceHandlers)) { + Object.assign(parsedTrace, { [name]: handler.data() }); + } + options.logger?.end("parse:handler.data()"); + this.dispatchEvent(new TraceParseProgressEvent({ + percent: 1 + /* ProgressPhase.CLONE */ + })); + this.#data = parsedTrace; } - /** - * @param {LH.TraceEvent} evt - * @return {evt is LCPCandidateEvent} - */ - static isLCPCandidateEvent(evt) { - return Boolean( - evt.name === "largestContentfulPaint::Candidate" && evt.args?.frame && evt.args.data && evt.args.data.size !== void 0 - ); + get data() { + if (this.#status !== "FINISHED_PARSING") { + return null; + } + return this.#data; } - /** - * The associated frame ID is set in different locations for different trace events. - * This function checks all known locations for the frame ID and returns `undefined` if it's not found. - * - * @param {LH.TraceEvent} evt - * @return {string|undefined} - */ - static getFrameId(evt) { - return evt.args?.data?.frame || evt.args.data?.frameID || evt.args.frame; + get insights() { + if (this.#status !== "FINISHED_PARSING") { + return null; + } + return this.#insights; } - /** - * Returns the maximum LCP event across all frames in `events`. - * Sets `invalidated` flag if LCP of every frame is invalidated. - * - * LCP's trace event was first introduced in m78. We can't surface an LCP for older Chrome versions. - * LCP comes from a frame's latest `largestContentfulPaint::Candidate`, but it can be invalidated by a `largestContentfulPaint::Invalidate` event. - * - * @param {LH.TraceEvent[]} events - * @param {LH.TraceEvent} timeOriginEvent - * @return {{lcp: LCPEvent | undefined, invalidated: boolean}} - */ - static computeValidLCPAllFrames(events, timeOriginEvent) { - const lcpEvents = events.filter(this.isLCPEvent).reverse(); - const finalLcpEventsByFrame = /* @__PURE__ */ new Map(); - for (const e of lcpEvents) { - if (e.ts <= timeOriginEvent.ts) break; - const frame = e.args.frame; - if (finalLcpEventsByFrame.has(frame)) continue; - finalLcpEventsByFrame.set(frame, e); + #createLanternContext(data31, traceEvents, frameId, navigationId, options) { + if (!data31.NetworkRequests || !data31.Workers || !data31.PageLoadMetrics) { + return; } - let maxLcpAcrossFrames; - for (const lcp of finalLcpEventsByFrame.values()) { - if (!this.isLCPCandidateEvent(lcp)) continue; - if (!maxLcpAcrossFrames || lcp.args.data.size > maxLcpAcrossFrames.args.data.size) { - maxLcpAcrossFrames = lcp; - } + if (!data31.NetworkRequests.byTime.length) { + throw new core_exports.LanternError("No network requests found in trace"); } - return { - lcp: maxLcpAcrossFrames, - // LCP events were found, but final LCP event of every frame was an invalidate event. - invalidated: Boolean(!maxLcpAcrossFrames && finalLcpEventsByFrame.size) + const navStarts = data31.Meta.navigationsByFrameId.get(frameId); + const navStartIndex = navStarts?.findIndex((n) => n.args.data?.navigationId === navigationId); + if (!navStarts || navStartIndex === void 0 || navStartIndex === -1) { + throw new core_exports.LanternError("Could not find navigation start"); + } + const startTime = navStarts[navStartIndex].ts; + const endTime = navStartIndex + 1 < navStarts.length ? navStarts[navStartIndex + 1].ts : Number.POSITIVE_INFINITY; + const boundedTraceEvents = traceEvents.filter((e) => e.ts >= startTime && e.ts < endTime); + const trace = { + traceEvents: boundedTraceEvents + }; + const requests = createNetworkRequests(trace, data31, startTime, endTime); + const graph2 = createGraph(requests, trace, data31); + const processedNavigation = createProcessedNavigation(data31, frameId, navigationId); + const networkAnalysis = core_exports.NetworkAnalyzer.analyze(requests); + if (!networkAnalysis) { + return; + } + const lanternSettings = { + // TODO(crbug.com/372674229): if devtools throttling was on, does this network analysis capture + // that? Do we need to set 'devtools' throttlingMethod? + networkAnalysis, + throttlingMethod: "provided", + ...options.lanternSettings }; + const simulator = simulation_exports.Simulator.createSimulator(lanternSettings); + const computeData = { graph: graph2, simulator, processedNavigation }; + const fcpResult = metrics_exports.FirstContentfulPaint.compute(computeData); + const lcpResult = metrics_exports.LargestContentfulPaint.compute(computeData, { fcpResult }); + const interactiveResult = metrics_exports.Interactive.compute(computeData, { lcpResult }); + const tbtResult = metrics_exports.TotalBlockingTime.compute(computeData, { fcpResult, interactiveResult }); + const metrics = { + firstContentfulPaint: fcpResult, + interactive: interactiveResult, + largestContentfulPaint: lcpResult, + totalBlockingTime: tbtResult + }; + return { requests, graph: graph2, simulator, metrics }; } /** - * @param {Array<{id: string, url: string, parent?: string}>} frames - * @return {Map} + * Sort the insight models based on the impact of each insight's estimated savings, additionally weighted by the + * worst metrics according to field data (if present). */ - static resolveRootFrames(frames2) { - const parentFrames = /* @__PURE__ */ new Map(); - for (const frame of frames2) { - if (!frame.parent) continue; - parentFrames.set(frame.id, frame.parent); + sortInsightSet(insightSet, metadata) { + const baselineOrder = { + INPBreakdown: null, + LCPBreakdown: null, + LCPDiscovery: null, + CLSCulprits: null, + RenderBlocking: null, + NetworkDependencyTree: null, + ImageDelivery: null, + DocumentLatency: null, + FontDisplay: null, + Viewport: null, + DOMSize: null, + ThirdParties: null, + DuplicatedJavaScript: null, + SlowCSSSelector: null, + ForcedReflow: null, + Cache: null, + ModernHTTP: null, + LegacyJavaScript: null + }; + const weights = Common_exports.calculateMetricWeightsForSorting(insightSet, metadata); + const observedLcpMicro = Common_exports.getLCP(insightSet)?.value; + const observedLcp = observedLcpMicro ? Timing_exports3.microToMilli(observedLcpMicro) : Timing_exports.Milli(0); + const observedCls = Common_exports.getCLS(insightSet).value; + const observedInpMicro = Common_exports.getINP(insightSet)?.value; + const observedInp = observedInpMicro ? Timing_exports3.microToMilli(observedInpMicro) : Timing_exports.Milli(200); + const observedLcpScore = observedLcp !== void 0 ? Common_exports.evaluateLCPMetricScore(observedLcp) : void 0; + const observedInpScore = Common_exports.evaluateINPMetricScore(observedInp); + const observedClsScore = Common_exports.evaluateCLSMetricScore(observedCls); + const insightToSortingRank = /* @__PURE__ */ new Map(); + for (const [name, model2] of Object.entries(insightSet.model)) { + const lcp = model2.metricSavings?.LCP ?? 0; + const inp = model2.metricSavings?.INP ?? 0; + const cls = model2.metricSavings?.CLS ?? 0; + const lcpPostSavings = observedLcp !== void 0 ? Math.max(0, observedLcp - lcp) : void 0; + const inpPostSavings = Math.max(0, observedInp - inp); + const clsPostSavings = Math.max(0, observedCls - cls); + let score = 0; + if (weights.lcp && lcp && observedLcpScore !== void 0 && lcpPostSavings !== void 0) { + score += weights.lcp * (Common_exports.evaluateLCPMetricScore(lcpPostSavings) - observedLcpScore); + } + if (weights.inp && inp && observedInpScore !== void 0) { + score += weights.inp * (Common_exports.evaluateINPMetricScore(inpPostSavings) - observedInpScore); + } + if (weights.cls && cls && observedClsScore !== void 0) { + score += weights.cls * (Common_exports.evaluateCLSMetricScore(clsPostSavings) - observedClsScore); + } + insightToSortingRank.set(name, score); } - const frameIdToRootFrameId = /* @__PURE__ */ new Map(); - for (const frame of frames2) { - let cur = frame.id; - while (parentFrames.has(cur)) { - cur = /** @type {string} */ - parentFrames.get(cur); + const baselineOrderKeys = Object.keys(baselineOrder); + const orderedKeys = Object.keys(insightSet.model); + orderedKeys.sort((a, b) => { + const a1 = baselineOrderKeys.indexOf(a); + const b1 = baselineOrderKeys.indexOf(b); + if (a1 >= 0 && b1 >= 0) { + return a1 - b1; } - if (cur === void 0) { - throw new Error("Unexpected undefined frameId"); + if (a1 >= 0) { + return -1; } - frameIdToRootFrameId.set(frame.id, cur); + if (b1 >= 0) { + return 1; + } + return 0; + }); + orderedKeys.sort((a, b) => (insightToSortingRank.get(b) ?? 0) - (insightToSortingRank.get(a) ?? 0)); + const newModel = {}; + for (const key of orderedKeys) { + const model2 = insightSet.model[key]; + newModel[key] = model2; } - return frameIdToRootFrameId; + insightSet.model = newModel; } - /** - * Finds key trace events, identifies main process/thread, and returns timings of trace events - * in milliseconds since the time origin in addition to the standard microsecond monotonic timestamps. - * @param {LH.Trace} trace - * @param {{timeOriginDeterminationMethod?: TimeOriginDeterminationMethod}} [options] - * @return {LH.Artifacts.ProcessedTrace} - */ - static processTrace(trace, options) { - const { timeOriginDeterminationMethod = "auto" } = options || {}; - const keyEvents = this.filteredTraceSort(trace.traceEvents, (e) => { - return e.cat.includes("blink.user_timing") || e.cat.includes("loading") || e.cat.includes("devtools.timeline") || e.cat === "__metadata"; - }); - const mainFrameInfo = this.findMainFrameIds(keyEvents); - const rendererPidToTid = this.findMainFramePidTids(mainFrameInfo, keyEvents); - const processEvents = _TraceProcessor.filteredTraceSort(trace.traceEvents, (e) => rendererPidToTid.has(e.pid)); - const framesById = /* @__PURE__ */ new Map(); - const tracingStartedFrames = keyEvents.find((e) => e.name === "TracingStartedInBrowser")?.args?.data?.frames; - if (tracingStartedFrames) { - for (const frame of tracingStartedFrames) { - framesById.set(frame.frame, { - id: frame.frame, - url: frame.url, - parent: frame.parent - }); - } + #computeInsightSet(data31, context) { + const logger = context.options.logger; + let id, urlString, navigation2; + if (context.navigation) { + id = context.navigationId; + urlString = data31.Meta.finalDisplayUrlByNavigationId.get(context.navigationId) ?? data31.Meta.mainFrameURL; + navigation2 = context.navigation; + } else { + id = TraceEvents_exports.NO_NAVIGATION; + urlString = data31.Meta.finalDisplayUrlByNavigationId.get("") ?? data31.Meta.mainFrameURL; } - keyEvents.filter( - /** @return {evt is FrameCommittedEvent} */ - (evt) => { - return Boolean( - evt.name === "FrameCommittedInBrowser" && evt.args.data?.frame && evt.args.data.url !== void 0 - ); + const insightSetModel = {}; + for (const [name, insight] of Object.entries(_a2.getInsightRunners())) { + let model2; + try { + logger?.start(`insights:${name}`); + model2 = insight.generateInsight(data31, context); + model2.frameId = context.frameId; + const navId = context.navigation?.args.data?.navigationId; + if (navId) { + model2.navigationId = navId; + } + model2.createOverlays = () => { + return insight.createOverlays(model2); + }; + } catch (err) { + model2 = err; + } finally { + logger?.end(`insights:${name}`); } - ).forEach((evt) => { - framesById.set(evt.args.data.frame, { - id: evt.args.data.frame, - url: evt.args.data.url, - parent: evt.args.data.parent - }); - }); - const frames2 = [...framesById.values()]; - const frameIdToRootFrameId = this.resolveRootFrames(frames2); - const inspectedTreeFrameIds = [...frameIdToRootFrameId.entries()].filter(([, rootFrameId]) => rootFrameId === mainFrameInfo.frameId).map(([child]) => child); - function associatedToMainFrame(e) { - const frameId = _TraceProcessor.getFrameId(e); - return frameId === mainFrameInfo.frameId; + Object.assign(insightSetModel, { [name]: model2 }); } - __name(associatedToMainFrame, "associatedToMainFrame"); - function associatedToAllFrames(e) { - const frameId = _TraceProcessor.getFrameId(e); - return frameId ? inspectedTreeFrameIds.includes(frameId) : false; + const isNavigation = id === TraceEvents_exports.NO_NAVIGATION; + const trivialThreshold = Timing_exports3.milliToMicro(Timing_exports.Milli(5e3)); + const everyInsightPasses = Object.values(insightSetModel).filter((model2) => !(model2 instanceof Error)).every((model2) => model2.state === "pass"); + const noLcp = !insightSetModel.LCPBreakdown.lcpEvent; + const noInp = !insightSetModel.INPBreakdown.longestInteractionEvent; + const noLayoutShifts = insightSetModel.CLSCulprits.shifts?.size === 0; + const shouldExclude = isNavigation && context.bounds.range < trivialThreshold && everyInsightPasses && noLcp && noInp && noLayoutShifts; + if (shouldExclude) { + return; } - __name(associatedToAllFrames, "associatedToAllFrames"); - const frameEvents = keyEvents.filter((e) => associatedToMainFrame(e)); - let frameTreeEvents = []; - if (frameIdToRootFrameId.has(mainFrameInfo.frameId)) { - frameTreeEvents = keyEvents.filter((e) => associatedToAllFrames(e)); - } else { - lighthouse_logger_default.warn( - "TraceProcessor", - "frameTreeEvents may be incomplete, make sure the trace has frame events" - ); - frameIdToRootFrameId.set(mainFrameInfo.frameId, mainFrameInfo.frameId); - frameTreeEvents = frameEvents; + let url; + try { + url = new URL(urlString); + } catch { + return; } - const timeOriginEvt = this.computeTimeOrigin( - { keyEvents, frameEvents, mainFrameInfo }, - timeOriginDeterminationMethod - ); - const mainThreadEvents = processEvents.filter((e) => e.tid === rendererPidToTid.get(e.pid)); - const traceEnd = this.computeTraceEnd(trace.traceEvents, timeOriginEvt); - return { - frames: frames2, - mainThreadEvents, - frameEvents, - frameTreeEvents, - processEvents, - mainFrameInfo, - timeOriginEvt, - timings: { - timeOrigin: 0, - traceEnd: traceEnd.timing - }, - timestamps: { - timeOrigin: timeOriginEvt.ts, - traceEnd: traceEnd.timestamp - }, - _keyEvents: keyEvents, - _rendererPidToTid: rendererPidToTid + const insightSet = { + id, + url, + navigation: navigation2, + frameId: context.frameId, + bounds: context.bounds, + model: insightSetModel }; - } - /** - * Finds key navigation trace events and computes timings of events in milliseconds since the time - * origin in addition to the standard microsecond monotonic timestamps. - * @param {LH.Artifacts.ProcessedTrace} processedTrace - * @return {LH.Artifacts.ProcessedNavigation} - */ - static processNavigation(processedTrace) { - const { frameEvents, frameTreeEvents, timeOriginEvt, timings, timestamps } = processedTrace; - const frameTimings = this.computeNavigationTimingsForFrame(frameEvents, { timeOriginEvt }); - const fcpAllFramesEvt = frameTreeEvents.find( - (e) => e.name === "firstContentfulPaint" && e.ts > timeOriginEvt.ts - ); - if (!fcpAllFramesEvt) { - throw this.createNoFirstContentfulPaintError(); + if (!this.#insights) { + this.#insights = /* @__PURE__ */ new Map(); } - const lcpAllFramesEvt = this.computeValidLCPAllFrames(frameTreeEvents, timeOriginEvt).lcp; - const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, "getTiming"); - const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), "maybeGetTiming"); - return { - timings: { - timeOrigin: timings.timeOrigin, - firstPaint: frameTimings.timings.firstPaint, - firstContentfulPaint: frameTimings.timings.firstContentfulPaint, - firstContentfulPaintAllFrames: getTiming(fcpAllFramesEvt.ts), - largestContentfulPaint: frameTimings.timings.largestContentfulPaint, - largestContentfulPaintAllFrames: maybeGetTiming(lcpAllFramesEvt?.ts), - load: frameTimings.timings.load, - domContentLoaded: frameTimings.timings.domContentLoaded, - traceEnd: timings.traceEnd - }, - timestamps: { - timeOrigin: timestamps.timeOrigin, - firstPaint: frameTimings.timestamps.firstPaint, - firstContentfulPaint: frameTimings.timestamps.firstContentfulPaint, - firstContentfulPaintAllFrames: fcpAllFramesEvt.ts, - largestContentfulPaint: frameTimings.timestamps.largestContentfulPaint, - largestContentfulPaintAllFrames: lcpAllFramesEvt?.ts, - load: frameTimings.timestamps.load, - domContentLoaded: frameTimings.timestamps.domContentLoaded, - traceEnd: timestamps.traceEnd - }, - firstPaintEvt: frameTimings.firstPaintEvt, - firstContentfulPaintEvt: frameTimings.firstContentfulPaintEvt, - firstContentfulPaintAllFramesEvt: fcpAllFramesEvt, - largestContentfulPaintEvt: frameTimings.largestContentfulPaintEvt, - largestContentfulPaintAllFramesEvt: lcpAllFramesEvt, - loadEvt: frameTimings.loadEvt, - domContentLoadedEvt: frameTimings.domContentLoadedEvt, - lcpInvalidated: frameTimings.lcpInvalidated - }; + this.#insights.set(insightSet.id, insightSet); + this.sortInsightSet(insightSet, context.options.metadata ?? null); } /** - * Computes the last observable timestamp in a set of trace events. - * - * @param {Array} events - * @param {LH.TraceEvent} timeOriginEvt - * @return {{timing: number, timestamp: number}} + * Run all the insights and set the result to `#insights`. */ - static computeTraceEnd(events, timeOriginEvt) { - let maxTs = -Infinity; - for (const event of events) { - maxTs = Math.max(event.ts + (event.dur || 0), maxTs); + #computeInsights(data31, traceEvents, options) { + this.#insights = /* @__PURE__ */ new Map(); + const navigations = data31.Meta.mainFrameNavigations.filter((navigation2) => navigation2.args.frame && navigation2.args.data?.navigationId); + this.#computeInsightsForInitialTracePeriod(data31, navigations, options); + for (const [index, navigation2] of navigations.entries()) { + const min = navigation2.ts; + const max = index + 1 < navigations.length ? navigations[index + 1].ts : data31.Meta.traceBounds.max; + const bounds = Timing_exports3.traceWindowFromMicroSeconds(min, max); + this.#computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options); } - return { timestamp: maxTs, timing: (maxTs - timeOriginEvt.ts) / 1e3 }; } /** - * Computes the time origin using the specified method. - * - * - firstResourceSendRequest - * Uses the time that the very first network request is sent in the main frame. - * Eventually should be used in place of lastNavigationStart as the default for navigations. - * This method includes the cost of all redirects when evaluating a navigation (which matches lantern behavior). - * The only difference between firstResourceSendRequest and the first `navigationStart` is - * the unload time of `about:blank` (which is a Lighthouse implementation detail and shouldn't be included). - * - * - lastNavigationStart - * Uses the time of the last `navigationStart` event in the main frame. - * The historical time origin of Lighthouse from 2016-Present. - * This method excludes the cost of client-side redirects when evaluating a navigation. - * Can also be skewed by several hundred milliseconds or even seconds when the browser takes a long - * time to unload `about:blank`. - * - * @param {{keyEvents: Array, frameEvents: Array, mainFrameInfo: {frameId: string}}} traceEventSubsets - * @param {TimeOriginDeterminationMethod} method - * @return {LH.TraceEvent} + * Computes insights for the period before the first navigation, or for the entire trace if no navigations exist. */ - static computeTimeOrigin(traceEventSubsets, method) { - const lastNavigationStart = /* @__PURE__ */ __name(() => { - const frameEvents = traceEventSubsets.frameEvents; - return frameEvents.filter(this._isNavigationStartOfInterest).pop(); - }, "lastNavigationStart"); - const lighthouseMarker = /* @__PURE__ */ __name(() => { - const frameEvents = traceEventSubsets.keyEvents; - return frameEvents.find( - (evt) => evt.name === "clock_sync" && evt.args.sync_id === _TraceProcessor.TIMESPAN_MARKER_ID - ); - }, "lighthouseMarker"); - switch (method) { - case "firstResourceSendRequest": { - const fetchStart = traceEventSubsets.keyEvents.find((event) => { - if (event.name !== "ResourceSendRequest") return false; - const data31 = event.args.data || {}; - return data31.frame === traceEventSubsets.mainFrameInfo.frameId; - }); - if (!fetchStart) throw this.createNoResourceSendRequestError(); - return fetchStart; - } - case "lastNavigationStart": { - const navigationStart = lastNavigationStart(); - if (!navigationStart) throw this.createNoNavstartError(); - return navigationStart; - } - case "lighthouseMarker": { - const marker = lighthouseMarker(); - if (!marker) throw this.createNoLighthouseMarkerError(); - return marker; - } - case "auto": { - const marker = lighthouseMarker() || lastNavigationStart(); - if (!marker) throw this.createNoNavstartError(); - return marker; - } - } + #computeInsightsForInitialTracePeriod(data31, navigations, options) { + const bounds = navigations.length > 0 ? Timing_exports3.traceWindowFromMicroSeconds(data31.Meta.traceBounds.min, navigations[0].ts) : data31.Meta.traceBounds; + const context = { + options, + bounds, + frameId: data31.Meta.mainFrameId + // No navigation or lantern context applies to this initial/no-navigation period. + }; + this.#computeInsightSet(data31, context); } /** - * Computes timings of trace events of key trace events in milliseconds since the time origin - * in addition to the standard microsecond monotonic timestamps. - * @param {Array} frameEvents - * @param {{timeOriginEvt: LH.TraceEvent}} options - */ - static computeNavigationTimingsForFrame(frameEvents, options) { - const { timeOriginEvt } = options; - const firstPaint = frameEvents.find((e) => e.name === "firstPaint" && e.ts > timeOriginEvt.ts); - const firstContentfulPaint = frameEvents.find( - (e) => e.name === "firstContentfulPaint" && e.ts > timeOriginEvt.ts - ); - if (!firstContentfulPaint) { - throw this.createNoFirstContentfulPaintError(); + * Computes insights for a specific navigation event. + */ + #computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options) { + const frameId = navigation2.args.frame; + const navigationId = navigation2.args.data?.navigationId; + let lantern; + try { + options.logger?.start("insights:createLanternContext"); + lantern = this.#createLanternContext(data31, traceEvents, frameId, navigationId, options); + } catch (e) { + const expectedErrors = [ + "mainDocumentRequest not found", + "missing metric scores for main frame", + "missing metric: FCP", + "missing metric: LCP", + "No network requests found in trace", + "Trace is too old" + ]; + if (!(e instanceof core_exports.LanternError)) { + console.error(e); + } else if (!expectedErrors.some((err) => e.message === err)) { + console.error(e); + } + } finally { + options.logger?.end("insights:createLanternContext"); } - const lcpResult = this.computeValidLCPAllFrames(frameEvents, timeOriginEvt); - const load = frameEvents.find((e) => e.name === "loadEventEnd" && e.ts > timeOriginEvt.ts); - const domContentLoaded = frameEvents.find( - (e) => e.name === "domContentLoadedEventEnd" && e.ts > timeOriginEvt.ts - ); - const getTimestamp = /* @__PURE__ */ __name((event) => event?.ts, "getTimestamp"); - const timestamps = { - timeOrigin: timeOriginEvt.ts, - firstPaint: getTimestamp(firstPaint), - firstContentfulPaint: firstContentfulPaint.ts, - largestContentfulPaint: getTimestamp(lcpResult.lcp), - load: getTimestamp(load), - domContentLoaded: getTimestamp(domContentLoaded) - }; - const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, "getTiming"); - const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), "maybeGetTiming"); - const timings = { - timeOrigin: 0, - firstPaint: maybeGetTiming(timestamps.firstPaint), - firstContentfulPaint: getTiming(timestamps.firstContentfulPaint), - largestContentfulPaint: maybeGetTiming(timestamps.largestContentfulPaint), - load: maybeGetTiming(timestamps.load), - domContentLoaded: maybeGetTiming(timestamps.domContentLoaded) - }; - return { - timings, - timestamps, - timeOriginEvt, - firstPaintEvt: firstPaint, - firstContentfulPaintEvt: firstContentfulPaint, - largestContentfulPaintEvt: lcpResult.lcp, - loadEvt: load, - domContentLoadedEvt: domContentLoaded, - lcpInvalidated: lcpResult.invalidated + const context = { + options, + bounds, + frameId, + navigation: navigation2, + navigationId, + lantern }; + this.#computeInsightSet(data31, context); } }; + _a2 = TraceProcessor2; + __name(sortHandlers, "sortHandlers"); + } +}); + +// node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js +var init_ModelImpl = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js"() { + init_process_global(); + init_platform(); + init_handlers(); + init_helpers2(); + init_Processor(); + init_types2(); + } +}); + +// node_modules/@paulirish/trace_engine/core/common/common.js +var init_common = __esm({ + "node_modules/@paulirish/trace_engine/core/common/common.js"() { + init_process_global(); + } +}); + +// node_modules/@paulirish/trace_engine/models/trace/Styles.js +var EventCategory; +var init_Styles = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/Styles.js"() { + init_process_global(); + init_handlers(); + init_helpers2(); + init_types2(); + (function(EventCategory2) { + EventCategory2["DRAWING"] = "drawing"; + EventCategory2["RASTERIZING"] = "rasterizing"; + EventCategory2["LAYOUT"] = "layout"; + EventCategory2["LOADING"] = "loading"; + EventCategory2["EXPERIENCE"] = "experience"; + EventCategory2["SCRIPTING"] = "scripting"; + EventCategory2["MESSAGING"] = "messaging"; + EventCategory2["RENDERING"] = "rendering"; + EventCategory2["PAINTING"] = "painting"; + EventCategory2["GPU"] = "gpu"; + EventCategory2["ASYNC"] = "async"; + EventCategory2["OTHER"] = "other"; + EventCategory2["IDLE"] = "idle"; + })(EventCategory || (EventCategory = {})); + } +}); + +// node_modules/@paulirish/trace_engine/models/trace/Name.js +var init_Name = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/Name.js"() { + init_process_global(); + init_common(); + init_handlers(); + init_Styles(); + init_types2(); + } +}); + +// node_modules/@paulirish/trace_engine/models/trace/trace.js +var init_trace2 = __esm({ + "node_modules/@paulirish/trace_engine/models/trace/trace.js"() { + init_process_global(); + init_EntityMapper(); + init_EventsSerializer(); + init_extras(); + init_handlers(); + init_helpers2(); + init_insights(); + init_lantern(); + init_LanternComputationData(); + init_ModelImpl(); + init_Name(); + init_Processor(); + init_Styles(); + init_types2(); + } +}); + +// core/lib/lantern/lantern.js +var init_lantern2 = __esm({ + "core/lib/lantern/lantern.js"() { + "use strict"; + init_process_global(); + init_lantern(); + init_trace2(); + /** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ } }); @@ -40311,13 +40409,4710 @@ var init_video_caption = __esm({ } }); +// node_modules/web-features/data.json +var data_default; +var init_data = __esm({ + "node_modules/web-features/data.json"() { + data_default = { browsers: { chrome: { name: "Chrome", releases: [{ date: "2008-12-11", version: "1" }, { date: "2009-05-21", version: "2" }, { date: "2009-09-15", version: "3" }, { date: "2010-01-25", version: "4" }, { date: "2010-05-25", version: "5" }, { date: "2010-09-02", version: "6" }, { date: "2010-10-19", version: "7" }, { date: "2010-12-02", version: "8" }, { date: "2011-02-03", version: "9" }, { date: "2011-03-08", version: "10" }, { date: "2011-04-27", version: "11" }, { date: "2011-06-07", version: "12" }, { date: "2011-08-02", version: "13" }, { date: "2011-09-16", version: "14" }, { date: "2011-10-25", version: "15" }, { date: "2011-12-13", version: "16" }, { date: "2012-02-08", version: "17" }, { date: "2012-03-28", version: "18" }, { date: "2012-05-15", version: "19" }, { date: "2012-06-26", version: "20" }, { date: "2012-07-31", version: "21" }, { date: "2012-09-25", version: "22" }, { date: "2012-11-06", version: "23" }, { date: "2013-01-10", version: "24" }, { date: "\ +2013-02-21", version: "25" }, { date: "2013-03-26", version: "26" }, { date: "2013-05-21", version: "27" }, { date: "2013-07-09", version: "28" }, { date: "2013-08-20", version: "29" }, { date: "2013-10-01", version: "30" }, { date: "2013-11-12", version: "31" }, { date: "2014-01-14", version: "32" }, { date: "2014-02-20", version: "33" }, { date: "2014-04-08", version: "34" }, { date: "2014-05-20", version: "35" }, { date: "2014-07-16", version: "36" }, { date: "2014-08-26", version: "37" }, { date: "2014-10-07", version: "38" }, { date: "2014-11-18", version: "39" }, { date: "2015-01-21", version: "40" }, { date: "2015-03-03", version: "41" }, { date: "2015-04-14", version: "42" }, { date: "2015-05-19", version: "43" }, { date: "2015-07-21", version: "44" }, { date: "2015-09-01", version: "45" }, { date: "2015-10-13", version: "46" }, { date: "2015-12-01", version: "47" }, { date: "2016-01-20", version: "48" }, { date: "2016-03-02", version: "49" }, { date: "2016-04-13", version: "50" }, + { date: "2016-05-25", version: "51" }, { date: "2016-07-20", version: "52" }, { date: "2016-08-31", version: "53" }, { date: "2016-10-12", version: "54" }, { date: "2016-12-01", version: "55" }, { date: "2017-01-25", version: "56" }, { date: "2017-03-09", version: "57" }, { date: "2017-04-19", version: "58" }, { date: "2017-06-05", version: "59" }, { date: "2017-07-25", version: "60" }, { date: "2017-09-05", version: "61" }, { date: "2017-10-17", version: "62" }, { date: "2017-12-06", version: "63" }, { date: "2018-01-23", version: "64" }, { date: "2018-03-06", version: "65" }, { date: "2018-04-17", version: "66" }, { date: "2018-05-29", version: "67" }, { date: "2018-07-24", version: "68" }, { date: "2018-09-04", version: "69" }, { date: "2018-10-16", version: "70" }, { date: "2018-12-04", version: "71" }, { date: "2019-01-29", version: "72" }, { date: "2019-03-12", version: "73" }, { date: "2019-04-23", version: "74" }, { date: "2019-06-04", version: "75" }, { date: "2019-07-30", + version: "76" }, { date: "2019-09-10", version: "77" }, { date: "2019-10-22", version: "78" }, { date: "2019-12-10", version: "79" }, { date: "2020-02-04", version: "80" }, { date: "2020-04-07", version: "81" }, { date: "2020-05-19", version: "83" }, { date: "2020-07-27", version: "84" }, { date: "2020-08-25", version: "85" }, { date: "2020-10-20", version: "86" }, { date: "2020-11-17", version: "87" }, { date: "2021-01-19", version: "88" }, { date: "2021-03-02", version: "89" }, { date: "2021-04-13", version: "90" }, { date: "2021-05-25", version: "91" }, { date: "2021-07-20", version: "92" }, { date: "2021-08-31", version: "93" }, { date: "2021-09-21", version: "94" }, { date: "2021-10-19", version: "95" }, { date: "2021-11-15", version: "96" }, { date: "2022-01-04", version: "97" }, { date: "2022-02-01", version: "98" }, { date: "2022-03-01", version: "99" }, { date: "2022-03-29", version: "100" }, { date: "2022-04-26", version: "101" }, { date: "2022-05-24", version: "102" }, { + date: "2022-06-21", version: "103" }, { date: "2022-08-02", version: "104" }, { date: "2022-09-02", version: "105" }, { date: "2022-09-27", version: "106" }, { date: "2022-10-25", version: "107" }, { date: "2022-11-29", version: "108" }, { date: "2023-01-10", version: "109" }, { date: "2023-02-07", version: "110" }, { date: "2023-03-07", version: "111" }, { date: "2023-04-04", version: "112" }, { date: "2023-05-02", version: "113" }, { date: "2023-05-30", version: "114" }, { date: "2023-07-18", version: "115" }, { date: "2023-08-15", version: "116" }, { date: "2023-09-12", version: "117" }, { date: "2023-10-10", version: "118" }, { date: "2023-10-31", version: "119" }, { date: "2023-12-05", version: "120" }, { date: "2024-01-23", version: "121" }, { date: "2024-02-20", version: "122" }, { date: "2024-03-19", version: "123" }, { date: "2024-04-16", version: "124" }, { date: "2024-05-14", version: "125" }, { date: "2024-06-11", version: "126" }, { date: "2024-07-23", version: "127" }, + { date: "2024-08-20", version: "128" }, { date: "2024-09-17", version: "129" }, { date: "2024-10-15", version: "130" }, { date: "2024-11-12", version: "131" }, { date: "2025-01-14", version: "132" }, { date: "2025-02-04", version: "133" }, { date: "2025-03-04", version: "134" }, { date: "2025-04-01", version: "135" }, { date: "2025-04-29", version: "136" }, { date: "2025-05-27", version: "137" }, { date: "2025-06-24", version: "138" }, { date: "2025-08-05", version: "139" }, { date: "2025-09-02", version: "140" }, { date: "2025-09-30", version: "141" }, { date: "2025-10-28", version: "142" }, { date: "2025-12-02", version: "143" }, { date: "2026-01-13", version: "144" }, { date: "2026-02-10", version: "145" }, { date: "2026-03-10", version: "146" }] }, chrome_android: { name: "Chrome Android", releases: [{ date: "2012-06-27", version: "18" }, { date: "2013-02-27", version: "25" }, { date: "2013-04-03", version: "26" }, { date: "2013-05-22", version: "27" }, { date: "2013-07-10", version: "\ +28" }, { date: "2013-08-21", version: "29" }, { date: "2013-10-02", version: "30" }, { date: "2013-11-14", version: "31" }, { date: "2014-01-15", version: "32" }, { date: "2014-02-26", version: "33" }, { date: "2014-04-02", version: "34" }, { date: "2014-05-20", version: "35" }, { date: "2014-07-16", version: "36" }, { date: "2014-09-03", version: "37" }, { date: "2014-10-08", version: "38" }, { date: "2014-11-12", version: "39" }, { date: "2015-01-21", version: "40" }, { date: "2015-03-11", version: "41" }, { date: "2015-04-15", version: "42" }, { date: "2015-05-27", version: "43" }, { date: "2015-07-29", version: "44" }, { date: "2015-09-01", version: "45" }, { date: "2015-10-14", version: "46" }, { date: "2015-12-02", version: "47" }, { date: "2016-01-26", version: "48" }, { date: "2016-03-09", version: "49" }, { date: "2016-04-13", version: "50" }, { date: "2016-06-08", version: "51" }, { date: "2016-07-27", version: "52" }, { date: "2016-09-07", version: "53" }, { date: "2016-10-1\ +9", version: "54" }, { date: "2016-12-06", version: "55" }, { date: "2017-02-01", version: "56" }, { date: "2017-03-16", version: "57" }, { date: "2017-04-25", version: "58" }, { date: "2017-06-06", version: "59" }, { date: "2017-08-01", version: "60" }, { date: "2017-09-05", version: "61" }, { date: "2017-10-24", version: "62" }, { date: "2017-12-05", version: "63" }, { date: "2018-01-23", version: "64" }, { date: "2018-03-06", version: "65" }, { date: "2018-04-17", version: "66" }, { date: "2018-05-31", version: "67" }, { date: "2018-07-24", version: "68" }, { date: "2018-09-04", version: "69" }, { date: "2018-10-17", version: "70" }, { date: "2018-12-04", version: "71" }, { date: "2019-01-29", version: "72" }, { date: "2019-03-12", version: "73" }, { date: "2019-04-24", version: "74" }, { date: "2019-06-04", version: "75" }, { date: "2019-07-30", version: "76" }, { date: "2019-09-10", version: "77" }, { date: "2019-10-22", version: "78" }, { date: "2019-12-17", version: "79" }, { date: "\ +2020-02-04", version: "80" }, { date: "2020-04-07", version: "81" }, { date: "2020-05-19", version: "83" }, { date: "2020-07-27", version: "84" }, { date: "2020-08-25", version: "85" }, { date: "2020-10-20", version: "86" }, { date: "2020-11-17", version: "87" }, { date: "2021-01-19", version: "88" }, { date: "2021-03-02", version: "89" }, { date: "2021-04-13", version: "90" }, { date: "2021-05-25", version: "91" }, { date: "2021-07-20", version: "92" }, { date: "2021-08-31", version: "93" }, { date: "2021-09-21", version: "94" }, { date: "2021-10-19", version: "95" }, { date: "2021-11-15", version: "96" }, { date: "2022-01-04", version: "97" }, { date: "2022-02-01", version: "98" }, { date: "2022-03-01", version: "99" }, { date: "2022-03-29", version: "100" }, { date: "2022-04-26", version: "101" }, { date: "2022-05-24", version: "102" }, { date: "2022-06-21", version: "103" }, { date: "2022-08-02", version: "104" }, { date: "2022-09-02", version: "105" }, { date: "2022-09-27", version: "\ +106" }, { date: "2022-10-25", version: "107" }, { date: "2022-11-29", version: "108" }, { date: "2023-01-10", version: "109" }, { date: "2023-02-07", version: "110" }, { date: "2023-03-07", version: "111" }, { date: "2023-04-04", version: "112" }, { date: "2023-05-02", version: "113" }, { date: "2023-05-30", version: "114" }, { date: "2023-07-21", version: "115" }, { date: "2023-08-15", version: "116" }, { date: "2023-09-12", version: "117" }, { date: "2023-10-10", version: "118" }, { date: "2023-10-31", version: "119" }, { date: "2023-12-05", version: "120" }, { date: "2024-01-23", version: "121" }, { date: "2024-02-20", version: "122" }, { date: "2024-03-19", version: "123" }, { date: "2024-04-16", version: "124" }, { date: "2024-05-14", version: "125" }, { date: "2024-06-11", version: "126" }, { date: "2024-07-23", version: "127" }, { date: "2024-08-20", version: "128" }, { date: "2024-09-17", version: "129" }, { date: "2024-10-15", version: "130" }, { date: "2024-11-12", version: "\ +131" }, { date: "2025-01-14", version: "132" }, { date: "2025-02-04", version: "133" }, { date: "2025-03-04", version: "134" }, { date: "2025-04-01", version: "135" }, { date: "2025-04-29", version: "136" }, { date: "2025-05-27", version: "137" }, { date: "2025-06-24", version: "138" }, { date: "2025-08-05", version: "139" }, { date: "2025-09-02", version: "140" }, { date: "2025-09-30", version: "141" }, { date: "2025-10-28", version: "142" }, { date: "2025-12-02", version: "143" }, { date: "2026-01-13", version: "144" }, { date: "2026-02-10", version: "145" }, { date: "2026-03-10", version: "146" }] }, edge: { name: "Edge", releases: [{ date: "2015-07-29", version: "12" }, { date: "2015-11-12", version: "13" }, { date: "2016-08-02", version: "14" }, { date: "2017-04-05", version: "15" }, { date: "2017-10-17", version: "16" }, { date: "2018-04-30", version: "17" }, { date: "2018-10-02", version: "18" }, { date: "2020-01-15", version: "79" }, { date: "2020-02-07", version: "80" }, { date: "\ +2020-04-13", version: "81" }, { date: "2020-05-21", version: "83" }, { date: "2020-07-16", version: "84" }, { date: "2020-08-27", version: "85" }, { date: "2020-10-09", version: "86" }, { date: "2020-11-19", version: "87" }, { date: "2021-01-21", version: "88" }, { date: "2021-03-04", version: "89" }, { date: "2021-04-15", version: "90" }, { date: "2021-05-27", version: "91" }, { date: "2021-07-22", version: "92" }, { date: "2021-09-02", version: "93" }, { date: "2021-09-24", version: "94" }, { date: "2021-10-21", version: "95" }, { date: "2021-11-19", version: "96" }, { date: "2022-01-06", version: "97" }, { date: "2022-02-03", version: "98" }, { date: "2022-03-03", version: "99" }, { date: "2022-04-01", version: "100" }, { date: "2022-04-28", version: "101" }, { date: "2022-05-31", version: "102" }, { date: "2022-06-23", version: "103" }, { date: "2022-08-05", version: "104" }, { date: "2022-09-01", version: "105" }, { date: "2022-10-03", version: "106" }, { date: "2022-10-27", version: "\ +107" }, { date: "2022-12-05", version: "108" }, { date: "2023-01-12", version: "109" }, { date: "2023-02-09", version: "110" }, { date: "2023-03-13", version: "111" }, { date: "2023-04-06", version: "112" }, { date: "2023-05-05", version: "113" }, { date: "2023-06-02", version: "114" }, { date: "2023-07-21", version: "115" }, { date: "2023-08-21", version: "116" }, { date: "2023-09-15", version: "117" }, { date: "2023-10-13", version: "118" }, { date: "2023-11-02", version: "119" }, { date: "2023-12-07", version: "120" }, { date: "2024-01-25", version: "121" }, { date: "2024-02-23", version: "122" }, { date: "2024-03-22", version: "123" }, { date: "2024-04-18", version: "124" }, { date: "2024-05-17", version: "125" }, { date: "2024-06-13", version: "126" }, { date: "2024-07-25", version: "127" }, { date: "2024-08-22", version: "128" }, { date: "2024-09-19", version: "129" }, { date: "2024-10-17", version: "130" }, { date: "2024-11-14", version: "131" }, { date: "2025-01-17", version: "\ +132" }, { date: "2025-02-06", version: "133" }, { date: "2025-03-06", version: "134" }, { date: "2025-04-04", version: "135" }, { date: "2025-05-01", version: "136" }, { date: "2025-05-29", version: "137" }, { date: "2025-06-26", version: "138" }, { date: "2025-08-07", version: "139" }, { date: "2025-09-05", version: "140" }, { date: "2025-10-03", version: "141" }, { date: "2025-10-31", version: "142" }, { date: "2025-12-05", version: "143" }, { date: "2026-01-21", version: "144" }, { date: "2026-02-14", version: "145" }] }, firefox: { name: "Firefox", releases: [{ date: "2004-11-09", version: "1" }, { date: "2005-11-29", version: "1.5" }, { date: "2006-10-24", version: "2" }, { date: "2008-06-17", version: "3" }, { date: "2009-06-30", version: "3.5" }, { date: "2010-01-21", version: "3.6" }, { date: "2011-03-22", version: "4" }, { date: "2011-06-21", version: "5" }, { date: "2011-08-16", version: "6" }, { date: "2011-09-27", version: "7" }, { date: "2011-11-08", version: "8" }, { date: "\ +2011-12-20", version: "9" }, { date: "2012-01-31", version: "10" }, { date: "2012-03-13", version: "11" }, { date: "2012-04-24", version: "12" }, { date: "2012-06-05", version: "13" }, { date: "2012-07-17", version: "14" }, { date: "2012-08-28", version: "15" }, { date: "2012-10-09", version: "16" }, { date: "2012-11-20", version: "17" }, { date: "2013-01-08", version: "18" }, { date: "2013-02-19", version: "19" }, { date: "2013-04-02", version: "20" }, { date: "2013-05-14", version: "21" }, { date: "2013-06-25", version: "22" }, { date: "2013-08-06", version: "23" }, { date: "2013-09-17", version: "24" }, { date: "2013-10-29", version: "25" }, { date: "2013-12-10", version: "26" }, { date: "2014-02-04", version: "27" }, { date: "2014-03-18", version: "28" }, { date: "2014-04-29", version: "29" }, { date: "2014-06-10", version: "30" }, { date: "2014-07-22", version: "31" }, { date: "2014-09-02", version: "32" }, { date: "2014-10-14", version: "33" }, { date: "2014-12-01", version: "34" }, + { date: "2015-01-13", version: "35" }, { date: "2015-02-24", version: "36" }, { date: "2015-03-31", version: "37" }, { date: "2015-05-12", version: "38" }, { date: "2015-07-02", version: "39" }, { date: "2015-08-11", version: "40" }, { date: "2015-09-22", version: "41" }, { date: "2015-11-03", version: "42" }, { date: "2015-12-15", version: "43" }, { date: "2016-01-26", version: "44" }, { date: "2016-03-08", version: "45" }, { date: "2016-04-26", version: "46" }, { date: "2016-06-07", version: "47" }, { date: "2016-08-02", version: "48" }, { date: "2016-09-20", version: "49" }, { date: "2016-11-15", version: "50" }, { date: "2017-01-24", version: "51" }, { date: "2017-03-07", version: "52" }, { date: "2017-04-19", version: "53" }, { date: "2017-06-13", version: "54" }, { date: "2017-08-08", version: "55" }, { date: "2017-09-28", version: "56" }, { date: "2017-11-14", version: "57" }, { date: "2018-01-23", version: "58" }, { date: "2018-03-13", version: "59" }, { date: "2018-05-09", + version: "60" }, { date: "2018-06-26", version: "61" }, { date: "2018-09-05", version: "62" }, { date: "2018-10-23", version: "63" }, { date: "2018-12-11", version: "64" }, { date: "2019-01-29", version: "65" }, { date: "2019-03-19", version: "66" }, { date: "2019-05-21", version: "67" }, { date: "2019-07-09", version: "68" }, { date: "2019-09-03", version: "69" }, { date: "2019-10-22", version: "70" }, { date: "2019-12-10", version: "71" }, { date: "2020-01-07", version: "72" }, { date: "2020-02-11", version: "73" }, { date: "2020-03-10", version: "74" }, { date: "2020-04-07", version: "75" }, { date: "2020-05-05", version: "76" }, { date: "2020-06-02", version: "77" }, { date: "2020-06-30", version: "78" }, { date: "2020-07-28", version: "79" }, { date: "2020-08-25", version: "80" }, { date: "2020-09-22", version: "81" }, { date: "2020-10-20", version: "82" }, { date: "2020-11-17", version: "83" }, { date: "2020-12-15", version: "84" }, { date: "2021-01-26", version: "85" }, { date: "\ +2021-02-23", version: "86" }, { date: "2021-03-23", version: "87" }, { date: "2021-04-19", version: "88" }, { date: "2021-06-01", version: "89" }, { date: "2021-07-13", version: "90" }, { date: "2021-08-10", version: "91" }, { date: "2021-09-07", version: "92" }, { date: "2021-10-05", version: "93" }, { date: "2021-11-02", version: "94" }, { date: "2021-12-07", version: "95" }, { date: "2022-01-11", version: "96" }, { date: "2022-02-08", version: "97" }, { date: "2022-03-08", version: "98" }, { date: "2022-04-05", version: "99" }, { date: "2022-05-03", version: "100" }, { date: "2022-05-31", version: "101" }, { date: "2022-06-28", version: "102" }, { date: "2022-07-26", version: "103" }, { date: "2022-08-23", version: "104" }, { date: "2022-09-20", version: "105" }, { date: "2022-10-18", version: "106" }, { date: "2022-11-15", version: "107" }, { date: "2022-12-13", version: "108" }, { date: "2023-01-17", version: "109" }, { date: "2023-02-14", version: "110" }, { date: "2023-03-14", version: "\ +111" }, { date: "2023-04-11", version: "112" }, { date: "2023-05-09", version: "113" }, { date: "2023-06-06", version: "114" }, { date: "2023-07-04", version: "115" }, { date: "2023-08-01", version: "116" }, { date: "2023-08-29", version: "117" }, { date: "2023-09-26", version: "118" }, { date: "2023-10-24", version: "119" }, { date: "2023-11-21", version: "120" }, { date: "2023-12-19", version: "121" }, { date: "2024-01-23", version: "122" }, { date: "2024-02-20", version: "123" }, { date: "2024-03-19", version: "124" }, { date: "2024-04-16", version: "125" }, { date: "2024-05-14", version: "126" }, { date: "2024-06-11", version: "127" }, { date: "2024-07-09", version: "128" }, { date: "2024-08-06", version: "129" }, { date: "2024-09-03", version: "130" }, { date: "2024-10-01", version: "131" }, { date: "2024-10-29", version: "132" }, { date: "2024-11-26", version: "133" }, { date: "2025-01-07", version: "134" }, { date: "2025-02-04", version: "135" }, { date: "2025-03-04", version: "\ +136" }, { date: "2025-04-01", version: "137" }, { date: "2025-04-29", version: "138" }, { date: "2025-05-27", version: "139" }, { date: "2025-06-24", version: "140" }, { date: "2025-07-22", version: "141" }, { date: "2025-08-19", version: "142" }, { date: "2025-09-16", version: "143" }, { date: "2025-10-14", version: "144" }, { date: "2025-11-11", version: "145" }, { date: "2025-12-09", version: "146" }, { date: "2026-01-13", version: "147" }, { date: "2026-02-24", version: "148" }] }, firefox_android: { name: "Firefox for Android", releases: [{ date: "2011-03-29", version: "4" }, { date: "2011-06-21", version: "5" }, { date: "2011-08-16", version: "6" }, { date: "2011-09-27", version: "7" }, { date: "2011-11-08", version: "8" }, { date: "2011-12-21", version: "9" }, { date: "2012-01-31", version: "10" }, { date: "2012-06-26", version: "14" }, { date: "2012-08-28", version: "15" }, { date: "2012-10-09", version: "16" }, { date: "2012-11-20", version: "17" }, { date: "2013-01-08", version: "\ +18" }, { date: "2013-02-19", version: "19" }, { date: "2013-04-02", version: "20" }, { date: "2013-05-14", version: "21" }, { date: "2013-06-25", version: "22" }, { date: "2013-08-06", version: "23" }, { date: "2013-09-17", version: "24" }, { date: "2013-10-29", version: "25" }, { date: "2013-12-10", version: "26" }, { date: "2014-02-04", version: "27" }, { date: "2014-03-18", version: "28" }, { date: "2014-04-29", version: "29" }, { date: "2014-06-10", version: "30" }, { date: "2014-07-22", version: "31" }, { date: "2014-09-02", version: "32" }, { date: "2014-10-14", version: "33" }, { date: "2014-12-01", version: "34" }, { date: "2015-01-13", version: "35" }, { date: "2015-02-27", version: "36" }, { date: "2015-03-31", version: "37" }, { date: "2015-05-12", version: "38" }, { date: "2015-07-02", version: "39" }, { date: "2015-08-11", version: "40" }, { date: "2015-09-22", version: "41" }, { date: "2015-11-03", version: "42" }, { date: "2015-12-15", version: "43" }, { date: "2016-01-2\ +6", version: "44" }, { date: "2016-03-08", version: "45" }, { date: "2016-04-26", version: "46" }, { date: "2016-06-07", version: "47" }, { date: "2016-08-02", version: "48" }, { date: "2016-09-20", version: "49" }, { date: "2016-11-15", version: "50" }, { date: "2017-01-24", version: "51" }, { date: "2017-03-07", version: "52" }, { date: "2017-04-19", version: "53" }, { date: "2017-06-13", version: "54" }, { date: "2017-08-08", version: "55" }, { date: "2017-09-28", version: "56" }, { date: "2017-11-28", version: "57" }, { date: "2018-01-22", version: "58" }, { date: "2018-03-13", version: "59" }, { date: "2018-05-09", version: "60" }, { date: "2018-06-26", version: "61" }, { date: "2018-09-05", version: "62" }, { date: "2018-10-23", version: "63" }, { date: "2018-12-11", version: "64" }, { date: "2019-01-29", version: "65" }, { date: "2019-03-19", version: "66" }, { date: "2019-05-21", version: "67" }, { date: "2019-07-09", version: "68" }, { date: "2020-07-28", version: "79" }, { date: "\ +2020-08-31", version: "80" }, { date: "2020-09-22", version: "81" }, { date: "2020-10-20", version: "82" }, { date: "2020-11-17", version: "83" }, { date: "2020-12-15", version: "84" }, { date: "2021-01-26", version: "85" }, { date: "2021-02-23", version: "86" }, { date: "2021-03-23", version: "87" }, { date: "2021-04-19", version: "88" }, { date: "2021-06-01", version: "89" }, { date: "2021-07-13", version: "90" }, { date: "2021-08-10", version: "91" }, { date: "2021-09-07", version: "92" }, { date: "2021-10-05", version: "93" }, { date: "2021-11-02", version: "94" }, { date: "2021-12-07", version: "95" }, { date: "2022-01-11", version: "96" }, { date: "2022-02-08", version: "97" }, { date: "2022-03-08", version: "98" }, { date: "2022-04-05", version: "99" }, { date: "2022-05-03", version: "100" }, { date: "2022-05-31", version: "101" }, { date: "2022-06-28", version: "102" }, { date: "2022-07-26", version: "103" }, { date: "2022-08-23", version: "104" }, { date: "2022-09-20", version: "\ +105" }, { date: "2022-10-18", version: "106" }, { date: "2022-11-15", version: "107" }, { date: "2022-12-13", version: "108" }, { date: "2023-01-17", version: "109" }, { date: "2023-02-14", version: "110" }, { date: "2023-03-14", version: "111" }, { date: "2023-04-11", version: "112" }, { date: "2023-05-09", version: "113" }, { date: "2023-06-06", version: "114" }, { date: "2023-07-04", version: "115" }, { date: "2023-08-01", version: "116" }, { date: "2023-08-29", version: "117" }, { date: "2023-09-26", version: "118" }, { date: "2023-10-24", version: "119" }, { date: "2023-11-21", version: "120" }, { date: "2023-12-19", version: "121" }, { date: "2024-01-23", version: "122" }, { date: "2024-02-20", version: "123" }, { date: "2024-03-19", version: "124" }, { date: "2024-04-16", version: "125" }, { date: "2024-05-14", version: "126" }, { date: "2024-06-11", version: "127" }, { date: "2024-07-09", version: "128" }, { date: "2024-08-06", version: "129" }, { date: "2024-09-03", version: "\ +130" }, { date: "2024-10-01", version: "131" }, { date: "2024-10-29", version: "132" }, { date: "2024-11-26", version: "133" }, { date: "2025-01-07", version: "134" }, { date: "2025-02-04", version: "135" }, { date: "2025-03-04", version: "136" }, { date: "2025-04-01", version: "137" }, { date: "2025-04-29", version: "138" }, { date: "2025-05-27", version: "139" }, { date: "2025-06-24", version: "140" }, { date: "2025-07-22", version: "141" }, { date: "2025-08-19", version: "142" }, { date: "2025-09-16", version: "143" }, { date: "2025-10-14", version: "144" }, { date: "2025-11-11", version: "145" }, { date: "2025-12-09", version: "146" }, { date: "2026-01-13", version: "147" }, { date: "2026-02-24", version: "148" }] }, safari: { name: "Safari", releases: [{ date: "2003-06-23", version: "1" }, { date: "2003-10-24", version: "1.1" }, { date: "2004-02-02", version: "1.2" }, { date: "2005-04-15", version: "1.3" }, { date: "2005-04-29", version: "2" }, { date: "2007-10-26", version: "3" }, + { date: "2008-03-18", version: "3.1" }, { date: "2009-06-08", version: "4" }, { date: "2010-06-07", version: "5" }, { date: "2011-07-20", version: "5.1" }, { date: "2012-07-25", version: "6" }, { date: "2013-10-22", version: "7" }, { date: "2014-10-16", version: "8" }, { date: "2015-09-30", version: "9" }, { date: "2016-03-21", version: "9.1" }, { date: "2016-09-20", version: "10" }, { date: "2017-03-27", version: "10.1" }, { date: "2017-09-19", version: "11" }, { date: "2018-04-12", version: "11.1" }, { date: "2018-09-17", version: "12" }, { date: "2019-03-25", version: "12.1" }, { date: "2019-09-19", version: "13" }, { date: "2020-03-24", version: "13.1" }, { date: "2020-09-16", version: "14" }, { date: "2021-04-26", version: "14.1" }, { date: "2021-09-20", version: "15" }, { date: "2021-10-25", version: "15.1" }, { date: "2021-12-13", version: "15.2" }, { date: "2022-01-26", version: "15.3" }, { date: "2022-03-14", version: "15.4" }, { date: "2022-05-16", version: "15.5" }, { date: "\ +2022-07-20", version: "15.6" }, { date: "2022-09-12", version: "16" }, { date: "2022-10-24", version: "16.1" }, { date: "2022-12-13", version: "16.2" }, { date: "2023-01-23", version: "16.3" }, { date: "2023-03-27", version: "16.4" }, { date: "2023-05-18", version: "16.5" }, { date: "2023-07-24", version: "16.6" }, { date: "2023-09-18", version: "17" }, { date: "2023-10-25", version: "17.1" }, { date: "2023-12-11", version: "17.2" }, { date: "2024-01-22", version: "17.3" }, { date: "2024-03-05", version: "17.4" }, { date: "2024-05-13", version: "17.5" }, { date: "2024-07-29", version: "17.6" }, { date: "2024-09-16", version: "18" }, { date: "2024-10-28", version: "18.1" }, { date: "2024-12-11", version: "18.2" }, { date: "2025-01-27", version: "18.3" }, { date: "2025-03-31", version: "18.4" }, { date: "2025-05-12", version: "18.5" }, { date: "2025-07-29", version: "18.6" }, { date: "2025-09-15", version: "26" }, { date: "2025-11-03", version: "26.1" }, { date: "2025-12-12", version: "2\ +6.2" }, { date: "2026-02-11", version: "26.3" }] }, safari_ios: { name: "Safari on iOS", releases: [{ date: "2007-06-29", version: "1" }, { date: "2008-07-11", version: "2" }, { date: "2009-06-17", version: "3" }, { date: "2010-04-03", version: "3.2" }, { date: "2010-06-21", version: "4" }, { date: "2010-11-22", version: "4.2" }, { date: "2011-10-12", version: "5" }, { date: "2012-09-10", version: "6" }, { date: "2013-09-18", version: "7" }, { date: "2014-09-17", version: "8" }, { date: "2015-09-16", version: "9" }, { date: "2016-03-21", version: "9.3" }, { date: "2016-09-13", version: "10" }, { date: "2017-03-27", version: "10.3" }, { date: "2017-09-19", version: "11" }, { date: "2018-03-29", version: "11.3" }, { date: "2018-09-17", version: "12" }, { date: "2019-03-25", version: "12.2" }, { date: "2019-09-19", version: "13" }, { date: "2020-03-24", version: "13.4" }, { date: "2020-09-16", version: "14" }, { date: "2021-04-26", version: "14.5" }, { date: "2021-09-20", version: "15" }, + { date: "2021-10-25", version: "15.1" }, { date: "2021-12-13", version: "15.2" }, { date: "2022-01-26", version: "15.3" }, { date: "2022-03-14", version: "15.4" }, { date: "2022-05-16", version: "15.5" }, { date: "2022-07-20", version: "15.6" }, { date: "2022-09-12", version: "16" }, { date: "2022-10-24", version: "16.1" }, { date: "2022-12-13", version: "16.2" }, { date: "2023-01-23", version: "16.3" }, { date: "2023-03-27", version: "16.4" }, { date: "2023-05-18", version: "16.5" }, { date: "2023-07-24", version: "16.6" }, { date: "2023-09-18", version: "17" }, { date: "2023-10-25", version: "17.1" }, { date: "2023-12-11", version: "17.2" }, { date: "2024-01-22", version: "17.3" }, { date: "2024-03-05", version: "17.4" }, { date: "2024-05-13", version: "17.5" }, { date: "2024-07-29", version: "17.6" }, { date: "2024-09-16", version: "18" }, { date: "2024-10-28", version: "18.1" }, { date: "2024-12-11", version: "18.2" }, { date: "2025-01-27", version: "18.3" }, { date: "2025-03-3\ +1", version: "18.4" }, { date: "2025-05-12", version: "18.5" }, { date: "2025-07-29", version: "18.6" }, { date: "2025-09-15", version: "26" }, { date: "2025-11-03", version: "26.1" }, { date: "2025-12-12", version: "26.2" }, { date: "2026-02-11", version: "26.3" }] } }, features: { a: { compat_features: ["api.HTMLAnchorElement", "api.HTMLAnchorElement.hash", "api.HTMLAnchorElement.host", "api.HTMLAnchorElement.hostname", "api.HTMLAnchorElement.href", "api.HTMLAnchorElement.hreflang", "api.HTMLAnchorElement.origin", "api.HTMLAnchorElement.password", "api.HTMLAnchorElement.pathname", "api.HTMLAnchorElement.port", "api.HTMLAnchorElement.protocol", "api.HTMLAnchorElement.rel", "api.HTMLAnchorElement.relList", "api.HTMLAnchorElement.search", "api.HTMLAnchorElement.target", "api.HTMLAnchorElement.text", "api.HTMLAnchorElement.toString", "api.HTMLAnchorElement.type", "api.HTMLAnchorElement.username", "html.elements.a", "html.elements.a.href", "html.elements.a.href.href_sms", "html.elements.a\ +.href.href_top", "html.elements.a.hreflang", "html.elements.a.implicit_noopener", "html.elements.a.rel", "html.elements.a.rel.noopener", "html.elements.a.rel.noreferrer", "html.elements.a.target", "html.elements.a.type"], description: "The element creates a hyperlink to any resource that's accessible via a URL, such as web pages, files, email addresses, or locations within the same page.", description_html: "The <a> element creates a hyperlink to any resource that's accessible via a URL, such as web pages, files, email addresses, or locations within the same page.", group: ["html-elements"], kind: "feature", name: "", spec: ["https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "api.HTMLAnchorElement": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "\ +18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.hash": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.host": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.hostname": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.href": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", + firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.hreflang": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.origin": { baseline: "high", baseline_high_date: "2020-10-30", baseline_low_date: "2018-04-30", support: { chrome: "8", chrome_android: "18", edge: "17", firefox: "26", firefox_android: "26", safari: "5.1", safari_ios: "5" } }, "api.HTMLAnchorElement.password": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "32", chrome_android: "32", edge: "79", firefox: "26", firefox_android: "26", safari: "10", safari_ios: "10" } }, "api.HTMLAnchorElement.pathname": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "\ +12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.port": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.protocol": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.rel": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.relList": { baseline: "high", baseline_high_date: "2021-04-02", baseline_low_date: "2018-10-02", support: { chrome: "65", chrome_android: "65", edge: "18", firefox: "\ +30", firefox_android: "30", safari: "9", safari_ios: "9" } }, "api.HTMLAnchorElement.search": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.target": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.text": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.toString": { baseline: "high", baseline_high_date: "2019-01-27", baseline_low_date: "2016-07-27", support: { chrome: "52", chrome_android: "52", edge: "12", firefox: "22", firefox_android: "\ +22", safari: "3", safari_ios: "1" } }, "api.HTMLAnchorElement.type": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.HTMLAnchorElement.username": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "32", chrome_android: "32", edge: "79", firefox: "26", firefox_android: "26", safari: "10", safari_ios: "10" } }, "html.elements.a": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "html.elements.a.href": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "\ +1" } }, "html.elements.a.href.href_sms": { baseline: false, support: { firefox: "12", firefox_android: "14" } }, "html.elements.a.href.href_top": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "10", firefox_android: "10", safari: "≤4", safari_ios: "≤3.2" } }, "html.elements.a.hreflang": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "html.elements.a.implicit_noopener": { baseline: "high", baseline_high_date: "2023-07-21", baseline_low_date: "2021-01-21", support: { chrome: "88", chrome_android: "88", edge: "88", firefox: "79", firefox_android: "79", safari: "12.1", safari_ios: "12.2" } }, "html.elements.a.rel": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "\ +1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "html.elements.a.rel.noopener": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "49", chrome_android: "49", edge: "79", firefox: "52", firefox_android: "52", safari: "10.1", safari_ios: "10.3" } }, "html.elements.a.rel.noreferrer": { baseline: "high", baseline_high_date: "2018-05-12", baseline_low_date: "2015-11-12", support: { chrome: "16", chrome_android: "18", edge: "13", firefox: "33", firefox_android: "33", safari: "5", safari_ios: "4.2" } }, "html.elements.a.target": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "html.elements.a.type": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "\ +18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, abbr: { compat_features: ["html.elements.abbr"], description: "The HTML element represents an abbreviation or acronym.", description_html: "The <abbr> HTML element represents an abbreviation or acronym.", group: ["html-elements"], kind: "feature", name: "", spec: ["https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-abbr-element"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "html.elements.abbr": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "2", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "4", safari_ios: "3.2" } } }, support: { chrome: "2", chrome_android: "18", edge: "\ +12", firefox: "1", firefox_android: "4", safari: "4", safari_ios: "3.2" } } }, "abortable-fetch": { compat_features: ["api.Request.signal", "api.fetch.init_signal_parameter"], description: "If you construct a fetch request with an AbortSignal, you can cancel the request.", description_html: "If you construct a fetch request with an AbortSignal, you can cancel the request.", kind: "feature", name: "Abortable fetch", spec: ["https://fetch.spec.whatwg.org/#ref-for-dom-request-signal%E2%91%A1"], status: { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", by_compat_key: { "api.Request.signal": { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } }, "api.fetch.init_signal_parameter": { baseline: "high", baseline_high_date: "2020-10-17", baseline_low_date: "2018-04-17", support: { + chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "11.1", safari_ios: "11.3" } } }, support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } } }, aborting: { caniuse: ["abortcontroller"], compat_features: ["api.AbortController", "api.AbortController.AbortController", "api.AbortController.abort", "api.AbortController.abort.reason_parameter", "api.AbortController.signal", "api.AbortSignal", "api.AbortSignal.abort_event", "api.AbortSignal.abort_static", "api.AbortSignal.abort_static.reason_parameter", "api.AbortSignal.aborted", "api.AbortSignal.reason", "api.AbortSignal.throwIfAborted"], description: "The AbortController and AbortSignal APIs allow you to cancel an ongoing operation, such as a fetch() request.", description_html: "The AbortController and AbortSignal APIs allow you to cancel an ongoing operation, such as a fetch() request.", kind: "feature", name: "AbortController and AbortSignal", spec: ["https://dom.spec.whatwg.org/#aborting-ongoing-activities"], status: { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", by_compat_key: { "api.AbortController": { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } }, "api.AbortController.AbortController": { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } }, "api.AbortController.abort": { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "\ +12.2" } }, "api.AbortController.abort.reason_parameter": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "98", chrome_android: "98", edge: "98", firefox: "97", firefox_android: "97", safari: "15.4", safari_ios: "15.4" } }, "api.AbortController.signal": { baseline: "high", baseline_high_date: "2021-09-25", baseline_low_date: "2019-03-25", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } }, "api.AbortSignal": { baseline: "high", baseline_high_date: "2020-10-17", baseline_low_date: "2018-04-17", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "11.1", safari_ios: "11.3" } }, "api.AbortSignal.abort_event": { baseline: "high", baseline_high_date: "2020-10-17", baseline_low_date: "2018-04-17", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "\ +11.1", safari_ios: "11.3" } }, "api.AbortSignal.abort_static": { baseline: "high", baseline_high_date: "2024-03-20", baseline_low_date: "2021-09-20", support: { chrome: "93", chrome_android: "93", edge: "93", firefox: "88", firefox_android: "88", safari: "15", safari_ios: "15" } }, "api.AbortSignal.abort_static.reason_parameter": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "98", chrome_android: "98", edge: "98", firefox: "97", firefox_android: "97", safari: "15.4", safari_ios: "15.4" } }, "api.AbortSignal.aborted": { baseline: "high", baseline_high_date: "2020-10-17", baseline_low_date: "2018-04-17", support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "11.1", safari_ios: "11.3" } }, "api.AbortSignal.reason": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "98", chrome_android: "98", edge: "98", firefox: "97", firefox_android: "\ +97", safari: "15.4", safari_ios: "15.4" } }, "api.AbortSignal.throwIfAborted": { baseline: "high", baseline_high_date: "2024-10-01", baseline_low_date: "2022-04-01", support: { chrome: "100", chrome_android: "100", edge: "100", firefox: "97", firefox_android: "97", safari: "15.4", safari_ios: "15.4" } } }, support: { chrome: "66", chrome_android: "66", edge: "16", firefox: "57", firefox_android: "57", safari: "12.1", safari_ios: "12.2" } } }, "abortsignal-any": { compat_features: ["api.AbortSignal.any_static"], description: "The AbortSignal.any() static method combines an iterable of abort signals into a single signal, with the abort reason taken from the first signal to abort.", description_html: "The AbortSignal.any() static method combines an iterable of abort signals into a single signal, with the abort reason taken from the first signal to abort.", kind: "feature", name: "AbortSignal.any()", spec: ["https://dom.spec.whatwg.org/#dom-abortsignal-any"], status: { baseline: "\ +low", baseline_low_date: "2024-03-19", by_compat_key: { "api.AbortSignal.any_static": { baseline: "low", baseline_low_date: "2024-03-19", support: { chrome: "116", chrome_android: "116", edge: "116", firefox: "124", firefox_android: "124", safari: "17.4", safari_ios: "17.4" } } }, support: { chrome: "116", chrome_android: "116", edge: "116", firefox: "124", firefox_android: "124", safari: "17.4", safari_ios: "17.4" } } }, "abortsignal-timeout": { compat_features: ["api.AbortSignal.timeout_static"], description: "The AbortSignal.timeout() static method returns an abort signal that automatically aborts after a specified duration.", description_html: "The AbortSignal.timeout() static method returns an abort signal that automatically aborts after a specified duration.", kind: "feature", name: "AbortSignal.timeout()", spec: ["https://dom.spec.whatwg.org/#dom-abortsignal-timeout"], status: { baseline: "low", baseline_low_date: "2024-04-18", by_compat_key: { "api.AbortSignal.time\ +out_static": { baseline: "low", baseline_low_date: "2024-04-18", support: { chrome: "124", chrome_android: "124", edge: "124", firefox: "100", firefox_android: "100", safari: "16", safari_ios: "16" } } }, support: { chrome: "124", chrome_android: "124", edge: "124", firefox: "100", firefox_android: "100", safari: "16", safari_ios: "16" } } }, "abs-sign": { compat_features: ["css.types.abs", "css.types.sign"], description: "The abs() and sign() CSS functions compute the absolute value or the sign of the input.", description_html: "The abs() and sign() CSS functions compute the absolute value or the sign of the input.", group: ["css"], kind: "feature", name: "abs() and sign()", spec: ["https://drafts.csswg.org/css-values-4/#sign-funcs"], status: { baseline: "low", baseline_low_date: "2025-06-26", by_compat_key: { "css.types.abs": { baseline: "low", baseline_low_date: "2025-06-26", support: { chrome: "138", chrome_android: "138", edge: "138", firefox: "118", firefox_android: "\ +118", safari: "15.4", safari_ios: "15.4" } }, "css.types.sign": { baseline: "low", baseline_low_date: "2025-06-26", support: { chrome: "138", chrome_android: "138", edge: "138", firefox: "118", firefox_android: "118", safari: "15.4", safari_ios: "15.4" } } }, support: { chrome: "138", chrome_android: "138", edge: "138", firefox: "118", firefox_android: "118", safari: "15.4", safari_ios: "15.4" } } }, "absolute-positioning": { compat_features: ["css.properties.align-self.position_absolute_context", "css.properties.justify-self.position_absolute_context", "css.properties.place-self.position_absolute_context", "css.properties.position.absolute"], description: "The position: absolute CSS declaration removes an element from the normal flow and positions it relative to its containing block, which is often the root element, or closest positioned ancestor.", description_html: "The position: absolute CSS declaration removes an element from the normal flow and positions it relative \ +to its containing block, which is often the root element, or closest positioned ancestor.", group: ["positioning"], kind: "feature", name: "Absolute positioning", spec: ["https://drafts.csswg.org/css-position-3/#abspos-insets"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "css.properties.align-self.position_absolute_context": { baseline: false, support: { chrome: "122", chrome_android: "122", edge: "122", firefox: "134", firefox_android: "134" } }, "css.properties.justify-self.position_absolute_context": { baseline: false, support: { chrome: "122", chrome_android: "122", edge: "122", firefox: "134", firefox_android: "134" } }, "css.properties.place-self.position_absolute_context": { baseline: false, support: { chrome: "122", chrome_android: "122", edge: "122", firefox: "134", firefox_android: "134" } }, "css.properties.position.absolute": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07\ +-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, accelerometer: { compat_features: ["api.Accelerometer", "api.Accelerometer.Accelerometer", "api.Accelerometer.x", "api.Accelerometer.y", "api.Accelerometer.z", "api.GravitySensor", "api.GravitySensor.GravitySensor", "api.LinearAccelerationSensor", "api.LinearAccelerationSensor.LinearAccelerationSensor", "api.Permissions.permission_accelerometer", "html.elements.iframe.allow.accelerometer", "http.headers.Permissions-Policy.accelerometer"], description: "The Accelerometer, LinearAccelerationSensor and GravitySensor APIs read the acceleration applied to a device in three dimensions, either including the effect of gravity, without its effect, or only its effect, respectively.", description_html: "The Accelerometer, \ +LinearAccelerationSensor and GravitySensor APIs read the acceleration applied to a device in three dimensions, either including the effect of gravity, without its effect, or only its effect, respectively.", group: ["sensors"], kind: "feature", name: "Accelerometer", spec: ["https://w3c.github.io/accelerometer/"], status: { baseline: false, by_compat_key: { "api.Accelerometer": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.Accelerometer.Accelerometer": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.Accelerometer.x": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.Accelerometer.y": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.Accelerometer.z": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.GravitySensor": { baseline: false, support: { chrome: "91", chrome_android: "\ +91", edge: "91" } }, "api.GravitySensor.GravitySensor": { baseline: false, support: { chrome: "91", chrome_android: "91", edge: "91" } }, "api.LinearAccelerationSensor": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.LinearAccelerationSensor.LinearAccelerationSensor": { baseline: false, support: { chrome: "67", chrome_android: "67", edge: "79" } }, "api.Permissions.permission_accelerometer": { baseline: false, support: { chrome: "62", chrome_android: "62", edge: "79" } }, "html.elements.iframe.allow.accelerometer": { baseline: false, support: { chrome: "66", chrome_android: "66", edge: "79" } }, "http.headers.Permissions-Policy.accelerometer": { baseline: false, support: { chrome: "88", chrome_android: "88", edge: "88" } } }, support: { chrome: "91", chrome_android: "91", edge: "91" } } }, "accent-color": { compat_features: ["css.properties.accent-color", "css.properties.accent-color.auto"], description: "The accent-color CSS property sets a colo\ +r for checkboxes, radio buttons, and other form controls.", description_html: "The accent-color CSS property sets a color for checkboxes, radio buttons, and other form controls.", group: ["css"], kind: "feature", name: "accent-color", spec: ["https://drafts.csswg.org/css-ui-4/#widget-accent"], status: { baseline: false, by_compat_key: { "css.properties.accent-color": { baseline: false, support: { chrome: "93", edge: "93", firefox: "92", firefox_android: "92" } }, "css.properties.accent-color.auto": { baseline: false, support: { chrome: "93", edge: "93", firefox: "92", firefox_android: "92" } } }, support: { chrome: "93", edge: "93", firefox: "92", firefox_android: "92" } } }, accesskey: { compat_features: ["api.HTMLElement.accessKey", "api.HTMLElement.accessKeyLabel", "html.global_attributes.accesskey"], description: "The accesskey global HTML attribute gives a hint for generating a keyboard shortcut for the current element. The attribute value must consist of a single pri\ +ntable character.", description_html: "The accesskey global HTML attribute gives a hint for generating a keyboard shortcut for the current element. The attribute value must consist of a single printable character.", kind: "feature", name: "accesskey", spec: ["https://html.spec.whatwg.org/multipage/interaction.html#the-accesskey-attribute"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "api.HTMLElement.accessKey": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "17", chrome_android: "18", edge: "12", firefox: "5", firefox_android: "5", safari: "6", safari_ios: "6" } }, "api.HTMLElement.accessKeyLabel": { baseline: false, support: { firefox: "8", firefox_android: "8", safari: "14", safari_ios: "14" } }, "html.global_attributes.accesskey": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "\ +18", edge: "12", firefox: "1", firefox_android: "4", safari: "≤4", safari_ios: "≤3.2" } } }, support: { chrome: "17", chrome_android: "18", edge: "12", firefox: "5", firefox_android: "5", safari: "6", safari_ios: "6" } } }, "accessor-methods": { compat_features: ["javascript.builtins.Object.defineGetter", "javascript.builtins.Object.defineSetter", "javascript.builtins.Object.lookupGetter", "javascript.builtins.Object.lookupSetter"], description: "The __defineGetter__() and __defineSetter__() methods of objects bind a function to a property, which is called on setting or reading the property.", description_html: "The __defineGetter__() and __defineSetter__() methods of objects bind a function to a property, which is called on setting or reading the property.", discouraged: { according_to: ["https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-additional-ecmascript-features-for-web-browsers"], reason: 'TC39 included acce\ +ssor methods in Annex B of the ECMAScript specification, which covers JavaScript features with "one or more undesirable characteristics and in the absence of legacy usage would be removed."', reason_html: 'TC39 included accessor methods in Annex B of the ECMAScript specification, which covers JavaScript features with "one or more undesirable characteristics and in the absence of legacy usage would be removed."' }, group: ["javascript"], kind: "feature", name: "Accessor methods", spec: ["https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.prototype-legacy-accessor-methods"], status: { baseline: false, by_compat_key: { "javascript.builtins.Object.defineGetter": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Object.defineSetter": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "3", + safari_ios: "1" } }, "javascript.builtins.Object.lookupGetter": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Object.lookupSetter": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "3", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "3", safari_ios: "1" } } }, "active-view-transition": { compat_features: ["api.ViewTransition.types", "api.ViewTransitionTypeSet", "api.ViewTransitionTypeSet.@@iterator", "api.ViewTransitionTypeSet.add", "api.ViewTransitionTypeSet.clear", "api.ViewTransitionTypeSet.delete", "api.ViewTransitionTypeSet.entries", "api.ViewTransitionTypeSet.forEach", "api.ViewTransitionTypeSet.has", "api.ViewTransitionTypeSet.keys", "api.ViewTransitionTypeSet.size", "api.ViewTransitionTypeSet.values", "css.\ +selectors.active-view-transition", "css.selectors.active-view-transition-type"], description: "The :active-view-transition CSS pseudo-class matches the root element when a view transition is active. The :active-view-transition-type() CSS pseudo-class matches only when the active view transition was started with the specified type.", description_html: "The :active-view-transition CSS pseudo-class matches the root element when a view transition is active. The :active-view-transition-type() CSS pseudo-class matches only when the active view transition was started with the specified type.", group: ["view-transitions", "selectors"], kind: "feature", name: "Active view transition", spec: ["https://drafts.csswg.org/css-view-transitions-2/#the-active-view-transition-pseudo"], status: { baseline: "low", baseline_low_date: "2026-01-13", by_compat_key: { "api.ViewTransition.types": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "\ +125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.@@iterator": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.add": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.clear": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "\ +18.2" } }, "api.ViewTransitionTypeSet.delete": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.entries": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.forEach": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.has": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.keys": { baseline: "low", baseline_low_date: "\ +2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "api.ViewTransitionTypeSet.values": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } }, "css.selectors.active-view-transition": { baseline: "low", baseline_low_date: "2025-10-14", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "144", firefox_android: "144", safari: "18", safari_ios: "18" } }, "css.selectors.active-view-transition-type": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", + firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } } }, support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "18.2", safari_ios: "18.2" } } }, address: { compat_features: ["html.elements.address"], description: "The
element represents contact information for a person or people, or for an organization.", description_html: "The <address> element represents contact information for a person or people, or for an organization.", group: ["html-elements"], kind: "feature", name: "
", spec: ["https://html.spec.whatwg.org/multipage/sections.html#the-address-element"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "html.elements.address": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "\ +4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, alerts: { compat_features: ["api.Window.alert", "api.Window.confirm", "api.Window.prompt"], description: "The window.alert(), window.confirm(), and window.prompt() methods open modal dialogs for notifying the user, asking for confirmation, or entering text.", description_html: "The window.alert(), window.confirm(), and window.prompt() methods open modal dialogs for notifying the user, asking for confirmation, or entering text.", kind: "feature", name: "Alerts", spec: ["https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#user-prompts"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "api.Window.alert": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "\ +1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.Window.confirm": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "api.Window.prompt": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, "align-content-block": { compat_features: ["css.properties.align-content.block_context"], description: "The align-content property vertically aligns content in block layouts, like it does in flex or grid layouts.", description_html: "The align-content property vertically al\ +igns content in block layouts, like it does in flex or grid layouts.", group: ["layout"], kind: "feature", name: "align-content in block layouts", spec: ["https://drafts.csswg.org/css-align-3/#align-justify-content"], status: { baseline: "low", baseline_low_date: "2024-04-16", by_compat_key: { "css.properties.align-content.block_context": { baseline: "low", baseline_low_date: "2024-04-16", support: { chrome: "123", chrome_android: "123", edge: "123", firefox: "125", firefox_android: "125", safari: "17.4", safari_ios: "17.4" } } }, support: { chrome: "123", chrome_android: "123", edge: "123", firefox: "125", firefox_android: "125", safari: "17.4", safari_ios: "17.4" } } }, "alignment-baseline": { compat_features: ["css.properties.alignment-baseline", "css.properties.alignment-baseline.alphabetic", "css.properties.alignment-baseline.baseline", "css.properties.alignment-baseline.central", "css.properties.alignment-baseline.ideographic", "css.properties.alignment-baseline.mathematical", "c\ +ss.properties.alignment-baseline.middle", "css.properties.alignment-baseline.text-after-edge", "css.properties.alignment-baseline.text-before-edge"], description: "The alignment-baseline CSS property sets which baseline of an element is aligned with the corresponding baseline of its parent.", description_html: "The alignment-baseline CSS property sets which baseline of an element is aligned with the corresponding baseline of its parent.", group: ["text"], kind: "feature", name: "alignment-baseline", spec: ["https://drafts.csswg.org/css-inline-3/#alignment-baseline-property"], status: { baseline: false, by_compat_key: { "css.properties.alignment-baseline": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.alphabetic": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.baseline": { baseline: false, + support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.central": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.ideographic": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.mathematical": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.middle": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.text-after-edge": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } }, "css.properties.alignment-baseline.text-before-edge": { baseline: false, support: { chrome: "1", + chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } } }, support: { chrome: "1", chrome_android: "18", edge: "79", safari: "5.1", safari_ios: "5" } } }, all: { caniuse: ["css-all"], compat_features: ["css.properties.all"], description: "The all CSS property is a shorthand for all CSS properties, except for direction and unicode-bidi. It accepts only the keywords for explicit defaulting (such as initial and inherit), since they are the only values supported on all CSS properties.", description_html: "The all CSS property is a shorthand for all CSS properties, except for direction and unicode-bidi. It accepts only the keywords for explicit defaulting (such as initial and inherit), since they are the only values supported on all CSS properties.", group: ["explicit-defaults"], kind: "feature", name: "all", spec: ["https://drafts.csswg.org/css-cascade-6/"], status: { baseline: "high", baseline_high_date: "20\ +22-07-15", baseline_low_date: "2020-01-15", by_compat_key: { "css.properties.all": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "37", chrome_android: "37", edge: "79", firefox: "27", firefox_android: "27", safari: "9.1", safari_ios: "9.3" } } }, support: { chrome: "37", chrome_android: "37", edge: "79", firefox: "27", firefox_android: "27", safari: "9.1", safari_ios: "9.3" } } }, "alt-text-generated-content": { compat_features: ["css.properties.content.alt_text"], description: "The / notation in content CSS property values adds alternative text to generated content. For example, the content: url('upvote-icon.svg') / 'Upvote' declaration adds accessible 'Upvote' text to the SVG icon. Also known as alternate text.", description_html: "The / notation in content CSS property values adds alternative text to generated content. For example, the content: url('upvote-icon.svg') / 'Upvote' declara\ +tion adds accessible 'Upvote' text to the SVG icon. Also known as alternate text.", group: ["css"], kind: "feature", name: "Alt text for generated content", spec: ["https://drafts.csswg.org/css-content-3/#alt"], status: { baseline: "low", baseline_low_date: "2024-07-09", by_compat_key: { "css.properties.content.alt_text": { baseline: "low", baseline_low_date: "2024-07-09", support: { chrome: "77", chrome_android: "77", edge: "79", firefox: "128", firefox_android: "128", safari: "17.4", safari_ios: "17.4" } } }, support: { chrome: "77", chrome_android: "77", edge: "79", firefox: "128", firefox_android: "128", safari: "17.4", safari_ios: "17.4" } } }, "alternative-style-sheets": { compat_features: ["html.elements.link.rel.alternate_stylesheet"], description: 'The rel="alternate stylesheet" attribute for the HTML element offers an alternative style option to users.', description_html: 'The rel="alternate stylesheet" attribute for the <link> HTML eleme\ +nt offers an alternative style option to users.', group: ["css"], kind: "feature", name: "Alternative style sheets", spec: ["https://drafts.csswg.org/cssom-1/#concept-css-style-sheet-alternate-flag"], status: { baseline: false, by_compat_key: { "html.elements.link.rel.alternate_stylesheet": { baseline: false, support: { firefox: "3", firefox_android: "4" } } }, support: { firefox: "3", firefox_android: "4" } } }, "ambient-light": { caniuse: ["ambient-light"], compat_features: ["api.AmbientLightSensor", "api.AmbientLightSensor.AmbientLightSensor", "api.AmbientLightSensor.illuminance", "api.Permissions.permission_ambient-light-sensor", "html.elements.iframe.allow.ambient-light-sensor", "http.headers.Permissions-Policy.ambient-light-sensor"], description: "The AmbientLightSensor API returns the current light level in lux of the ambient light level around the device.", description_html: "The AmbientLightSensor API returns the current light level in lux of the ambient light lev\ +el around the device.", group: ["sensors"], kind: "feature", name: "Ambient light sensor", spec: ["https://w3c.github.io/ambient-light/"], status: { baseline: false, by_compat_key: { "api.AmbientLightSensor": { baseline: false, support: {} }, "api.AmbientLightSensor.AmbientLightSensor": { baseline: false, support: {} }, "api.AmbientLightSensor.illuminance": { baseline: false, support: {} }, "api.Permissions.permission_ambient-light-sensor": { baseline: false, support: {} }, "html.elements.iframe.allow.ambient-light-sensor": { baseline: false, support: {} }, "http.headers.Permissions-Policy.ambient-light-sensor": { baseline: false, support: {} } }, support: {} } }, "anchor-positioning": { caniuse: ["css-anchor-positioning"], compat_features: ["api.CSSPositionTryDescriptors", "api.CSSPositionTryDescriptors.align-self", "api.CSSPositionTryDescriptors.alignSelf", "api.CSSPositionTryDescriptors.block-size", "api.CSSPositionTryDescriptors.blockSize", "api.CSSPositionTryDescriptors.bottom", "\ +api.CSSPositionTryDescriptors.height", "api.CSSPositionTryDescriptors.inline-size", "api.CSSPositionTryDescriptors.inlineSize", "api.CSSPositionTryDescriptors.inset", "api.CSSPositionTryDescriptors.inset-block", "api.CSSPositionTryDescriptors.inset-block-end", "api.CSSPositionTryDescriptors.inset-block-start", "api.CSSPositionTryDescriptors.inset-inline", "api.CSSPositionTryDescriptors.inset-inline-end", "api.CSSPositionTryDescriptors.inset-inline-start", "api.CSSPositionTryDescriptors.insetBlock", "api.CSSPositionTryDescriptors.insetBlockEnd", "api.CSSPositionTryDescriptors.insetBlockStart", "api.CSSPositionTryDescriptors.insetInline", "api.CSSPositionTryDescriptors.insetInlineEnd", "api.CSSPositionTryDescriptors.insetInlineStart", "api.CSSPositionTryDescriptors.justify-self", "api.CSSPositionTryDescriptors.justifySelf", "api.CSSPositionTryDescriptors.left", "api.CSSPositionTryDescriptors.margin", "api.CSSPositionTryDescriptors.margin-block", "api.CSSPositionTryDescriptors.margin-bloc\ +k-end", "api.CSSPositionTryDescriptors.margin-block-start", "api.CSSPositionTryDescriptors.margin-bottom", "api.CSSPositionTryDescriptors.margin-inline", "api.CSSPositionTryDescriptors.margin-inline-end", "api.CSSPositionTryDescriptors.margin-inline-start", "api.CSSPositionTryDescriptors.margin-left", "api.CSSPositionTryDescriptors.margin-right", "api.CSSPositionTryDescriptors.margin-top", "api.CSSPositionTryDescriptors.marginBlock", "api.CSSPositionTryDescriptors.marginBlockEnd", "api.CSSPositionTryDescriptors.marginBlockStart", "api.CSSPositionTryDescriptors.marginBottom", "api.CSSPositionTryDescriptors.marginInline", "api.CSSPositionTryDescriptors.marginInlineEnd", "api.CSSPositionTryDescriptors.marginInlineStart", "api.CSSPositionTryDescriptors.marginLeft", "api.CSSPositionTryDescriptors.marginRight", "api.CSSPositionTryDescriptors.marginTop", "api.CSSPositionTryDescriptors.max-block-size", "api.CSSPositionTryDescriptors.max-height", "api.CSSPositionTryDescriptors.max-inline-size", + "api.CSSPositionTryDescriptors.max-width", "api.CSSPositionTryDescriptors.maxBlockSize", "api.CSSPositionTryDescriptors.maxHeight", "api.CSSPositionTryDescriptors.maxInlineSize", "api.CSSPositionTryDescriptors.maxWidth", "api.CSSPositionTryDescriptors.min-block-size", "api.CSSPositionTryDescriptors.min-height", "api.CSSPositionTryDescriptors.min-inline-size", "api.CSSPositionTryDescriptors.min-width", "api.CSSPositionTryDescriptors.minBlockSize", "api.CSSPositionTryDescriptors.minHeight", "api.CSSPositionTryDescriptors.minInlineSize", "api.CSSPositionTryDescriptors.minWidth", "api.CSSPositionTryDescriptors.place-self", "api.CSSPositionTryDescriptors.placeSelf", "api.CSSPositionTryDescriptors.position-anchor", "api.CSSPositionTryDescriptors.position-area", "api.CSSPositionTryDescriptors.positionAnchor", "api.CSSPositionTryDescriptors.positionArea", "api.CSSPositionTryDescriptors.right", "api.CSSPositionTryDescriptors.top", "api.CSSPositionTryDescriptors.width", "api.CSSPositionTryRu\ +le", "api.CSSPositionTryRule.name", "api.CSSPositionTryRule.style", "api.HTMLButtonElement.popoverTargetElement.implicit_anchor_reference", "api.HTMLElement.showPopover.options_source_parameter.implicit_anchor_reference", "api.HTMLElement.togglePopover.options_source_parameter.implicit_anchor_reference", "api.HTMLInputElement.popoverTargetElement.implicit_anchor_reference", "css.at-rules.position-try", "css.properties.align-items.anchor-center", "css.properties.align-self.anchor-center", "css.properties.anchor-name", "css.properties.anchor-name.none", "css.properties.anchor-scope", "css.properties.anchor-scope.all", "css.properties.anchor-scope.none", "css.properties.block-size.anchor-size", "css.properties.bottom.anchor", "css.properties.bottom.anchor-size", "css.properties.height.anchor-size", "css.properties.inline-size.anchor-size", "css.properties.inset-block-end.anchor", "css.properties.inset-block-end.anchor-size", "css.properties.inset-block-start.anchor", "css.properties.inset\ +-block-start.anchor-size", "css.properties.inset-block.anchor", "css.properties.inset-block.anchor-size", "css.properties.inset-inline-end.anchor", "css.properties.inset-inline-end.anchor-size", "css.properties.inset-inline-start.anchor", "css.properties.inset-inline-start.anchor-size", "css.properties.inset-inline.anchor", "css.properties.inset-inline.anchor-size", "css.properties.inset.anchor", "css.properties.inset.anchor-size", "css.properties.justify-items.anchor-center", "css.properties.justify-self.anchor-center", "css.properties.left.anchor", "css.properties.left.anchor-size", "css.properties.margin-block-end.anchor-size", "css.properties.margin-block-start.anchor-size", "css.properties.margin-block.anchor-size", "css.properties.margin-bottom.anchor-size", "css.properties.margin-inline-end.anchor-size", "css.properties.margin-inline-start.anchor-size", "css.properties.margin-inline.anchor-size", "css.properties.margin-left.anchor-size", "css.properties.margin-right.anchor-size", + "css.properties.margin-top.anchor-size", "css.properties.margin.anchor-size", "css.properties.max-block-size.anchor-size", "css.properties.max-height.anchor-size", "css.properties.max-inline-size.anchor-size", "css.properties.max-width.anchor-size", "css.properties.min-block-size.anchor-size", "css.properties.min-height.anchor-size", "css.properties.min-inline-size.anchor-size", "css.properties.min-width.anchor-size", "css.properties.place-items.anchor-center", "css.properties.place-self.anchor-center", "css.properties.position-anchor", "css.properties.position-anchor.auto", "css.properties.position-anchor.none", "css.properties.position-area", "css.properties.position-area.block-end", "css.properties.position-area.block-start", "css.properties.position-area.bottom", "css.properties.position-area.center", "css.properties.position-area.end", "css.properties.position-area.inline-end", "css.properties.position-area.inline-start", "css.properties.position-area.left", "css.properties.po\ +sition-area.none", "css.properties.position-area.right", "css.properties.position-area.self-block-end", "css.properties.position-area.self-block-start", "css.properties.position-area.self-end", "css.properties.position-area.self-inline-end", "css.properties.position-area.self-inline-start", "css.properties.position-area.self-start", "css.properties.position-area.self-x-end", "css.properties.position-area.self-x-start", "css.properties.position-area.self-y-end", "css.properties.position-area.self-y-start", "css.properties.position-area.span-all", "css.properties.position-area.span-block-end", "css.properties.position-area.span-block-start", "css.properties.position-area.span-bottom", "css.properties.position-area.span-end", "css.properties.position-area.span-inline-end", "css.properties.position-area.span-inline-start", "css.properties.position-area.span-left", "css.properties.position-area.span-right", "css.properties.position-area.span-self-block-end", "css.properties.position-area.sp\ +an-self-block-start", "css.properties.position-area.span-self-end", "css.properties.position-area.span-self-inline-end", "css.properties.position-area.span-self-inline-start", "css.properties.position-area.span-self-start", "css.properties.position-area.span-self-x-end", "css.properties.position-area.span-self-x-start", "css.properties.position-area.span-self-y-end", "css.properties.position-area.span-self-y-start", "css.properties.position-area.span-start", "css.properties.position-area.span-top", "css.properties.position-area.span-x-end", "css.properties.position-area.span-x-start", "css.properties.position-area.span-y-end", "css.properties.position-area.span-y-start", "css.properties.position-area.start", "css.properties.position-area.top", "css.properties.position-area.x-end", "css.properties.position-area.x-start", "css.properties.position-area.y-end", "css.properties.position-area.y-start", "css.properties.position-try", "css.properties.position-try-fallbacks", "css.properties.po\ +sition-try-fallbacks.flip-block", "css.properties.position-try-fallbacks.flip-inline", "css.properties.position-try-fallbacks.flip-start", "css.properties.position-try-fallbacks.none", "css.properties.position-try-fallbacks.position-area", "css.properties.position-try-fallbacks.self-x-end", "css.properties.position-try-fallbacks.self-x-start", "css.properties.position-try-fallbacks.self-y-end", "css.properties.position-try-fallbacks.self-y-start", "css.properties.position-try-fallbacks.span-self-x-end", "css.properties.position-try-fallbacks.span-self-x-start", "css.properties.position-try-fallbacks.span-self-y-end", "css.properties.position-try-fallbacks.span-self-y-start", "css.properties.position-try-order", "css.properties.position-try-order.most-block-size", "css.properties.position-try-order.most-height", "css.properties.position-try-order.most-inline-size", "css.properties.position-try-order.most-width", "css.properties.position-try-order.normal", "css.properties.position-try.se\ +lf-x-end", "css.properties.position-try.self-x-start", "css.properties.position-try.self-y-end", "css.properties.position-try.self-y-start", "css.properties.position-try.span-self-x-end", "css.properties.position-try.span-self-x-start", "css.properties.position-try.span-self-y-end", "css.properties.position-try.span-self-y-start", "css.properties.position-visibility", "css.properties.position-visibility.always", "css.properties.position-visibility.anchors-visible", "css.properties.position-visibility.no-overflow", "css.properties.right.anchor", "css.properties.right.anchor-size", "css.properties.top.anchor", "css.properties.top.anchor-size", "css.properties.width.anchor-size", "css.types.anchor", "css.types.anchor-size", "css.types.anchor-size.inset_margin", "html.elements.button.popovertarget.implicit_anchor_reference", "html.elements.input.popovertarget.implicit_anchor_reference"], description: "Anchor positioning places an element based on the position of another element. For exampl\ +e, you can place a tooltip next to the content it references.", description_html: "Anchor positioning places an element based on the position of another element. For example, you can place a tooltip next to the content it references.", kind: "feature", name: "Anchor positioning", spec: ["https://drafts.csswg.org/css-anchor-position-1/#anchoring"], status: { baseline: false, by_compat_key: { "api.CSSPositionTryDescriptors": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.align-self": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.alignSelf": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "\ +125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.block-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.blockSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.bottom": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.height": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "api.CSSPositionTryDescriptors.inline-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inlineSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-block": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-block-end": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-block-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-inline": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-inline-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.inset-inline-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { + chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetBlock": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetBlockEnd": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetBlockStart": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetInline": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "\ +147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetInlineEnd": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.insetInlineStart": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.justify-self": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.justifySelf": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "api.CSSPositionTryDescriptors.left": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-block": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-block-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-block-start": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-bottom": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-inline": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-inline-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-inline-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { + chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-left": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-right": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.margin-top": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginBlock": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "\ +147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginBlockEnd": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginBlockStart": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginBottom": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginInline": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "api.CSSPositionTryDescriptors.marginInlineEnd": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginInlineStart": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginLeft": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginRight": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.marginTop": { + baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.max-block-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.max-height": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.max-inline-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.max-width": { baseline: "low", baseline_low_date: "2026-01-13", support: { + chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.maxBlockSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.maxHeight": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.maxInlineSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.maxWidth": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "\ +147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.min-block-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.min-height": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.min-inline-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.min-width": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "api.CSSPositionTryDescriptors.minBlockSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.minHeight": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.minInlineSize": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.minWidth": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.place-self": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.placeSelf": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.position-anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.position-area": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.positionAnchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "\ +125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.positionArea": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.right": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.top": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryDescriptors.width": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", + safari: "26", safari_ios: "26" } }, "api.CSSPositionTryRule": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryRule.name": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.CSSPositionTryRule.style": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.HTMLButtonElement.popoverTargetElement.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "133", chrome_android: "133", edge: "133", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.HTMLElement.showPopover.options_so\ +urce_parameter.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "137", chrome_android: "137", edge: "137", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.HTMLElement.togglePopover.options_source_parameter.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "137", chrome_android: "137", edge: "137", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "api.HTMLInputElement.popoverTargetElement.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "133", chrome_android: "133", edge: "133", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.at-rules.position-try": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properti\ +es.align-items.anchor-center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.align-self.anchor-center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.anchor-name": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.anchor-name.none": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.anchor-scope": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "\ +131", chrome_android: "131", edge: "131", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.anchor-scope.all": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "131", chrome_android: "131", edge: "131", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.anchor-scope.none": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "131", chrome_android: "131", edge: "131", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.block-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.bottom.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "css.properties.bottom.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.height.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inline-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block-end.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block-end.anchor-size": { baseline: "low", baseline_low_date: "\ +2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block-start.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block-start.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-block.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "1\ +32", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-inline-end.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-inline-end.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-inline-start.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-inline-start.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", + safari_ios: "26" } }, "css.properties.inset-inline.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset-inline.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.inset.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.justify-items.anchor-center": { baseline: "low", baseline_low_date: "\ +2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.justify-self.anchor-center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.left.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.left.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-block-end.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "\ +147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-block-start.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-block.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-bottom.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-inline-end.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "css.properties.margin-inline-start.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-inline.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-left.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-right.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin-top.anchor-size": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.margin.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.max-block-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.max-height.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.max-inline-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "\ +125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.max-width.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.min-block-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.min-height.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.min-inline-size.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "\ +26", safari_ios: "26" } }, "css.properties.min-width.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.place-items.anchor-center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.place-self.anchor-center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-anchor.auto": { baseline: false, + support: { firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-anchor.none": { baseline: false, support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "147", firefox_android: "147" } }, "css.properties.position-area": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.block-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.block-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.bottom": { baseline: "low", + baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.center": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.inline-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.inline-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "\ +144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.left": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.none": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.right": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-block-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "\ +26" } }, "css.properties.position-area.self-block-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-inline-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-inline-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-start": { + baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.self-x-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.self-x-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.self-y-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.self-y-start": { baseline: "low", baseline_low_date: "2026-02-24", + support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.span-all": { baseline: false, support: { chrome: "144", chrome_android: "144", edge: "144", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-block-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-block-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-bottom": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "\ +26" } }, "css.properties.position-area.span-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-inline-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-inline-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-left": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-right": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-block-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-block-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-inline-end": { baseline: "low", baseline_low_date: "2026-01-1\ +3", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-inline-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-self-x-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.span-self-x-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "\ +143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.span-self-y-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.span-self-y-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-area.span-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-top": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "\ +147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-x-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-x-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-y-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.span-y-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.positi\ +on-area.start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "129", chrome_android: "129", edge: "129", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-area.top": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.x-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.x-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.y-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "\ +144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-area.y-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks.flip-block": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "\ +147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks.flip-inline": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks.flip-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks.none": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.position-try-fallbacks.position-area": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "2\ +6" } }, "css.properties.position-try-fallbacks.self-x-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.self-x-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.self-y-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.self-y-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css\ +.properties.position-try-fallbacks.span-self-x-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.span-self-x-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.span-self-y-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try-fallbacks.span-self-y-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, + "css.properties.position-try-order": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try-order.most-block-size": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try-order.most-height": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try-order.most-inline-size": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try-order.most-wid\ +th": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try-order.normal": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "148", firefox_android: "148", safari: "26", safari_ios: "26" } }, "css.properties.position-try.self-x-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.self-x-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.self-y-end": { baseline: "low", baseline_low_date: "2026-02-24", support: { + chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.self-y-start": { baseline: "low", baseline_low_date: "2026-02-24", support: { chrome: "144", chrome_android: "144", edge: "144", firefox: "148", firefox_android: "148", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.span-self-x-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.span-self-x-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.span-self-y-end": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "1\ +43", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-try.span-self-y-start": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "143", chrome_android: "143", edge: "143", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-visibility": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-visibility.always": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-visibility.anchors-visible": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "\ +147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.position-visibility.no-overflow": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26.2", safari_ios: "26.2" } }, "css.properties.right.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.right.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.top.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.top.anchor-size": { baseline: "\ +low", baseline_low_date: "2026-01-13", support: { chrome: "132", chrome_android: "132", edge: "132", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.properties.width.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.types.anchor": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.types.anchor-size": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "125", chrome_android: "125", edge: "125", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "css.types.anchor-size.inset_margin": { baseline: false, support: { chrome: "132", chrome_android: "132", edge: "132", safari: "26", safari_ios: "26" } }, "html.elements.bu\ +tton.popovertarget.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "133", chrome_android: "133", edge: "133", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } }, "html.elements.input.popovertarget.implicit_anchor_reference": { baseline: "low", baseline_low_date: "2026-01-13", support: { chrome: "133", chrome_android: "133", edge: "133", firefox: "147", firefox_android: "147", safari: "26", safari_ios: "26" } } }, support: {} } }, "angle-instanced-arrays": { compat_features: ["api.ANGLE_instanced_arrays", "api.ANGLE_instanced_arrays.drawArraysInstancedANGLE", "api.ANGLE_instanced_arrays.drawElementsInstancedANGLE", "api.ANGLE_instanced_arrays.vertexAttribDivisorANGLE"], description: "The ANGLE_instanced_arrays extension for WebGL 1.0 contexts draws the same object multiple times or groups of similar objects multiple times, if the group shares the same vertex data, primitive count and type.", description_html: "Th\ +e ANGLE_instanced_arrays extension for WebGL 1.0 contexts draws the same object multiple times or groups of similar objects multiple times, if the group shares the same vertex data, primitive count and type.", group: ["webgl-extensions"], kind: "feature", name: "ANGLE_instanced_arrays WebGL extension", spec: ["https://registry.khronos.org/webgl/extensions/ANGLE_instanced_arrays/"], status: { baseline: "high", baseline_high_date: "2018-12-07", baseline_low_date: "2016-06-07", by_compat_key: { "api.ANGLE_instanced_arrays": { baseline: "high", baseline_high_date: "2018-12-07", baseline_low_date: "2016-06-07", support: { chrome: "32", chrome_android: "30", edge: "12", firefox: "47", firefox_android: "47", safari: "8", safari_ios: "8" } }, "api.ANGLE_instanced_arrays.drawArraysInstancedANGLE": { baseline: "high", baseline_high_date: "2018-12-07", baseline_low_date: "2016-06-07", support: { chrome: "32", chrome_android: "30", edge: "12", firefox: "47", firefox_android: "47", safari: "\ +8", safari_ios: "8" } }, "api.ANGLE_instanced_arrays.drawElementsInstancedANGLE": { baseline: "high", baseline_high_date: "2018-12-07", baseline_low_date: "2016-06-07", support: { chrome: "32", chrome_android: "30", edge: "12", firefox: "47", firefox_android: "47", safari: "8", safari_ios: "8" } }, "api.ANGLE_instanced_arrays.vertexAttribDivisorANGLE": { baseline: "high", baseline_high_date: "2018-12-07", baseline_low_date: "2016-06-07", support: { chrome: "32", chrome_android: "30", edge: "12", firefox: "47", firefox_android: "47", safari: "8", safari_ios: "8" } } }, support: { chrome: "32", chrome_android: "30", edge: "12", firefox: "47", firefox_android: "47", safari: "8", safari_ios: "8" } } }, "animation-composition": { compat_features: ["css.properties.animation-composition"], description: "The animation-composition CSS property chooses how to combine animations that affect the same property.", description_html: "The animation-composition CSS property chooses how to \ +combine animations that affect the same property.", group: ["animation"], kind: "feature", name: "animation-composition", spec: ["https://drafts.csswg.org/css-animations-2/#animation-composition"], status: { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", by_compat_key: { "css.properties.animation-composition": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "112", chrome_android: "112", edge: "112", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } } }, support: { chrome: "112", chrome_android: "112", edge: "112", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } } }, "animations-css": { caniuse: ["css-animation"], compat_features: ["api.AnimationEvent", "api.AnimationEvent.AnimationEvent", "api.AnimationEvent.animationName", "api.AnimationEvent.elapsedTime", "api.AnimationEvent.pseudoElement", "api.CSSAnimation", "api.CSSAnimation.animationName", + "api.CSSKeyframeRule", "api.CSSKeyframeRule.keyText", "api.CSSKeyframeRule.style", "api.CSSKeyframesRule", "api.CSSKeyframesRule.appendRule", "api.CSSKeyframesRule.cssRules", "api.CSSKeyframesRule.deleteRule", "api.CSSKeyframesRule.findRule", "api.CSSKeyframesRule.length", "api.CSSKeyframesRule.name", "css.at-rules.keyframes", "css.at-rules.keyframes.ignore_important_declarations", "css.at-rules.keyframes.named_range_keyframes", "css.properties.animation", "css.properties.animation-delay", "css.properties.animation-direction", "css.properties.animation-direction.alternate", "css.properties.animation-direction.alternate-reverse", "css.properties.animation-direction.normal", "css.properties.animation-direction.reverse", "css.properties.animation-duration", "css.properties.animation-duration.auto", "css.properties.animation-fill-mode", "css.properties.animation-fill-mode.backwards", "css.properties.animation-fill-mode.both", "css.properties.animation-fill-mode.forwards", "css.properti\ +es.animation-fill-mode.none", "css.properties.animation-iteration-count", "css.properties.animation-iteration-count.infinite", "css.properties.animation-name", "css.properties.animation-name.none", "css.properties.animation-play-state", "css.properties.animation-play-state.paused", "css.properties.animation-play-state.running", "css.properties.animation-timing-function", "css.properties.animation-timing-function.ease", "css.properties.animation-timing-function.ease-in", "css.properties.animation-timing-function.ease-in-out", "css.properties.animation-timing-function.ease-out", "css.properties.animation-timing-function.jump", "css.properties.animation-timing-function.linear", "css.properties.animation-timing-function.step-end", "css.properties.animation-timing-function.step-start", "css.properties.animation.alternate", "css.properties.animation.alternate-reverse", "css.properties.animation.auto", "css.properties.animation.backwards", "css.properties.animation.both", "css.properties.anim\ +ation.ease", "css.properties.animation.ease-in", "css.properties.animation.ease-in-out", "css.properties.animation.ease-out", "css.properties.animation.forwards", "css.properties.animation.infinite", "css.properties.animation.linear", "css.properties.animation.none", "css.properties.animation.normal", "css.properties.animation.reverse", "css.properties.animation.step-end", "css.properties.animation.step-start", "css.types.time"], description: "The animation CSS property animates an element's style over time, using keyframes described in @keyframes rules.", description_html: "The animation CSS property animates an element's style over time, using keyframes described in @keyframes rules.", group: ["animation", "css"], kind: "feature", name: "Animations (CSS)", spec: ["https://drafts.csswg.org/css-animations-2/"], status: { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", by_compat_key: { "api.AnimationEvent": { baseline: "high", + baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "5", firefox_android: "5", safari: "9", safari_ios: "9" } }, "api.AnimationEvent.AnimationEvent": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "43", chrome_android: "43", edge: "14", firefox: "23", firefox_android: "23", safari: "9", safari_ios: "9" } }, "api.AnimationEvent.animationName": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "5", firefox_android: "5", safari: "9", safari_ios: "9" } }, "api.AnimationEvent.elapsedTime": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "5", firefox_android: "5", safari: "9", safari_ios: "9" } }, "api.AnimationEvent.pseudoElement": { baseline: "\ +high", baseline_high_date: "2022-09-24", baseline_low_date: "2020-03-24", support: { chrome: "68", chrome_android: "68", edge: "79", firefox: "23", firefox_android: "23", safari: "13.1", safari_ios: "13.4" } }, "api.CSSAnimation": { baseline: "high", baseline_high_date: "2023-01-28", baseline_low_date: "2020-07-28", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "75", firefox_android: "79", safari: "13.1", safari_ios: "13.4" } }, "api.CSSAnimation.animationName": { baseline: "high", baseline_high_date: "2023-01-28", baseline_low_date: "2020-07-28", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "75", firefox_android: "79", safari: "13.1", safari_ios: "13.4" } }, "api.CSSKeyframeRule": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9", safari_ios: "9" } }, "api.CSSKeyframeRule.keyText": { baseline: "hi\ +gh", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9", safari_ios: "9" } }, "api.CSSKeyframeRule.style": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9", safari_ios: "9" } }, "api.CSSKeyframesRule": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "api.CSSKeyframesRule.appendRule": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "41", chrome_android: "41", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "api.CSSKeyframesRule.cssRules": { baseline: "h\ +igh", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "api.CSSKeyframesRule.deleteRule": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "api.CSSKeyframesRule.findRule": { baseline: "high", baseline_high_date: "2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "api.CSSKeyframesRule.length": { baseline: "low", baseline_low_date: "2024-03-22", support: { chrome: "123", chrome_android: "123", edge: "123", firefox: "109", firefox_android: "109", safari: "17", safari_ios: "17" } }, "api.CSSKeyframesRule.name": { baseline: "high", baseline_high_date: "\ +2019-02-02", baseline_low_date: "2016-08-02", support: { chrome: "31", chrome_android: "31", edge: "12", firefox: "48", firefox_android: "48", safari: "9.1", safari_ios: "9.3" } }, "css.at-rules.keyframes": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.at-rules.keyframes.ignore_important_declarations": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "45", chrome_android: "45", edge: "79", firefox: "19", firefox_android: "19", safari: "10.1", safari_ios: "10.3" } }, "css.at-rules.keyframes.named_range_keyframes": { baseline: false, support: { chrome: "115", chrome_android: "115", edge: "115", safari: "26", safari_ios: "26" } }, "css.properties.animation": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "\ +43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-delay": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-direction": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-direction.alternate": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-direction.alternate-reverse": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "\ +2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-direction.normal": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-direction.reverse": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-duration": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-duration.auto": { baseline: false, support: { chrome: "\ +115", chrome_android: "115", edge: "115", safari: "18.4", safari_ios: "18.4" } }, "css.properties.animation-fill-mode": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-fill-mode.backwards": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-fill-mode.both": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-fill-mode.forwards": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { + chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-fill-mode.none": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-iteration-count": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-iteration-count.infinite": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-name": { baseline: "high", baseline_high_date: "2018-03-\ +30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-name.none": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-play-state": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-play-state.paused": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-play-state.running": { baseline: "\ +high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.ease": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.ease-in": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, + "css.properties.animation-timing-function.ease-in-out": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.ease-out": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.jump": { baseline: "high", baseline_high_date: "2023-03-16", baseline_low_date: "2020-09-16", support: { chrome: "77", chrome_android: "77", edge: "79", firefox: "65", firefox_android: "65", safari: "14", safari_ios: "14" } }, "css.properties.animation-timing-function.linear": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", + edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.step-end": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation-timing-function.step-start": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.alternate": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.alternate-reverse": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "\ +2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.auto": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.backwards": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.both": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.ease": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "\ +2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.ease-in": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.ease-in-out": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.ease-out": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.forwards": { baseline: "high", baseline_high_date: "2018-03-30", + baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.infinite": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.linear": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.none": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.normal": { baseline: "high", baseline_high_date: "\ +2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.reverse": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.step-end": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.properties.animation.step-start": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } }, "css.types.time": { baseline: "high", baseline_high_date: "\ +2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "4", firefox_android: "4", safari: "3.1", safari_ios: "2" } } }, support: { chrome: "43", chrome_android: "43", edge: "12", firefox: "16", firefox_android: "16", safari: "9", safari_ios: "9" } } }, "app-file-handlers": { compat_features: ["api.LaunchParams.files", "manifests.webapp.file_handlers"], description: "The file_handlers web app manifest member registers an installed web app as a handler for files with specific file extensions or MIME types.", description_html: "The file_handlers web app manifest member registers an installed web app as a handler for files with specific file extensions or MIME types.", group: ["progressive-web-app"], kind: "feature", name: "File handlers", spec: ["https://wicg.github.io/manifest-incubations/#file_handlers-member"], status: { baseline: false, by_compat_key: { "api.LaunchParams.files": { baseline: false, support: { chrome: "\ +102", edge: "102" } }, "manifests.webapp.file_handlers": { baseline: false, support: { chrome: "102", edge: "102" } } }, support: { chrome: "102", edge: "102" } } }, "app-launch-handler": { compat_features: ["api.LaunchParams", "api.LaunchParams.targetURL", "api.LaunchQueue", "api.LaunchQueue.setConsumer", "api.Window.launchQueue", "manifests.webapp.launch_handler", "manifests.webapp.launch_handler.client_mode"], description: "The launch_handler web app manifest member, with the client_mode property, configure how web app launches behave when an instance of the app is already open. For example, you can choose to focus the existing app instance instead of launching a new one.", description_html: "The launch_handler web app manifest member, with the client_mode property, configure how web app launches behave when an instance of the app is already open. For example, you can choose to focus the existing app instance instead of launching a new one.", group: ["progr\ +essive-web-app"], kind: "feature", name: "Launch handler", spec: ["https://wicg.github.io/web-app-launch/"], status: { baseline: false, by_compat_key: { "api.LaunchParams": { baseline: false, support: { chrome: "102", edge: "102" } }, "api.LaunchParams.targetURL": { baseline: false, support: { chrome: "110", edge: "110" } }, "api.LaunchQueue": { baseline: false, support: { chrome: "102", edge: "102" } }, "api.LaunchQueue.setConsumer": { baseline: false, support: { chrome: "102", edge: "102" } }, "api.Window.launchQueue": { baseline: false, support: { chrome: "102", edge: "102" } }, "manifests.webapp.launch_handler": { baseline: false, support: { chrome: "110", chrome_android: "110", edge: "110" } }, "manifests.webapp.launch_handler.client_mode": { baseline: false, support: { chrome: "110", chrome_android: "110", edge: "110" } } }, support: { chrome: "110", edge: "110" } } }, "app-protocol-handlers": { compat_features: ["manifests.webapp.protocol_handlers", "manifests.webapp.protocol_ha\ +ndlers.protocol", "manifests.webapp.protocol_handlers.url"], description: "The protocol_handlers web app manifest member registers an installed web app as a handler for a specific protocol. When a user follows a link with the specified protocol, the installed app opens the link.", description_html: "The protocol_handlers web app manifest member registers an installed web app as a handler for a specific protocol. When a user follows a link with the specified protocol, the installed app opens the link.", group: ["progressive-web-app"], kind: "feature", name: "Protocol handlers", spec: ["https://wicg.github.io/manifest-incubations/#protocol_handlers-member"], status: { baseline: false, by_compat_key: { "manifests.webapp.protocol_handlers": { baseline: false, support: { chrome: "96", edge: "96" } }, "manifests.webapp.protocol_handlers.protocol": { baseline: false, support: { chrome: "96", edge: "96" } }, "manifests.webapp.protocol_handlers.url": { baseline: false, support: { chrome: "\ +96", edge: "96" } } }, support: { chrome: "96", edge: "96" } } }, "app-share-targets": { compat_features: ["manifests.webapp.share_target"], description: "The share_target web app manifest member registers an installed web app as a handler for shared content. When a user shares content by using the device share dialog, the installed app can be listed as an option for handling the shared content.", description_html: "The share_target web app manifest member registers an installed web app as a handler for shared content. When a user shares content by using the device share dialog, the installed app can be listed as an option for handling the shared content.", group: ["progressive-web-app"], kind: "feature", name: "Share targets", spec: ["https://w3c.github.io/web-share-target/#share_target-member"], status: { baseline: false, by_compat_key: { "manifests.webapp.share_target": { baseline: false, support: { chrome: "89", chrome_android: "76", edge: "89" } } }, support: { chrome: "\ +89", chrome_android: "76", edge: "89" } } }, "app-shortcuts": { compat_features: ["manifests.webapp.shortcuts"], description: "The shortcuts web app manifest member registers common actions of an installed web app with the device. The device can present these actions to the user in contextually appropriate locations, such as jump lists on Windows or the app launcher on Android.", description_html: "The shortcuts web app manifest member registers common actions of an installed web app with the device. The device can present these actions to the user in contextually appropriate locations, such as jump lists on Windows or the app launcher on Android.", group: ["progressive-web-app"], kind: "feature", name: "Application shortcuts", spec: ["https://w3c.github.io/manifest/#shortcuts-member"], status: { baseline: false, by_compat_key: { "manifests.webapp.shortcuts": { baseline: false, support: { chrome: "96", chrome_android: "84", edge: "96", safari: "17.4" } } }, support: { chrome: "\ +96", chrome_android: "84", edge: "96", safari: "17.4" } } }, appearance: { compat_features: ["css.properties.appearance", "css.properties.appearance.auto", "css.properties.appearance.button", "css.properties.appearance.checkbox", "css.properties.appearance.listbox", "css.properties.appearance.menulist", "css.properties.appearance.menulist-button", "css.properties.appearance.meter", "css.properties.appearance.none", "css.properties.appearance.progress-bar", "css.properties.appearance.radio", "css.properties.appearance.searchfield", "css.properties.appearance.textarea", "css.properties.appearance.textfield"], description: "The appearance CSS property controls the appearance of form controls. Using appearance: none disables any default native appearance and allows the elements to be styled with CSS.", description_html: "The appearance CSS property controls the appearance of form controls. Using appearance: none disables any default native appearance and allows th\ +e elements to be styled with CSS.", group: ["css"], kind: "feature", name: "appearance", spec: ["https://drafts.csswg.org/css-ui-4/#appearance-switching"], status: { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", by_compat_key: { "css.properties.appearance": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.auto": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.button": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "\ +15.4", safari_ios: "15.4" } }, "css.properties.appearance.checkbox": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.listbox": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.menulist": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.menulist-button": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "\ +84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.meter": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.none": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.progress-bar": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.radio": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "\ +84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.searchfield": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.textarea": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } }, "css.properties.appearance.textfield": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "80", safari: "15.4", safari_ios: "15.4" } } }, support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "80", firefox_android: "\ +80", safari: "15.4", safari_ios: "15.4" } } }, "arguments-callee": { compat_features: ["javascript.functions.arguments.callee"], description: "The callee property of the arguments variable in a non-strict function body's local scope is the function that arguments belongs to.", description_html: "The callee property of the arguments variable in a non-strict function body's local scope is the function that arguments belongs to.", discouraged: { according_to: ["https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-arguments-exotic-objects"], reason: "JavaScript strict mode prohibits accessing arguments.callee.", reason_html: "JavaScript strict mode prohibits accessing arguments.callee." }, group: ["javascript"], kind: "feature", name: "arguments.callee", spec: ["https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-arguments-exotic-objects"], status: { baseline: false, by_compat_key: { + "javascript.functions.arguments.callee": { baseline: false, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, "aria-attribute-reflection": { compat_features: ["api.Element.ariaActiveDescendantElement", "api.Element.ariaAtomic", "api.Element.ariaAutoComplete", "api.Element.ariaBrailleLabel", "api.Element.ariaBrailleRoleDescription", "api.Element.ariaBusy", "api.Element.ariaChecked", "api.Element.ariaColCount", "api.Element.ariaColIndex", "api.Element.ariaColIndexText", "api.Element.ariaColSpan", "api.Element.ariaControlsElements", "api.Element.ariaCurrent", "api.Element.ariaDescribedByElements", "api.Element.ariaDescription", "api.Element.ariaDetailsElements", "api.Element.ariaDisabled", "api.Element.ariaErrorMessageElements", "api.Element.ariaExpanded", "api.Element.ariaFlowT\ +oElements", "api.Element.ariaHasPopup", "api.Element.ariaHidden", "api.Element.ariaInvalid", "api.Element.ariaKeyShortcuts", "api.Element.ariaLabel", "api.Element.ariaLabelledByElements", "api.Element.ariaLevel", "api.Element.ariaLive", "api.Element.ariaModal", "api.Element.ariaMultiLine", "api.Element.ariaMultiSelectable", "api.Element.ariaOrientation", "api.Element.ariaOwnsElements", "api.Element.ariaPlaceholder", "api.Element.ariaPosInSet", "api.Element.ariaPressed", "api.Element.ariaReadOnly", "api.Element.ariaRelevant", "api.Element.ariaRequired", "api.Element.ariaRoleDescription", "api.Element.ariaRowCount", "api.Element.ariaRowIndex", "api.Element.ariaRowIndexText", "api.Element.ariaRowSpan", "api.Element.ariaSelected", "api.Element.ariaSetSize", "api.Element.ariaSort", "api.Element.ariaValueMax", "api.Element.ariaValueMin", "api.Element.ariaValueNow", "api.Element.ariaValueText", "api.Element.role", "api.ElementInternals.ariaActiveDescendantElement", "api.ElementInternals.ariaA\ +tomic", "api.ElementInternals.ariaAutoComplete", "api.ElementInternals.ariaBrailleLabel", "api.ElementInternals.ariaBrailleRoleDescription", "api.ElementInternals.ariaBusy", "api.ElementInternals.ariaChecked", "api.ElementInternals.ariaColCount", "api.ElementInternals.ariaColIndex", "api.ElementInternals.ariaColIndexText", "api.ElementInternals.ariaColSpan", "api.ElementInternals.ariaControlsElements", "api.ElementInternals.ariaCurrent", "api.ElementInternals.ariaDescribedByElements", "api.ElementInternals.ariaDescription", "api.ElementInternals.ariaDetailsElements", "api.ElementInternals.ariaDisabled", "api.ElementInternals.ariaErrorMessageElements", "api.ElementInternals.ariaExpanded", "api.ElementInternals.ariaFlowToElements", "api.ElementInternals.ariaHasPopup", "api.ElementInternals.ariaHidden", "api.ElementInternals.ariaInvalid", "api.ElementInternals.ariaKeyShortcuts", "api.ElementInternals.ariaLabel", "api.ElementInternals.ariaLabelledByElements", "api.ElementInternals.ariaLeve\ +l", "api.ElementInternals.ariaLive", "api.ElementInternals.ariaModal", "api.ElementInternals.ariaMultiLine", "api.ElementInternals.ariaMultiSelectable", "api.ElementInternals.ariaOrientation", "api.ElementInternals.ariaOwnsElements", "api.ElementInternals.ariaPlaceholder", "api.ElementInternals.ariaPosInSet", "api.ElementInternals.ariaPressed", "api.ElementInternals.ariaReadOnly", "api.ElementInternals.ariaRequired", "api.ElementInternals.ariaRoleDescription", "api.ElementInternals.ariaRowCount", "api.ElementInternals.ariaRowIndex", "api.ElementInternals.ariaRowIndexText", "api.ElementInternals.ariaRowSpan", "api.ElementInternals.ariaSelected", "api.ElementInternals.ariaSetSize", "api.ElementInternals.ariaSort", "api.ElementInternals.ariaValueMax", "api.ElementInternals.ariaValueMin", "api.ElementInternals.ariaValueNow", "api.ElementInternals.ariaValueText", "api.ElementInternals.role"], description: "WAI-ARIA attributes have corresponding properties on Element and ElementInternals obj\ +ects.", description_html: "WAI-ARIA attributes have corresponding properties on Element and ElementInternals objects.", kind: "feature", name: "ARIA attribute reflection", spec: ["https://w3c.github.io/aria/#accessibilityroleandproperties-correspondence"], status: { baseline: "low", baseline_low_date: "2023-10-24", by_compat_key: { "api.Element.ariaActiveDescendantElement": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaAtomic": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaAutoComplete": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "\ +12.1", safari_ios: "12.2" } }, "api.Element.ariaBrailleLabel": { baseline: "low", baseline_low_date: "2024-09-16", support: { chrome: "107", chrome_android: "107", edge: "107", firefox: "125", firefox_android: "125", safari: "18", safari_ios: "18" } }, "api.Element.ariaBrailleRoleDescription": { baseline: "low", baseline_low_date: "2024-09-16", support: { chrome: "107", chrome_android: "107", edge: "107", firefox: "125", firefox_android: "125", safari: "18", safari_ios: "18" } }, "api.Element.ariaBusy": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaChecked": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaColCount": { baseline: "low", baseline_low_date: "2023-10-24", support: { + chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaColIndex": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaColIndexText": { baseline: "low", baseline_low_date: "2025-12-12", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "119", firefox_android: "119", safari: "26.2", safari_ios: "26.2" } }, "api.Element.ariaColSpan": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaControlsElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", + safari_ios: "16.4" } }, "api.Element.ariaCurrent": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaDescribedByElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaDescription": { baseline: "low", baseline_low_date: "2024-03-05", support: { chrome: "83", chrome_android: "83", edge: "83", firefox: "119", firefox_android: "119", safari: "17.4", safari_ios: "17.4" } }, "api.Element.ariaDetailsElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaDisabled": { baseline: "low", baseline_low_date: "202\ +3-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaErrorMessageElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaExpanded": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaFlowToElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaHasPopup": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "\ +119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaHidden": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaInvalid": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "102", chrome_android: "102", edge: "102", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaKeyShortcuts": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaLabel": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaLabelledByElements": { baseline: "low", baseline_low_date: "\ +2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaLevel": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaLive": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaModal": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaMultiLine": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "\ +12.2" } }, "api.Element.ariaMultiSelectable": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaOrientation": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaOwnsElements": { baseline: false, support: { firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.Element.ariaPlaceholder": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaPosInSet": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", + safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaPressed": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaReadOnly": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRelevant": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRequired": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRoleDescription": { baseline: "low", baseline_low_date: "2023-10\ +-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRowCount": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRowIndex": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaRowIndexText": { baseline: "low", baseline_low_date: "2025-12-12", support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "119", firefox_android: "119", safari: "26.2", safari_ios: "26.2" } }, "api.Element.ariaRowSpan": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", + safari_ios: "12.2" } }, "api.Element.ariaSelected": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaSetSize": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaSort": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaValueMax": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaValueMin": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "8\ +1", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaValueNow": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.ariaValueText": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.Element.role": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "103", chrome_android: "103", edge: "103", firefox: "119", firefox_android: "119", safari: "12.1", safari_ios: "12.2" } }, "api.ElementInternals.ariaActiveDescendantElement": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "\ +16.4" } }, "api.ElementInternals.ariaAtomic": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaAutoComplete": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaBrailleLabel": { baseline: "low", baseline_low_date: "2024-09-16", support: { chrome: "107", chrome_android: "107", edge: "107", firefox: "125", firefox_android: "125", safari: "18", safari_ios: "18" } }, "api.ElementInternals.ariaBrailleRoleDescription": { baseline: "low", baseline_low_date: "2024-09-16", support: { chrome: "107", chrome_android: "107", edge: "107", firefox: "125", firefox_android: "125", safari: "18", safari_ios: "18" } }, "api.ElementInternals.ariaBusy": { baseline: "low", baseline_low_date: "\ +2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaChecked": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaColCount": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaColIndex": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaColIndexText": { baseline: false, support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "119", firefox_android: "119" } }, + "api.ElementInternals.ariaColSpan": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaControlsElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaCurrent": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaDescribedByElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaDescription": { baseline: false, support: { + chrome: "83", chrome_android: "83", edge: "83", firefox: "119", firefox_android: "119" } }, "api.ElementInternals.ariaDetailsElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaDisabled": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaErrorMessageElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaExpanded": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "\ +16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaFlowToElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaHasPopup": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaHidden": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaInvalid": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "102", chrome_android: "102", edge: "102", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaKeyShortcuts": { baseline: "\ +low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaLabel": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaLabelledByElements": { baseline: "low", baseline_low_date: "2025-04-04", support: { chrome: "135", chrome_android: "135", edge: "135", firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaLevel": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaLive": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", + edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaModal": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaMultiLine": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaMultiSelectable": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaOrientation": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "\ +16.4" } }, "api.ElementInternals.ariaOwnsElements": { baseline: false, support: { firefox: "136", firefox_android: "136", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaPlaceholder": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaPosInSet": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaPressed": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaReadOnly": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "\ +119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaRequired": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaRoleDescription": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaRowCount": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaRowIndex": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.Elemen\ +tInternals.ariaRowIndexText": { baseline: false, support: { chrome: "128", chrome_android: "128", edge: "128", firefox: "119", firefox_android: "119" } }, "api.ElementInternals.ariaRowSpan": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaSelected": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaSetSize": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "84", chrome_android: "84", edge: "84", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaSort": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "\ +119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaValueMax": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaValueMin": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaValueNow": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.ariaValueText": { baseline: "low", baseline_low_date: "2023-10-24", support: { chrome: "81", chrome_android: "81", edge: "81", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } }, "api.ElementInternals.role": { baseline: "\ +low", baseline_low_date: "2023-10-24", support: { chrome: "103", chrome_android: "103", edge: "103", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } } }, support: { chrome: "103", chrome_android: "103", edge: "103", firefox: "119", firefox_android: "119", safari: "16.4", safari_ios: "16.4" } } }, arianotify: { compat_features: ["api.Document.ariaNotify", "api.Element.ariaNotify"], description: "The ariaNotify() method of Element and Document requests assistive technology software, if activated, to announce a message to the user. This can help make dynamic content changes more accessible to users.", description_html: "The ariaNotify() method of Element and Document requests assistive technology software, if activated, to announce a message to the user. This can help make dynamic content changes more accessible to users.", kind: "feature", name: "ariaNotify()", spec: ["https://github.com/MicrosoftEdge/MSEdgeExplainers/bl\ +ob/main/Accessibility/AriaNotify/explainer.md"], status: { baseline: false, by_compat_key: { "api.Document.ariaNotify": { baseline: false, support: {} }, "api.Element.ariaNotify": { baseline: false, support: {} } }, support: {} } }, array: { compat_features: ["javascript.builtins.Array", "javascript.builtins.Array.Array", "javascript.builtins.Array.concat", "javascript.builtins.Array.join", "javascript.builtins.Array.length", "javascript.builtins.Array.pop", "javascript.builtins.Array.push", "javascript.builtins.Array.reverse", "javascript.builtins.Array.shift", "javascript.builtins.Array.slice", "javascript.builtins.Array.sort", "javascript.builtins.Array.toString", "javascript.builtins.Array.unshift", "javascript.grammar.array_literals"], description: "Arrays are ordered lists of JavaScript values.", description_html: "Arrays are ordered lists of JavaScript values.", group: ["arrays"], kind: "feature", name: "Array (initial support)", snapshot: ["ecmascript-1"], spec: ["https://tc39.\ +es/ecma262/multipage/indexed-collections.html#sec-array-objects", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array-constructor", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.concat", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.join", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-properties-of-array-instances-length", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.pop", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.push", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.reverse", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.shift", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.slice", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.sort", "https://tc39.es/ecma262/multipage/indexed-co\ +llections.html#sec-array.prototype.tolocalestring", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.tostring", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.unshift", "https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-array-initializer"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "javascript.builtins.Array": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.Array": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.concat": { baseline: "high", baseline_high_date: "\ +2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.join": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.length": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.pop": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.push": { baseline: "high", baseline_high_date: "201\ +8-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.reverse": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.shift": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.slice": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.sort": { baseline: "high", baseline_high_date: "20\ +18-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.toString": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.builtins.Array.unshift": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } }, "javascript.grammar.array_literals": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", + firefox_android: "4", safari: "1", safari_ios: "1" } } }, "array-at": { compat_features: ["javascript.builtins.Array.at", "javascript.builtins.TypedArray.at"], description: "The at() method of arrays and typed arrays returns the item at an index, including negative indices for getting items relative to the end of an array. Also known as the relative indexing method.", description_html: "The at() method of arrays and typed arrays returns the item at an index, including negative indices for getting items relative to the end of an array. Also known as the relative indexing method.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array at()", snapshot: ["ecmascript-2022"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.at"], status: { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", by_compat_key: { "javascript.builtins.Array.at": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "\ +2022-03-14", support: { chrome: "92", chrome_android: "92", edge: "92", firefox: "90", firefox_android: "90", safari: "15.4", safari_ios: "15.4" } }, "javascript.builtins.TypedArray.at": { baseline: "high", baseline_high_date: "2024-09-14", baseline_low_date: "2022-03-14", support: { chrome: "92", chrome_android: "92", edge: "92", firefox: "90", firefox_android: "90", safari: "15.4", safari_ios: "15.4" } } }, support: { chrome: "92", chrome_android: "92", edge: "92", firefox: "90", firefox_android: "90", safari: "15.4", safari_ios: "15.4" } } }, "array-by-copy": { compat_features: ["javascript.builtins.Array.toReversed", "javascript.builtins.Array.toSorted", "javascript.builtins.Array.toSpliced", "javascript.builtins.Array.with", "javascript.builtins.TypedArray.toReversed", "javascript.builtins.TypedArray.toSorted", "javascript.builtins.TypedArray.with"], description: "The toReversed(), toSorted(), toSpliced(), and with() methods of arrays and typed arrays return changed copies of arra\ +ys. They stand in contrast to methods such as sort() or reverse() that change arrays in place.", description_html: "The toReversed(), toSorted(), toSpliced(), and with() methods of arrays and typed arrays return changed copies of arrays. They stand in contrast to methods such as sort() or reverse() that change arrays in place.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array by copy", snapshot: ["ecmascript-2023"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.toreversed", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.tosorted", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.tospliced", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.with", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.toreversed", "https://tc\ +39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.tosorted", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.with"], status: { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", by_compat_key: { "javascript.builtins.Array.toReversed": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.Array.toSorted": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.Array.toSpliced": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "1\ +10", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.Array.with": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.TypedArray.toReversed": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.TypedArray.toSorted": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } }, "javascript.builtins.TypedArray.with": { baseline: "high", baseline_high_date: "2026-01-04", baseline_low_date: "\ +2023-07-04", support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } } }, support: { chrome: "110", chrome_android: "110", edge: "110", firefox: "115", firefox_android: "115", safari: "16", safari_ios: "16" } } }, "array-copywithin": { compat_features: ["javascript.builtins.Array.copyWithin", "javascript.builtins.TypedArray.copyWithin"], description: "The copyWithin() method of arrays and typed arrays shifts or copies items of an array to another index of the array without changing its length.", description_html: "The copyWithin() method of arrays and typed arrays shifts or copies items of an array to another index of the array without changing its length.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array copyWithin()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.copywithin"], status: { baseline: "high", baseline_high_date: "\ +2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.copyWithin": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "32", firefox_android: "32", safari: "9", safari_ios: "9" } }, "javascript.builtins.TypedArray.copyWithin": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "34", firefox_android: "34", safari: "10", safari_ios: "10" } } }, support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "34", firefox_android: "34", safari: "10", safari_ios: "10" } } }, "array-fill": { compat_features: ["javascript.builtins.Array.fill", "javascript.builtins.TypedArray.fill"], description: "The fill() method of arrays and typed arrays sets all or some items of an array to a given a value.", description_html: "The fill() method of \ +arrays and typed arrays sets all or some items of an array to a given a value.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array fill()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.fill", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.fill"], status: { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.fill": { baseline: "high", baseline_high_date: "2018-03-01", baseline_low_date: "2015-09-01", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "31", firefox_android: "31", safari: "8", safari_ios: "8" } }, "javascript.builtins.TypedArray.fill": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "37", firefox_android: "37", safari: "10", safari_ios: "10" } } }, + support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "37", firefox_android: "37", safari: "10", safari_ios: "10" } } }, "array-find": { caniuse: ["array-find", "array-find-index"], compat_features: ["javascript.builtins.Array.find", "javascript.builtins.Array.findIndex", "javascript.builtins.TypedArray.find", "javascript.builtins.TypedArray.findIndex"], description: "The find() and findIndex() methods of arrays and typed arrays search an array for the first item that satisfies a test function.", description_html: "The find() and findIndex() methods of arrays and typed arrays search an array for the first item that satisfies a test function.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array find() and findIndex()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.findindex", + "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.find", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.findindex"], status: { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.find": { baseline: "high", baseline_high_date: "2018-03-01", baseline_low_date: "2015-09-01", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "25", firefox_android: "4", safari: "8", safari_ios: "8" } }, "javascript.builtins.Array.findIndex": { baseline: "high", baseline_high_date: "2018-03-01", baseline_low_date: "2015-09-01", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "25", firefox_android: "4", safari: "8", safari_ios: "8" } }, "javascript.builtins.TypedArray.find": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "\ +12", firefox: "37", firefox_android: "37", safari: "10", safari_ios: "10" } }, "javascript.builtins.TypedArray.findIndex": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "37", firefox_android: "37", safari: "10", safari_ios: "10" } } }, support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "37", firefox_android: "37", safari: "10", safari_ios: "10" } } }, "array-findlast": { compat_features: ["javascript.builtins.Array.findLast", "javascript.builtins.Array.findLastIndex", "javascript.builtins.TypedArray.findLast", "javascript.builtins.TypedArray.findLastIndex"], description: "The findLast() and findLastIndex() methods of arrays and typed arrays search an array in reverse order for the first item that satisfies a test function.", description_html: "The findLast() and findLastIndex() methods of arrays and typed arrays search an array in rever\ +se order for the first item that satisfies a test function.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array findLast() and findLastIndex()", snapshot: ["ecmascript-2023"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.findlast", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.findlastindex", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.findlast", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.findlastindex"], status: { baseline: "high", baseline_high_date: "2025-02-23", baseline_low_date: "2022-08-23", by_compat_key: { "javascript.builtins.Array.findLast": { baseline: "high", baseline_high_date: "2025-02-23", baseline_low_date: "2022-08-23", support: { chrome: "97", chrome_android: "97", edge: "97", firefox: "104", firefox_android: "104", safari: "15.4", safari_ios: "15.4" } }, "javascript.builtins.Array.fi\ +ndLastIndex": { baseline: "high", baseline_high_date: "2025-02-23", baseline_low_date: "2022-08-23", support: { chrome: "97", chrome_android: "97", edge: "97", firefox: "104", firefox_android: "104", safari: "15.4", safari_ios: "15.4" } }, "javascript.builtins.TypedArray.findLast": { baseline: "high", baseline_high_date: "2025-02-23", baseline_low_date: "2022-08-23", support: { chrome: "97", chrome_android: "97", edge: "97", firefox: "104", firefox_android: "104", safari: "15.4", safari_ios: "15.4" } }, "javascript.builtins.TypedArray.findLastIndex": { baseline: "high", baseline_high_date: "2025-02-23", baseline_low_date: "2022-08-23", support: { chrome: "97", chrome_android: "97", edge: "97", firefox: "104", firefox_android: "104", safari: "15.4", safari_ios: "15.4" } } }, support: { chrome: "97", chrome_android: "97", edge: "97", firefox: "104", firefox_android: "104", safari: "15.4", safari_ios: "15.4" } } }, "array-flat": { caniuse: ["array-flat"], compat_features: ["javascript.bui\ +ltins.Array.flat", "javascript.builtins.Array.flatMap"], description: "The flat() and flatMap() methods for arrays creates a new array such that each nested array item is concatenated into it.", description_html: "The flat() and flatMap() methods for arrays creates a new array such that each nested array item is concatenated into it.", group: ["arrays"], kind: "feature", name: "Array flat() and flatMap()", snapshot: ["ecmascript-2019"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.flat", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.flatmap"], status: { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", by_compat_key: { "javascript.builtins.Array.flat": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "69", chrome_android: "69", edge: "79", firefox: "62", firefox_android: "62", safari: "12", safari_ios: "\ +12" } }, "javascript.builtins.Array.flatMap": { baseline: "high", baseline_high_date: "2022-07-15", baseline_low_date: "2020-01-15", support: { chrome: "69", chrome_android: "69", edge: "79", firefox: "62", firefox_android: "62", safari: "12", safari_ios: "12" } } }, support: { chrome: "69", chrome_android: "69", edge: "79", firefox: "62", firefox_android: "62", safari: "12", safari_ios: "12" } } }, "array-from": { compat_features: ["javascript.builtins.Array.from", "javascript.builtins.TypedArray.from"], description: "The Array.from() and typed array .from() static methods copy items from an iterable or array-like object to make a new array.", description_html: "The Array.from() and typed array .from() static methods copy items from an iterable or array-like object to make a new array.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array.from()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#se\ +c-array.from", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.of"], status: { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.from": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "32", firefox_android: "32", safari: "9", safari_ios: "9" } }, "javascript.builtins.TypedArray.from": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "38", firefox_android: "38", safari: "10", safari_ios: "10" } } }, support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "38", firefox_android: "38", safari: "10", safari_ios: "10" } } }, "array-fromasync": { compat_features: ["javascript.builtins.Array.fromAsync"], description: "The Array.fromAsync() static method copies it\ +ems from an async iterable object to make a new array.", description_html: "The Array.fromAsync() static method copies items from an async iterable object to make a new array.", group: ["arrays"], kind: "feature", name: "Array.fromAsync()", spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.fromasync"], status: { baseline: "low", baseline_low_date: "2024-01-25", by_compat_key: { "javascript.builtins.Array.fromAsync": { baseline: "low", baseline_low_date: "2024-01-25", support: { chrome: "121", chrome_android: "121", edge: "121", firefox: "115", firefox_android: "115", safari: "16.4", safari_ios: "16.4" } } }, support: { chrome: "121", chrome_android: "121", edge: "121", firefox: "115", firefox_android: "115", safari: "16.4", safari_ios: "16.4" } } }, "array-group": { compat_features: ["javascript.builtins.Map.groupBy", "javascript.builtins.Object.groupBy"], description: "The Object.groupBy() and Map.groupBy() static methods group values of arrays \ +and iterables based on a function that returns a key for each value.", description_html: "The Object.groupBy() and Map.groupBy() static methods group values of arrays and iterables based on a function that returns a key for each value.", group: ["maps"], kind: "feature", name: "Array grouping", spec: ["https://tc39.es/ecma262/multipage/abstract-operations.html#sec-groupby"], status: { baseline: "low", baseline_low_date: "2024-03-05", by_compat_key: { "javascript.builtins.Map.groupBy": { baseline: "low", baseline_low_date: "2024-03-05", support: { chrome: "117", chrome_android: "117", edge: "117", firefox: "119", firefox_android: "119", safari: "17.4", safari_ios: "17.4" } }, "javascript.builtins.Object.groupBy": { baseline: "low", baseline_low_date: "2024-03-05", support: { chrome: "117", chrome_android: "117", edge: "117", firefox: "119", firefox_android: "119", safari: "17.4", safari_ios: "17.4" } } }, support: { chrome: "117", chrome_android: "117", edge: "\ +117", firefox: "119", firefox_android: "119", safari: "17.4", safari_ios: "17.4" } } }, "array-includes": { caniuse: ["array-includes"], compat_features: ["javascript.builtins.Array.includes", "javascript.builtins.TypedArray.includes"], description: "The includes() method of arrays and typed arrays returns whether a given value appears in the array.", description_html: "The includes() method of arrays and typed arrays returns whether a given value appears in the array.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array includes()", snapshot: ["ecmascript-2016"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.includes", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.prototype.includes"], status: { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.includes": { baseline: "high", baseline_high_date: "2019-02-02", + baseline_low_date: "2016-08-02", support: { chrome: "47", chrome_android: "47", edge: "14", firefox: "43", firefox_android: "43", safari: "9", safari_ios: "9" } }, "javascript.builtins.TypedArray.includes": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "47", chrome_android: "47", edge: "14", firefox: "43", firefox_android: "43", safari: "10", safari_ios: "10" } } }, support: { chrome: "47", chrome_android: "47", edge: "14", firefox: "43", firefox_android: "43", safari: "10", safari_ios: "10" } } }, "array-isarray": { compat_features: ["javascript.builtins.Array.isArray"], description: "The Array.isArray() static method checks whether a value is an array.", description_html: "The Array.isArray() static method checks whether a value is an array.", group: ["arrays"], kind: "feature", name: "Array.isArray()", snapshot: ["ecmascript-5"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.i\ +sarray"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "javascript.builtins.Array.isArray": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "4", chrome_android: "18", edge: "12", firefox: "4", firefox_android: "4", safari: "5", safari_ios: "5" } } }, support: { chrome: "4", chrome_android: "18", edge: "12", firefox: "4", firefox_android: "4", safari: "5", safari_ios: "5" } } }, "array-iteration-methods": { compat_features: ["javascript.builtins.Array.every", "javascript.builtins.Array.filter", "javascript.builtins.Array.forEach", "javascript.builtins.Array.indexOf", "javascript.builtins.Array.lastIndexOf", "javascript.builtins.Array.map", "javascript.builtins.Array.reduce", "javascript.builtins.Array.reduceRight", "javascript.builtins.Array.some"], description: "Array iteration methods", description_html: "Array iteration methods", group: ["arrays"], kind: "featu\ +re", name: "Array iteration methods", snapshot: ["ecmascript-5"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.every", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.filter", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.foreach", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.indexof", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.lastindexof", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.map", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.reduce", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.reduceright", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.some"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "javasc\ +ript.builtins.Array.every": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Array.filter": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Array.forEach": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Array.indexOf": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, + "javascript.builtins.Array.lastIndexOf": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Array.map": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } }, "javascript.builtins.Array.reduce": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "3", chrome_android: "18", edge: "12", firefox: "3", firefox_android: "4", safari: "4", safari_ios: "3.2" } }, "javascript.builtins.Array.reduceRight": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "3", chrome_android: "18", edge: "12", firefox: "3", firefox_android: "4", safari: "4", safari_ios: "\ +3.2" } }, "javascript.builtins.Array.some": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1.5", firefox_android: "4", safari: "3", safari_ios: "1" } } }, support: { chrome: "3", chrome_android: "18", edge: "12", firefox: "3", firefox_android: "4", safari: "4", safari_ios: "3.2" } } }, "array-iterators": { compat_features: ["javascript.builtins.Array.@@iterator", "javascript.builtins.Array.entries", "javascript.builtins.Array.keys", "javascript.builtins.Array.values"], description: "Arrays are iterable with the for … of statement and enumerable with the methods entries(), keys(), and values().", description_html: "Arrays are iterable with the for … of statement and enumerable with the methods entries(), keys(), and values().", group: ["arrays", "iterators"], kind: "feature", name: "Array iterators", snapshot: ["ecmascript-20\ +15"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype-@@iterator", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.entries", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.keys", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.values"], status: { baseline: "high", baseline_high_date: "2020-11-09", baseline_low_date: "2018-05-09", by_compat_key: { "javascript.builtins.Array.@@iterator": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "38", chrome_android: "38", edge: "12", firefox: "36", firefox_android: "36", safari: "10", safari_ios: "10" } }, "javascript.builtins.Array.entries": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "38", chrome_android: "38", edge: "12", firefox: "28", firefox_android: "28", safari: "8", safari_ios: "8" } }, "\ +javascript.builtins.Array.keys": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "38", chrome_android: "38", edge: "12", firefox: "28", firefox_android: "28", safari: "8", safari_ios: "8" } }, "javascript.builtins.Array.values": { baseline: "high", baseline_high_date: "2020-11-09", baseline_low_date: "2018-05-09", support: { chrome: "66", chrome_android: "66", edge: "14", firefox: "60", firefox_android: "60", safari: "9", safari_ios: "9" } } }, support: { chrome: "66", chrome_android: "66", edge: "14", firefox: "60", firefox_android: "60", safari: "10", safari_ios: "10" } } }, "array-of": { compat_features: ["javascript.builtins.Array.of", "javascript.builtins.TypedArray.of"], description: "The Array.of() and typed array .of() static methods create new arrays from the values of any number of arguments.", description_html: "The Array.of() and typed array .of() static methods create new arrays from the va\ +lues of any number of arguments.", group: ["arrays", "typed-arrays"], kind: "feature", name: "Array.of()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.of", "https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%25typedarray%25.of"], status: { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", by_compat_key: { "javascript.builtins.Array.of": { baseline: "high", baseline_high_date: "2018-03-30", baseline_low_date: "2015-09-30", support: { chrome: "45", chrome_android: "39", edge: "12", firefox: "25", firefox_android: "25", safari: "9", safari_ios: "9" } }, "javascript.builtins.TypedArray.of": { baseline: "high", baseline_high_date: "2019-03-20", baseline_low_date: "2016-09-20", support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "38", firefox_android: "38", safari: "10", safari_ios: "10" } } }, support: { chrome: "45", chrome_android: "45", edge: "12", firefox: "38", + firefox_android: "38", safari: "10", safari_ios: "10" } } }, "array-splice": { compat_features: ["javascript.builtins.Array.splice"], description: "The array splice() method changes an array in-place. You can use it to delete items, overwrite items, or insert items, starting from an index.", description_html: "The array splice() method changes an array in-place. You can use it to delete items, overwrite items, or insert items, starting from an index.", group: ["arrays"], kind: "feature", name: "Array splice()", snapshot: ["ecmascript-2015"], spec: ["https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.splice"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "javascript.builtins.Array.splice": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "\ +1", safari_ios: "1" } } }, support: { chrome: "1", chrome_android: "18", edge: "12", firefox: "1", firefox_android: "4", safari: "1", safari_ios: "1" } } }, article: { compat_features: ["html.elements.article"], description: "The
element represents self-contained content, which is intended to be independently distributable or reusable, such as a comment, a blog post, or news article.", description_html: "The <article> element represents self-contained content, which is intended to be independently distributable or reusable, such as a comment, a blog post, or news article.", group: ["html-elements"], kind: "feature", name: "
", spec: ["https://html.spec.whatwg.org/multipage/sections.html#the-article-element"], status: { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", by_compat_key: { "html.elements.article": { baseline: "high", baseline_high_date: "2018-01-29", baseline_low_date: "2015-07-29", support: { chrome: "5", + chrome_android: "18", edge: "12", firefox: "4", firefox_android: "4", safari: "5", safari_ios: "4.2" } } }, support: { chrome: "5", chrome_android: "18", edge: "12", firefox: "4", firefox_android: "4", safari: "5", safari_ios: "4.2" } } }, aside: { compat_features: ["html.elements.aside"], description: "The