diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d3366d3 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + env: { + node: true, + }, + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + plugins: ["@typescript-eslint", "prettier"], + rules: { + "prettier/prettier": 2, + "@typescript-eslint/no-explicit-any": ["error", { ignoreRestArgs: true }], + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e859a8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# basically ignore .vscode but allow for some specific files such as debug +.vscode/**/* +!.vscode/launch.json + +# logs +logs +*.log + +# docs +docs +documentation/_build/ +documentation/_static/ +documentation/_templates/ + +# modules +node_modules +!extensions/node_modules + +# distribution +dist diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..75fac8e --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run lint diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..8affc64 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,17 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "bracketSameLine": true, + "endOfLine": "lf", + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "printWidth": 100, + "proseWrap": "always", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": false, + "useTabs": false, + "tabWidth": 2, + "trailingComma": "es5" +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e8d1c47 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.1.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug TypeScript", + "program": "${file}", + "cwd": "${workspaceRoot}", + "runtimeArgs": ["-r", "ts-node/register"] + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f682f4e..296a0ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,37 @@ # Contributing -### License +## License - is licensed under the terms in [LICENSE]. By contributing to the project, you agree to the license and copyright terms therein and release your contribution under these terms. +Webinizer is licensed under the terms in [LICENSE](LICENSE). By contributing to the project, you +agree to the license and copyright terms therein and release your contribution under these terms. + +## How to contribute + +We welcome contributions to Webinizer. You can: + +- Log a bug or provide feedback with an [issue]. +- Submit your changes directly with a [pull request]. + +### Pull requests + +This project follows a simple workflow with contributions delivered as PRs against the main branch. +To submit your change: + +- Make sure your code is in line with our coding conventions by running `npm run lint` to format the + code. +- Create an [issue] describing the bug the PR fixes or the feature you intend to implement. +- Submit a [pull request] into the main branch. + +Your PR will then be reviewed by one or more maintainers. Your PR will be automatically merged +(assuming no conflicts) with one approving review. Maintainers may suggest changes to a PR before +approving. ### Sign your work -Please use the sign-off line at the end of the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify -the below (from [developercertificate.org](http://developercertificate.org/)): +Please use the sign-off line at the end of the patch. Your signature certifies that you wrote the +patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty +simple: if you can certify the below (from +[developercertificate.org](http://developercertificate.org/)): ``` Developer Certificate of Origin @@ -53,5 +77,8 @@ Then you just add a line to every git commit message: Use your real name (sorry, no pseudonyms or anonymous contributions.) -If you set your `user.name` and `user.email` git configs, you can sign your -commit automatically with `git commit -s`. +If you set your `user.name` and `user.email` git configs, you can sign your commit automatically +with `git commit -s`. + +[issue]: https://github.com/intel/webinizer/issues +[pull request]: https://github.com/intel/webinizer/pulls diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..afa3291 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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 2023 Intel Corporation + + 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b510d1b --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# Webinizer + +> [!IMPORTANT]\ +> Webinizer is now in **_Beta_** trial. We'd greatly appreciate your feedback! + +## About + +Webinizer is a collection of tools to convert native applications, such as these programmed by +C/C++/Rust, to Web applications which are constructed by HTML/CSS/JavaScript and WebAssembly. + +Webinizer consists of two parts; a core engine that analyzes the code and then either fixes or +highlights issues, and a web frontend to configure projects and display results. This repo consists +of the core engine, for the web frontend see the +[webinizer-webclient](https://github.com/intel/webinizer-webclient) repo. + +We also provide the [webinizer-demo](https://github.com/intel/webinizer-demo) repo that holds the +demo projects and build scripts to setup Webinizer. + +## Setting up Webinizer + +### Run with Docker (recommended) + +Webinizer provides scripts to build a Docker image that will setup everything for you and make +Webinizer ready to use out of the box. + +Please follow the Docker installation and setup [guide](./documentation/installation-setup.rst) for +the detailed instructions. + +### Run locally + +The Webinizer also supports running locally `without` Docker. Currently this is validated on Linux +(`Ubuntu 20.04`). + +Please follow the Run locally [guide](https://github.com/intel/webinizer-demo#run-webinizer-locally) +for the detailed instructions. + +## Documentation + +Webinizer User Manual is available under [documentation/](./documentation/) folder with below +structure. + +### Using Webinizer + +- [Installation and setup](./documentation/installation-setup.rst) +- [Build a simple project](./documentation/build-a-simple-project.rst) +- [Build and define a library](./documentation/build-a-module.rst) +- [Build a project with dependencies](./documentation/build-a-project-with-dependencies.rst) + +### Extending Webinizer + +Webinizer provides an extension mechanism for developers to extend the capabilities of the tool. + +- [Extension Overview](./documentation/extensions/index.rst) +- [How to develop an Extension](./documentation/extensions/develop-an-extension.rst) +- [How to use an Extension](./documentation/extensions/use-an-extension.rst) +- [How to install an Extension](./documentation/extensions/install-an-extension.rst) +- [How to test an Extension](./documentation/extensions/use-an-extension.rst) + +## Setting up the development environment + +The steps to setup the development environment are similar to those described in +[Run Webinizer locally](#run-locally). + +### Basic commands + +- `npm run serve` to launch the core engine server and start at port 16666. +- `npm run test` to run the unit tests, see [tests/README.md](./tests/README.md) for details. +- `npm run lint` to format code with ESLint. +- `npm run doc` to generate the Webinizer Extension API document into `./docs`. + +### Recommended IDE setup + +It's preferred to use [VS Code](https://code.visualstudio.com/) for development. + +It's preferred to use Prettier formatter, along with `Format on Save`. Please setup the +[Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) and +[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extensions and +configure them accordingly. + +NOTE that we set printWidth as 100 and tab width as 2. + +## Contributing + +We welcome contributions to Webinizer. You can find more details in +[CONTRIBUTING.md](CONTRIBUTING.md) . diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..a080faa --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,15 @@ +# Support + +For general queries about the project, goals, status, etc email paul.g.cooper@intel.com. + +Submit feature requests and bug reports to the GitHub [issues] page. Refer to GitHub's +[Creating an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-an-issue) +for instructions. + +## Status + +Webinizer is a WPE pathfinding project and as such is not yet suitable for broad usage. Support +bandwidth is limited, and we will focus on well documented [issues], ideally with test cases. We +always welcome contributions, for more detail see [CONTRIBUTING.md](CONTRIBUTING.md). Caveat Emptor. + +[issues]: https://github.com/intel/webinizer/issues diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/documentation/build-a-module.rst b/documentation/build-a-module.rst new file mode 100644 index 0000000..996db29 --- /dev/null +++ b/documentation/build-a-module.rst @@ -0,0 +1,62 @@ +.. _build-a-module: + +Build and define a library +########################## + +This section will introduce the process of building and defining a library to reuse it in a bigger project using Webinizer. + +Build a library +*************** + +The process of building a library module is similar to that described in the :ref:`build-a-simple-project` section. We'll take the demo project ``Ncurses``, which is a library that allows the programmer to write text-based user interfaces (TUI) in a terminal-independent manner, as an example to go through the processes. + +Select the `Ncurses` demo project from ``Get started`` page. Click the checkbox of ``Check the box if the project is a library.`` at the bottom as we are building a library module. + +.. image:: images/build-a-module/basic-configs-ncurses.png + +Navigate to the `Build steps` page to define build target and build steps. Set build target as ``static`` and accept the recommended build steps from Webinizer. As a library, we'd like to install the library files after a successful build. Click the ``ADD STEP`` button to add another step `make install`. Choose ``Build tools type`` as `make` and add ``Arguments for build`` as `install`, then click the ``SAVE`` button. + +.. image:: images/build-a-module/add-build-step-ncurses.png + +Navigate to the `Build` page and click the ``BUILD`` button to trigger our first build. We'll be prompted with two recipes generated from Webinizer pre-build checks: + +* `Recipe for main loop issue`: the `Ncurses` library doesn't have the main loop issue, so we can click the ``IGNORE`` button to dismiss this recipe. +* `Recipe for pthread support`: the detected pthreads usage in the `Ncurses` library are from test files, so we can also click the ``IGNORE`` button to proceed. + +.. image:: images/build-a-module/ignore-recipes-ncurses.png + +After these recipes are dismissed, we can click the ``BUILD`` button for a second build. + +This build will take a longer time so we can check the live build log to understand the build status. After a while, another recipe on ``building intermedium tools with native compiler other than Emscripten`` issue appears. As per the suggestion shown, for `Ncurses` library, we need to enable `cross-platform compiling` and use `gcc` to build these tools to solve this issue. We can add arguments to the `configure` build step to achieve this. + +Navigate back to the `Build Steps` page and click the ``MANAGE STEPS`` button to enable editing build steps at first. Then add the arguments ``--build=x86_64-pc-emscripten --host=x86_64-pc-linux-gnu`` to the ``Arguments for build`` field of **Step 1** `configure`. Click the ``FINISH`` button to save the changes. + +.. image:: images/build-a-module/add-build-step-args-ncurses.png + +Navigate to the `Build` page and click the ``BUILD`` button for a third build. A recipe on ``strip issue`` is generated by Webinizer. Similar as the previous action, we can follow the suggestions from the recipe and add the argument ``--disable-stripping`` to **Step 1** `configure` in `Build Steps` page. + +Navigate to the `Build` page and click the ``BUILD`` button for a fourth build. A recipe on ``C++ exception`` issue is generated by Webinizer. We can click ``IGNORE`` button on the recipe to dismiss it as the usage of C++ exception catching is detected from demos, which is not related to the core library. + +Click the ``BUILD`` button for a fifth build. If everything goes well, after a while, we'll be notified a successful build from Webinizer. We can click the ``Library`` tab from build results section to view the built library files. + +.. image:: images/build-a-module/build-results-ncurses.png + +Define a library +**************** + +After building a library successfully, an important additional step required is to define the package configurations and native library information that will be utilized by other projects depending on this library. Click the ``Package & Native library info`` section in the `Config` page will navigate us to the configuration section. + +.. image:: images/build-a-module/pkg-configs-ncurses.png + +For `Ncurses` library, we'd define the package configurations as below for the ``static`` build target. Note that if multiple targets are defined, we should set the package configurations for each target respectively. Detailed explanations of the package configurations fields are available in :ref:`package-configs-explaination`. + +* **Prefix**: ``${projectRoot}/webinizer_build`` +* **Compiler flags**: ``'-I${prefix}/include'`` +* **Linker flags**: ``'-L${prefix}/lib' -lncurses '--preload-file ${prefix}/lib/terminfo@/home/web_user/.terminfo'`` + +In addition, we also need to set the native library information with `name` and `version`. Below is the example for `Ncurses` library. + +* **name**: ``ncurses`` +* **version**: ``6.1.20180127`` + +After all the fields are filled in correctly, we have now completed defining the `Ncurses` library. diff --git a/documentation/build-a-project-with-dependencies.rst b/documentation/build-a-project-with-dependencies.rst new file mode 100644 index 0000000..131fef4 --- /dev/null +++ b/documentation/build-a-project-with-dependencies.rst @@ -0,0 +1,64 @@ +.. _build-a-project-with-dependencies: + +Build a project with dependencies +################################# + +Webinizer supports adding dependencies to a project and manages the building process with dependencies automatically. This section will introduce how to build a project with dependent libraries using Webinizer. + +We'll take the demo project ``2048`` as an example, which is a classical puzzle game that reuses the ``Ncurses`` library we built in section :ref:`build-a-module` as a dependency. + +Add a dependency +**************** + +To add dependencies for a project, navigate to the `Basic Configuration` page, click the ``PROJECT DEPENDENCIES`` button and the `Dependencies` section will be shown. + +Click the ``ADD DEPENDENCIES`` button to select the dependent projects we need from the selection list, and then click the ``SAVE`` button to add and confirm. Once the dependencies are successfully added, continue the build process following the instructions in :ref:`build-a-simple-project` section. + +If the dependent libraries needed are not available from the selection list :ref:`add-new-project` and build it from the native sources using Webinizer first. + +For project `2048`, add ``[Local] - Ncurses`` from the selection list in the `Dependencies` section. It might take a while until the dependency is successfully added. + +.. image:: images/build-with-dependencies/add-deps-2048.png + +Configure build with dependencies +************************************* + +To configure the build with dependencies, the major difference is the :ref:`config-dependencies` section shown in the `Configuration` page. + +This section allows us to configure the build targets for each dependency and its dependencies, as well as an entry for each dependent project page by clicking the project name. As the target is selected for each dependency, we can observe that the ``Compiler flags`` and ``Linker flags`` from the dependencies' package configurations are automatically appended into the corresponding fields in :ref:`config-overall-env-variables`, which will be utilized by the main project to link all the dependencies together. + +.. image:: images/build-with-dependencies/overall-envs-2048.png + +For project `2048`, follow the steps below to build with dependencies. + +In the `Build steps` page, set the build target as ``static`` and accept the recommended build steps from Webinizer. + +In the `Configuration` page, tweak the configurations for build as below. + +* In the :ref:`config-options` section, set ``Disable`` to options ``Infinite main loop`` and ``Modularize JS output`` as we are building the demo to run in a worker thread, so the main thread blocking issue from infinite main loop doesn't exist and we can leave the JavaScript glue code to run in a global scope in a worker thread. + +* In the :ref:`config-dependencies` section, select the build target for dependency project ``Ncurses`` as ``static`` as we'd build the whole application using static linking. + +Navigate to the `Build` page and click the ``BUILD`` button to trigger the first build. Webinizer would build the dependency `Ncurses` first and then link it against the main project `2048`. After a while, a recipe appears, showing there are recipes generated for dependent projects. We can expand the recipe, follow the suggestion and click the ``GOTO`` link to navigate to a new tab for the dependent project. + +.. image:: images/build-with-dependencies/recipes-from-deps-2048.png + +A recipe on ``C++ exception`` issue is generated by Webinizer for the `Ncurses` project. Click the ``IGNORE`` button to dismiss it as the usage of C++ exception is detected from demos, which are not related to the core library. + +.. image:: images/build-with-dependencies/handle-recipes-from-deps-2048.png + +Then switch back to the **main project tab** and click the ``BUILD`` button for a second build. + +If everything goes well, we'll be notified a successful build from Webinizer, as well as the statistics of the WebAssembly modules generated from the build. + +.. image:: images/build-with-dependencies/build-results-2048.png + +To load the WebAssembly modules in the browser, we can run the ``run.sh`` script provided in the ``demos/2048`` folder. The demo is based on Web Worker, so we need to launch the browser with `SharedArrayBuffer` feature enabled at first: + +.. code-block:: bash + + path/to/your/chrome --enable-features=SharedArrayBuffer + +Then we can enjoy the game in the browser! + +.. image:: images/build-with-dependencies/run-2048-game.png diff --git a/documentation/build-a-simple-project.rst b/documentation/build-a-simple-project.rst new file mode 100644 index 0000000..d711918 --- /dev/null +++ b/documentation/build-a-simple-project.rst @@ -0,0 +1,262 @@ +.. _build-a-simple-project: + +Build a simple project +###################### + +This section will walk through the process of building a simple project using Webinizer. + +We'll use the demo project ``Tetris`` as an example, and when all the build processes are successfully completed, we can play this classical game in the browser. Let's get started! + +.. _get-started: + +Get started +*********** + +The `Get started` page is the entry for all Webinizer projects. We can either click the ``SELECT`` button on the project profile we'd like to choose from the demo projects, or the ``Add Project`` button to :ref:`add-new-project`. + +For the ``Tetris`` project, we can click the ``SELECT`` button from the project profile, and it'll navigate us to the :ref:`basic-configuration` page. + +.. image:: images/build-a-simple-project/get-started.png + +.. _add-new-project: + +Add a new Webinizer project +*************************** +Webinizer supports three ways of adding a new project. + +* **Upload project locally**. This method allow us to upload a project ``.zip`` package to Webinizer. +* **Clone from GitHub**. This method allows us to pull the project sources and setup locally by providing a git repository address. +* **Add from registry**. This method allows us to add a project from a Webinizer-supported registry by providing the package `name` and `version`. + +Click the ``Add Project`` button from `Get Started` page will navigate us to an empty :ref:`basic-configuration` page, where we can select the method we'd like to add a project from by clicking on different tabs. After all the required project information is provided, click the ``CREATE`` button to let Webinizer setup the project locally. + +.. image:: images/build-a-simple-project/add-project.png + +.. _basic-configuration: + +Basic configuration +******************* + +The `Basic configuration` page presents basic information about the project, including project `name`, `version`, `description` and `location`. If your project is a library, you should also click the checkbox at the bottom to inform Webinizer. + +``Tetris`` is an application project rather than a library, so we can leave the checkbox unchecked and click the ``BUILD STEPS ->`` button to navigate us to the `Build steps` page. + +.. image:: images/build-a-simple-project/basic-config.png + +.. _build-steps: + +Build steps +*********** + +The `Build steps` page describes how we can build a project step by step. + +First, set a build target for our build. Currenly Webinizer only supports two build targets: + +* ``static``: Select the static build target if you want to build your project with static linking. All dependent libraries will be built into Wasm archive files (.a), and then linked to the main project to get a standalone Wasm module with no external dependencies. +* ``shared``: Select the shared build target if you want to build your project with dynamic linking. All dependent libraries will be built into Wasm binary files (.wasm/.so) as side modules (using flag -sSIDE_MODULE), whose exports will be dynamically imported into the context of main project's Wasm module (using flag -sMAIN_MODULE) by JavaScript glue code. + +More details for static and dynamic linking are available `here +`_. + +Once the build target is set, Webinizer will prompt us with recommended build steps based on the ``native`` build systems detected in the project. Each build step has three properties: + +* **Build tools type**: specifies what's the build tool to use for a ``native`` build. Below are the five built-in build tools type Webinizer supports. We can extend the build tools type supported by refering to the section :ref:`develop-an-extension`. + + .. list-table:: Build tools type + :widths: 25 50 + :header-rows: 1 + + * - Build tools type + - Description + * - CMake + - Build the native project with a ``cmake`` command. + * - configure + - Build the native project using a ``configure`` script. + * - make + - Build the native project with a ``make`` command. + * - cc + - Build the native project with a ``gcc`` command. + * - native commands + - Run other native commands, such as ``cp``, ``ls``, etc. + +* **Arguments for build**: specifies the arguments appended to the build command. +* **Working directory for build**: specifies the working directory to execute the build command. + +We can either click the ``YES`` button to accept the recommendations from Webinizer, or click the ``NO`` and ``ADD STEP`` button to add the build steps one by one ourselves. Once the build steps are set, we can click ``MANAGE STEPS`` button to enable modifications on build steps properties and change the orders of build steps, and then click ``FINISH`` button to save the changes. + +.. image:: images/build-a-simple-project/build-steps-recommend.png + +For the ``Tetris`` project, set the build target as ``static``, and accept the recommended build steps from Webinizer. Click ``BUILD`` button and it'll navigate us to the `Build` page. + +.. _build-page: + +Build +***** + +The `Build` page is the entry to trigger the build process and presents the build recipes, logs and results. + +For the ``Tetris`` project, click the ``BUILD`` button to trigger a build. After a while, Webinizer will prompt us with three build recipes. + +Build recipes are applicable actions or suggestions provided by Webinizer if any errors occurred during the build process. Clicking on each recipe will show us the detailed contents of the recipe, including description of the issues detected and possible solutions provided by Webinizer. + +If the recipe has an ``APPLY RECIPE`` button at the upper-right corner, it means that this is an applicable action and click it will apply this recipe automatically and trigger a new build afterwards. If the ``IGNORE`` button is clicked, then this recipe will be dismissed and not shown again. Here we'd like to accept the recipe from Webinizer on the ``C++ exception`` issue detected, so we click the ``APPLY RECIPE`` button to proceed. + +.. image:: images/build-a-simple-project/build-recipes-apply-cpp-exception.png + +After a second build, only two recipes are presented. We'd also want to accept the recipe from Webinizer on the ``project dependent packages`` issue detected, so we click the ``APPLY RECIPE`` button to continue as well. + +After a third build, only one recipe is left, which is about the ``main loop issue``. Expanding the recipe will display the details and suggestions from Webinizer. This is not an auto-applicable action and requires manual efforts on modifying the source code. Webinizer provides a simple :ref:`edit-page` for viewing and editing the project files. Click the ``Edit`` button from the `sub-navigator` and we'll be directed to the `Editor` page. + +.. image:: images/build-a-simple-project/editor-save-file.png + +* Select the file ``src -> main.cpp`` from the ``Project Explorer`` sidebar and modify the code as below based on the suggestion. + + .. code-block:: cpp + + // main.cpp + #include "game.h" + #include + + int main() { + emscripten_set_main_loop( + []() { + static Game game; + game.loop(); + }, 0, 1); + return 0; + } + +* Click the ``SAVE`` button to save the changes. +* Click the ``Build`` button from the `sub-navigator` to route us back to the `Build` page to trigger another build. + +Note that we can always navigate across different pages using the `sub-navigator` to check the build steps, recipes, logs, configurations, and code editor. + +If everything goes well, we'll be notified of a successful build from Webinizer, as well as the statistics of the WebAssembly modules generated from the build. + +.. image:: images/build-a-simple-project/build-results-tetris.png + +To load the WebAssembly modules in the browser, we can run the ``run.sh`` script provided in the ``demos/tetris`` folder. + +.. image:: images/build-a-simple-project/run-tetris-game.png + +.. _build-configuration: + +Configuration +************* + +The `Configuration` page presents the available configurations from Webinizer to tweak the build. Below are the explanations for each configure section. + +.. _config-build-target: + +Build target +------------ + +Currenly Webinizer only supports two build targets: + +* ``static``: Select the static build target if you want to build your project with static linking. All dependent libraries will be built into Wasm archive files (.a), and then linked to the main project to get a standalone Wasm module with no external dependencies. +* ``shared``: Select the shared build target if you want to build your project with dynamic linking. All dependent libraries will be built into Wasm binary files (.wasm/.so) as side modules (using flag -sSIDE_MODULE), whose exports will be dynamically imported into the context of main project's Wasm module (using flag -sMAIN_MODULE) by JavaScript glue code. + +More details for static and dynamic linking are available `here +`_. + +.. _config-overall-env-variables: + +Overall env variables +--------------------- + +The `Overall environment variables` section specifies the overall compiler and linker flags for the build. The compiler and linker flags presented in this field are the aggregation of both the project :ref:`config-env-variables` and its :ref:`config-dependencies` (*if any*) flags. These fields are ``read-only`` and used for information display. + +.. _config-env-variables: + +Env variables +------------- + +The `Environment variables` section specifies compiler and linker flags of the project and related fields in tweaking these flags. + +.. list-table:: Environment variables + :widths: 20 40 40 + :header-rows: 1 + + * - Environment variables + - Description + - Note + * - Compiler flags + - The compiler flags used to build the project. + - Each argument is separated with a whitespace in Webinizer. If we want to add a single argument with whitespaces inside, please use **single quotation marks** (i.e., ``'-s USE_OPTION'``) to mark it as one. + * - Lnker flags + - The linker flags used to build the project. + - Each argument is separated with a whitespace in Webinizer. If we want to add a single argument with whitespaces inside, please use **single quotation marks** (i.e., ``'-s USE_OPTION'``) to mark it as one. + * - Exported functions + - The native function names we'd want to keep alive and available to be called from JavaScript. + - Each function should be separated with a comma. Modify this field will also update related arguments into ``Linker flags``. + * - Exported runtime methods + - The additional JavaScript runtime methods provided by Emscripten for better interaction with WebAssembly binary that we'd like to export to the JavaScript glue code. + - Each function should be separated with a comma. Modify this field will also update related arguments into ``Linker flags``. + * - Local data files + - The paths to the local files we'd like to preload to a ``.data`` file, which will be used by WebAssembly module at runtime. + - By defualt, Webinizer maps these files to the root of a virtual file system (``@/``). We can also map these files to different locations by setting the file path as ``/path/to/local/file@/path/in/virtual/FS``. Modify this field will also update related arguments into ``Linker flags``. + +.. _config-options: + +Options +------- + +The `Options` section specifies available options to adjust the compiler and linker flags of the project defind in the :ref:`config-env-variables` section. + +.. list-table:: Options + :widths: 25 60 15 + :header-rows: 1 + + * - Options + - Description + - Default value + * - Infinite main loop + - Enable this option if the application uses an infinite main loop (i.e., for rendering). + - Enable + * - Pthreads + - Enable this option if the application uses pthreads. Toggle this option will automatically update related arguments in the ``Compiler flags`` and ``Linker flags`` fields. + - Disable + * - C++ exception + - Enable this option if the application uses C++ exception catching and we'd also like to enable this functionality in WebAssembly. Toggle this option will automatically update related arguments in the ``Compiler flags`` and ``Linker flags`` fields. Note that enable this feature might bring slight performance overhead. + - Disable + * - SIMD support + - Enable this option if we need SIMD support for WebAssembly. Toggle this option will automatically update related arguments in the ``Compiler flags`` and ``Linker flags`` fields. + - Enable + * - Modularize JS output + - Enable this option if we want to emit the JavaScript glue code wrapped into a module instead of a global scope. Toggle this option will automatically update related arguments in the ``Linker flags`` field. + - Enable + +.. _config-dependencies: + +Dependencies +------------ + +The `Dependencies` section specifies build targets and presents corresponding package configurations from **all** dependent libraries. For each dependent library, we can change the build target here, but the corresponding configurations are ``read-only``. If we want to change these configurations, we can navigate to the project page of the dependent library by clicking the library name and conduct changes there. Below are the explanations for the package configuration fields of a dependent library. + +.. image:: images/build-a-simple-project/configs-deps.png + +.. _package-configs-explaination: + +.. list-table:: Package configurations + :widths: 25 50 + :header-rows: 1 + + * - Package configurations fields + - Description + * - Prefix + - The install prefix of the library. This field will be referenced as ``${prefix}`` by below ``Compiler flags`` and ``Linker flags`` fields to identify the path to search for related library files. + * - Compiler flags + - The compiler flags that will be acquired by the main project depending on this library to search for the header files (i.e., the ``-I`` options). + * - Linker flags + - The linker flags that will be acquired by the main project depending on this library to search for and identify the library files (i.e., the ``-L``, ``-l`` options). + +.. _edit-page: + +Editor +****** + +Webinizer provides a simple editor for viewing and editing the project files. It supports basic syntax highlighting of the file content, editing an existing file and creating a new file. + +To open a file, we can either select a file from the `Project Explore` sidebar, or click the button ``FILE -> OPEN FILE`` in the upper-right corner and enter a file location directly. + +To save a file, we can click the ``SAVE`` button to save any changes to the current opened file or the ``SAVE AS`` button with a given file location to create a new file. We can also click the button ``FILE -> NEW FILE`` in the upper-right corner to create an empty file in the editor and save the content with a specific location by clicking the ``SAVE AS`` button. diff --git a/documentation/conf.py b/documentation/conf.py new file mode 100644 index 0000000..51ef2a5 --- /dev/null +++ b/documentation/conf.py @@ -0,0 +1,58 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Webinizer' +copyright = '2023, Intel' +author = 'Intel' + +# The full version, including alpha/beta/rc tags +release = '0.5' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# The master toctree document. +master_doc = 'index' diff --git a/documentation/extensions/develop-an-extension.rst b/documentation/extensions/develop-an-extension.rst new file mode 100644 index 0000000..de30723 --- /dev/null +++ b/documentation/extensions/develop-an-extension.rst @@ -0,0 +1,421 @@ +.. _develop-an-extension: + +How to develop an Extension +########################### + +In this section, we will use a demo ``webinizer-extension-demo`` to demonstrate how to develop a Webinizer extension. The source code of this demo is placed in ``${webinizer_root}/extensions/webinizer-extension-demo``. + +Webinizer Extension Package directory +************************************* + +Below is the package directory of the ``webinizer-extension-demo``. + +.. code-block:: none + + /webinizer-extension-demo + /src + /actions + demo_action.ts + /advisors + demo_advisor.ts + /builders + demo_builder.ts + index.ts + /tests + /assets + /actions + /DemoAction + test (test file for DemoAction) + /advisors + /DemoAdvisor + /.webinizer (project config for DemoAdvisor) + config.json + /builders + /DemoBuilder (project config for DemoBuilder) + /.webinizer + config.json + demo_action_tests.ts + demo_advisor_tests.ts + demo_builder_tests.ts + index.ts + utils.ts + package.json + tsconfig.json + +The extension directory has the following properties; + +* ``package.json`` & ``tsconfig.ts`` are required to all extension packages. +* ``package.json`` contains the npm package config data and the metadata of the extension. +* ``tsconfig.json`` contains the typescript project config data of the extension. +* ``src`` folder contains the source code of extension, while ``tests`` folder contains the test code of the extension. +* ``index.ts`` under ``src`` folder contains code that loads all the components of the extension, and this file is required to all extensions. +* The folder structure under ``tests`` can be decided by the extension developer to make it convenient for testing. +* An extension can contain one or more actions, advisors and builders. They are placed in the corresponding folders, and they are optional. +* ``webinizer-extension-demo`` will extend Webinizer with a DemoAction, a DemoAdvisor and a DemoBuilder. + +Webinizer Extension Metadata +**************************** + +A Webinizer extension must contain a ``package.json`` which contains the package config data and the extension metadata. Below is an example of the metadata for ``webinizer-extension-demo``. + +.. code-block:: json + + { + "name": "webinizer-extension-demo", + "version": "0.0.1", + "description": "This is a demo extension for webinizer.", + "main": "dist/index.js", + "scripts": { + "build": "rimraf dist && tsc -p .", + "pretest": "npm run build", + "test": "cross-env TS_NODE_PROJECT='./tsconfig.json' mocha -r ts-node/register tests/index.ts" + }, + "author": "", + "license": "ISC", + "webinizerExtMeta": { + "status": "enable", + "actions": [ + { + "__type__": "DemoAction", + "desc": "this is demo action" + } + ], + "advisors": [ + { + "__type__": "DemoAdvisor", + "desc": "this is demo advisor", + "tags": [ + "demo" + ] + } + ], + "builders": [ + { + "__type__": "DemoBuilder", + "desc": "this is demo builder" + } + ] + } + } + +Besides ``name`` & ``description``, other metadata of extension is in the property ``webinizerExtMeta``. + +The details of each field of the metadata are as below: + +.. list-table:: Extension Metadata fields + :widths: 25 50 25 + :header-rows: 1 + + * - Element name + - Description + - Required or optional + * - name + - The name of the extension + - required + * - description + - The description of the extension + - required + * - webinizerExtMeta.status + - The status of the extension. Only when it is "enabled", the extension will be load by Webinizer. + - required + * - webinizerExtMeta.actions + - Array of action items. It can be absence or empty. + - optional + * - *[action]*.__type__ + - The type of an action. *[action]* means an action in the action arrary. If there is an action item in action array, the "__type__" element is required for this action item. + - required + * - *[action]*.desc + - The description of an action. If there is an action item in action array, the "description" element is required for this action item. + - required + * - webinizerExtMeta.advisors + - Array of advisor items. It can be absence or empty. + - optional + * - *[advisor]*.__type__ + - The type of an advisor. *[advisor]* means an advisor in advisor array. If there is an advisor item in advisor array, the "__type__" element is required for this advisor item. + - required + * - *[advisor]*.desc + - The description of an advisor. If there is an advisor item in advisor array, the "description" element is required for this advisor item. + - required + * - *[advisor]*.tags + - The tags of the advisor pipelines that the advisor item belongs to. Each advisor pipeline has a tag to represent this pipeline. An advisor should be added to advisor pipelines, otherwise it will be never used by Webinizer. An advisor can be added to multiple advisor pipelines, thus can have multiple tags. + - required + * - webinizerExtMeta.builders + - Array of builder items. It can be absence or empty. + - optional + * - *[builder]*.__type__ + - The type of a builder. *[builder]* means a builder in builder array. If there is a builder item in builder array, the "__type__" element is required for this builder item. + - required + * - *[builder]*.desc + - The description of a builder. If there is a builder item in builder array, the "description" element is required for this builder item. + - required + +tsconfig.json +************* + +A Webinizer extension must have a ``tsconfig.json`` which is the typescript project config file. Below is an example of the ``tsconfig.json`` for ``webinizer-extension-demo``. + +.. code-block:: json + + { + "extends": "../../tsconfig.base.json", + "include": ["src/**/*", "../../typings/webinizer.d.ts"], + "compilerOptions": { + "outDir": "./dist" + } + } + +Things to note; + +* It should be extended from the ``${webinizer_root}/tsconfig.base.json`` file. +* It must include file ``${webinizer_root}/typings/webinizer.d.ts`` in ``include`` field, which is the declaration file for :ref:`extension-api`. +* It should specify the ``tsc`` ``outDir`` as ``./dist``. + +index.ts +******** + +A Webinizer extension must have an ``index.ts`` in ``src`` folder which will help to load the actions, advisors, and builders of the extension. Below is the example code of ``index.ts`` of ``webinizer-extension-demo``. + +.. code-block:: typescript + + import * as webinizer from "webinizer"; + import path from "path"; + + const builderPath = path.join(__dirname, "builders"); + const advisorPath = path.join(__dirname, "advisors"); + const actionPath = path.join(__dirname, "actions"); + const moduleDirectories = [builderPath, advisorPath, actionPath]; + + export default async function load() { + for (const md of moduleDirectories) { + await webinizer.loadAllModulesInDirctory(md); + } + } + +Things to note; + +* Use ``import * as webinizer from "webinizer"`` to import the :ref:`extension-api`. +* ``index.ts`` must have an export default function ``load()`` to walk through all the module directories (builder, action, advisor and so on) and load all the modules under the directories. +* Section :ref:`extension-api` explains details on available API. + +Extend Webinizer with a new builder +*********************************** + +Below is the example code of a new builder DemoBuilder of ``webinizer-extension-demo``. + +.. code-block:: typescript + + import shlex from "shlex"; + import * as webinizer from "webinizer"; + + const log = webinizer.getLogger("DemoBuilderStep"); + + class DemoBuilderFactory implements webinizer.IBuilderFactory { + name = "demo_builder"; + desc = "Demo builder for webinizer extension demo"; + /* eslint-disable @typescript-eslint/no-unused-vars */ + detect(proj: webinizer.Project): DemoBuilder | null { + // TODO. implement detect here + return null; + } + + createDefault(proj: webinizer.Project, args?: string): DemoBuilder { + // use project root as default rootBuildFilePath + return new DemoBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: webinizer.Project, o: webinizer.IJsonObject, index: number): webinizer.IBuilder { + webinizer.checkJsonType(DemoBuilder.__type__, o); + return new DemoBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } + } + + class DemoBuilder implements webinizer.IBuilder { + static __type__ = "DemoBuilder"; + type = DemoBuilder.__type__; + desc = "demo builder"; + args: string[]; + id: number; + private _proj: webinizer.Project; + private _rootBuildFilePath: string; + + constructor(proj: webinizer.Project, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this.args = shlex.split(args); + this._rootBuildFilePath = rootBuildFilePath; + } + toJson(): webinizer.IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: webinizer.AdviseManager, errors: string) { + adviseManager.queueRequest(new webinizer.ErrorAdviseRequest(["demo"], errors, null, this.id)); + return; + } + + async build(adviseManager: webinizer.AdviseManager): Promise { + log.info("Start the build of demo builder..."); + const error = "demo builder error"; + await this._analyzeErrors(adviseManager, error); + return false; + } + } + + // loading + export default function onload() { + webinizer.ALL_BUILDER_FACTORIES.register(DemoBuilder.__type__, new DemoBuilderFactory()); + } + +Things to note; + +* DemoBuilder must implement interface ``IBuilder``, implement the functions ``build()`` and ``toJson()``. +* DemoBuilder must have a factory class ``DemoBuilderFactory`` which implements interface ``IBuilderFactory`` and implements the functions ``detect()`` and ``createDefault()``. +* It should have an export default function ``onload()`` which will register the ``DemoBuilderFactory`` with DemoBuilder's type at loading time. +* Section :ref:`extension-api` explains details on available API. + +Extending Webinizer with a new advisor +************************************** + +Below is the example code of a new advisor DemoAdvisor of ``webinizer-extension-demo``. + +.. code-block:: typescript + + import * as webinizer from "webinizer"; + + class DemoAdvisorFactory implements webinizer.IAdvisorFactory { + name = "DemoAdvisorFactory"; + desc = "Use this factory class to create DemoAdvisor instance"; + + createAdvisor(): webinizer.IAdvisor { + return new DemoAdvisor(); + } + } + + class DemoAdvisor implements webinizer.IAdvisor { + static __type__ = "DemoAdvisor"; + type = DemoAdvisor.__type__; + desc = "Demo advisor for Webinizer extension demo"; + + private _getSuggestionExample(): webinizer.SuggestionExample { + const before = `This is demo advisor for Webinizer Extension Demo`; + const after = `This is demo advisor for Webinizer Extension Demo!!!!!!`; + return new webinizer.SuggestionExample(before, after); + } + + private async _generateTestAdvise( + proj: webinizer.Project, + req: webinizer.ErrorAdviseRequest + ): Promise { + const action = new webinizer.ShowSuggestionAction( + "error", + `Demo Advisor for Webinizer Extension Demo.`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new webinizer.Recipe( + proj, + "Recipe for demo advisor of Webinizer extension demo", + this, + req, + action + ), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: webinizer.Project, + req: webinizer.IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof webinizer.ErrorAdviseRequest) { + const errorReq = req as webinizer.ErrorAdviseRequest; + if (errorReq.error.includes("demo builder error")) { + return this._generateTestAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } + } + + // loading + export default function onload() { + webinizer.registerAdvisorFactory(DemoAdvisor.__type__, new DemoAdvisorFactory()); + } + + +Things to note; + +* DemoAdvisor must implement interface ``IAdvisor``, and implement the function ``advise()``. +* DemoAdvisor must have a factory class ``DemoAdvisorFactory`` which implements interface ``IAdvisorFactory`` and implements the function ``createAdvisor()``. +* It should have an export default function ``onload()`` which will register the ``DemoAdvisorFactory`` with DemoAdvisor's type at loading time. +* Section :ref:`extension-api` explains details on available API. + +Extending Webinizer with a new action +************************************* + +Below is the example code of a new action DemoAction of ``webinizer-extension-demo`` + +.. code-block:: typescript + + import * as webinizer from "webinizer"; + + export class DemoAction implements webinizer.IAction { + static __type__ = "DemoAction"; + type: string = DemoAction.__type__; + desc: string; + + constructor(desc: string) { + this.desc = desc; + } + + async apply(): Promise { + return false; + } + toJson(): webinizer.IJsonObject { + return { + __type__: DemoAction.__type__, + desc: this.desc, + }; + } + + static fromJson(proj: webinizer.Project, o: webinizer.IJsonObject): DemoAction { + webinizer.checkJsonType(DemoAction.__type__, o); + return new DemoAction(o.desc as string); + } + } + + export default function onload() { + webinizer.ALL_ACTION_FACTORIES.register(DemoAction.__type__, DemoAction.fromJson); + } + +Things to note; + +* DemoAction must implement interface ``IAction``, and implement function ``apply()``. +* It should have an export default function ``onload()`` which will register the DemoAction with its type at loading time. +* Section :ref:`extension-api` explains details on available API. + +.. _extension-api: + +Webinizer Extension API +*********************** + +To view API details for Webinizer Extension, run ``npm run doc`` command from the ``${webinizer_root}`` directory and the API documentation will be generated under the ``docs`` folder. + +Launch the file ``${webinizer_root}/docs/index.html`` in the browser to view the API documentation interactively. diff --git a/documentation/extensions/index.rst b/documentation/extensions/index.rst new file mode 100644 index 0000000..b87597f --- /dev/null +++ b/documentation/extensions/index.rst @@ -0,0 +1,6 @@ +.. _extension-index: + +Extensions Overview +################### + +Webinizer provides an extension mechanism for developers to extend the capabilities of the tool. Using this mechanism, developers can develop new builders which adapt new build tools to build native applications, and new advisors and actions to handle more complex and varied types of the build issues/errors. \ No newline at end of file diff --git a/documentation/extensions/install-an-extension.rst b/documentation/extensions/install-an-extension.rst new file mode 100644 index 0000000..4c95958 --- /dev/null +++ b/documentation/extensions/install-an-extension.rst @@ -0,0 +1,42 @@ +.. _install-an-extension: + +How to install / uninstall an Extension +####################################### + +Currently we install and uninstall Webinizer extensions manually. + +To manually install an extension: + +* Extract the extension package into ``${webinizer_root}/extensions/${extension_name}``. +* Add the advisor instances into the ``${webinizer_root}/advisor_pipelines.json``. The user could decide which tags the advisor instances will be added to and its sequence position inside the tags. +* Make sure the ``status`` field of ``webinizerExtMeta`` property in ``package.json`` is set to ``enable``. +* Add project path to the ``references`` field from the ``tsconfig.all.json`` file in ``${webinizer_root}`` as: + +.. code-block:: json + + { + "files": [], + "include": [], + "references": [ + { "path": "./src" }, + { "path": "./extensions/webinizer-extension-demo" }, + { "path": "./extensions/${extension_name}" }, // <-- add it here + ] + } + +* At last, restart Webinizer to load the extensions. + +To manually uninstall an extension: + +* Remove the advisor instances from ``webinizer/advisor_pipelines.json``. +* Delete the ``webinizer/extensions/${extension_name}`` folder. +* Restart Webinizer to unload the extension. + +Webinizer Extension Load +************************ + +After an extension is installed and its status is set to ``enable``, you should restart Webinizer to load the new extensions. Currently, Webinizer does not support dynamic extension loading. + +Each extension will have an ``index.ts`` file which loads the extension in Webinizer. This file is used to register and load Builder Factories, Advisor Factories, Actions and other operations that should be done while loading this extension. + +The ``index.ts`` of extension will be loaded by Webinizer while it starts up if the extension is enabled. diff --git a/documentation/extensions/test-an-extension.rst b/documentation/extensions/test-an-extension.rst new file mode 100644 index 0000000..6c7ec99 --- /dev/null +++ b/documentation/extensions/test-an-extension.rst @@ -0,0 +1,105 @@ +.. _test-an-extension: + +How to test an Extension +######################## + +The developers of the extensions can develop test cases for their extensions. All the test related code should be placed in folder ``${extension_root}/tests``. + +How to develop a test for an Extension +*************************************** + +First, the extension tests should have an ``index.ts`` to initialize Webinizer and the extension for testing. + +An example code of an ``index.ts`` for testing ``webinizer-extension-demo`` is below. + +.. code-block:: typescript + + import * as webinizer from "webinizer"; + + async function initTests() { + try { + await webinizer.init(); + } catch (e) { + // stop running tests if initialization failed. + process.exit(); + } + } + + initTests(); + + import "./demo_action_tests"; + import "./demo_advisor_tests"; + import "./demo_builder_tests"; + +Things to note; + +* Use ``import * as webinizer from "webinizer"`` to import the :ref:`extension-api`. +* Function ``webinizer.init()`` would initialize Webinizer and all extensions. +* You can develop test cases in ``index.ts``, but it is recommended that to write test cases in other files and import them in ``index.ts``. For example, ``import ./demo_action_tests`` imports all the test cases in ``./demo_action_tests.ts``. + +Some example test cases in ``demo_action_tests.ts`` of the tests of ``webinizer-extension-demo`` are below; + +.. code-block:: typescript + + import * as webinizer from "webinizer"; + import { expect } from "chai"; + import path from "path"; + import { backupFolderSync, deleteFolder, renameFolder } from "./utils"; + import { DemoAction } from "../src/actions/demo_action"; + + const DEMO_ACTION_ASSETS_DIR = path.join(__dirname, "assets", "actions"); + + describe("action", () => { + before(() => { + //Backup the "assets/actions" folder + backupFolderSync(DEMO_ACTION_ASSETS_DIR, path.join(__dirname, "assets", ".actions")); + }); + + after(() => { + //Delete the older "assets/actions" and restore it from backup + deleteFolder(DEMO_ACTION_ASSETS_DIR); + renameFolder(path.join(__dirname, "assets", ".actions"), DEMO_ACTION_ASSETS_DIR); + }); + + it("DemoActionTest", async () => { + const action = new DemoAction("Demo Action Test"); + const result = await (action as webinizer.IAction).apply(); + + expect(result).to.equal(false); + }); + }); + +Things to note: + +* ``describe()`` defines a test category which can contain multiple test cases. +* ``it()`` defines a single test case. +* ``before()`` and ``after()`` are used to do some actions before and after running the test cases. In the example above, we backup the test assets files before running tests and restore them after running the tests. +* ``assets`` folder contains the files that the test cases would use, however other directories can be defined to achieve this. + + +How to run the test of an extension +*********************************** + +To run the test cases of an extension, first add a ``pretest`` field and a ``test`` field into the ``scripts`` property of ``package.json``. + +An example ``package.json`` of ``webinizer-extension-demo`` is below; + +.. code-block:: json + + { + //...skip some other fileds + "scripts": { + "build": "rimraf dist && tsc -p .", + "pretest": "npm run build", + "test": "cross-env TS_NODE_PROJECT='./tsconfig.json' mocha -r ts-node/register tests/index.ts" + } + //...skip some other fileds + } + +Tings to note; + +* Before running the test cases, you should go to ``${webinizer_root}`` and run command ``npm run build`` to build the Webinizer project. Every time you change the Webinizer code, you should run this command to recompile Webinizer project. +* After adding ``pretest`` & ``test`` into ``package.json``, you can go to ``${extension_root}`` and run ``npm run test`` or ``npm test`` to execute the test cases of the extension. +* The ``pretest`` command in ``package.json`` of ``webinizer-extension-demo`` is automatically exectued while running ``npm test``. +* To run the test cases of category ``action`` only, go to ``${extension_root}`` and run ``npm run test -- --grep "action"``. To run test cases of multiple category, use command ``npm run test -- --grep "(action|builder)"``. +* To run a single case, go to ``${extension_root}`` and run ``npm run test -- --grep "DemoActionTest"``. To run multiple cases, use command ``npm run test -- --grep "(DemoActionTest|DemoBuilderTest)"``. diff --git a/documentation/extensions/use-an-extension.rst b/documentation/extensions/use-an-extension.rst new file mode 100644 index 0000000..18d7faf --- /dev/null +++ b/documentation/extensions/use-an-extension.rst @@ -0,0 +1,46 @@ +.. _use-an-extension: + +How to use a Webinizer Extension +################################ + +Enabling and disabling extensions +********************************* + +There is a ``status`` field of ``webinizerExtMeta`` property in ``package.json`` which indicates if the extension is enabled or disabled. If extension is disabled, the components of the extension will not be loaded by Webinizer. Modify the ``status`` field of ``webinizerExtMeta`` property of ``package.json`` to enable or disable the extension. After modifying the ``status`` field, Webinizer should be restarted for the changes to take effect. + +Please note that it is not encouraged to modify the ``status`` from ``package.json`` directly. It is highly recommended that update the ``status`` of an extension from ``Settings`` page in the Webinizer Web UI. + +Advisor Pipeline +**************** + +If a Webinizer extension contains advisors, besides loading the advisor factories, it also needs to add the advisor to ``advisor_pipelines.json`` under the root directory of Webinizer. Otherwise, the advisor will be never used. + +Below is an example of adding TestAdvisor to ``advisor_pipelines.json``. + +.. code-block:: json + + { + "__type__": "AdvisorPipelineConfig", + "pipelines": [ + { + "tag": "default", + "advisors": [{ "__type__": "ErrorsNotHandledAdvisor" }] + }, + { + "tag": "demo", + "advisors": [{ "__type__": "DemoAdvisor" }] + }, + + { + "tag": "pipeline1", + "advisors": [{ "__type__": "advisor1" }, { "__type__": "advisor2" }, { "__type__": "advisor3" }] + } + ] + } + + +Things to note: + +* Each advisor pipeline has a tag. +* You can add an advisor to multiple tags/pipelines. In the example above, ``DemoAdvisor`` is added to pipeline ``demo``. +* In each pipeline's advisor list, the order of the advisors is very important. When a request is sent to a pipeline, the request will be passed to each advisor in this order. In the example above, if a request is sent to ``pipeline1``, ``advisor1`` will be the first advisor that try to handle this request, then ``advisor2``, ``advisor3`` until the request is handled, or the advisor list reaches its end. diff --git a/documentation/images/build-a-module/add-build-step-args-ncurses.png b/documentation/images/build-a-module/add-build-step-args-ncurses.png new file mode 100644 index 0000000..04d4950 Binary files /dev/null and b/documentation/images/build-a-module/add-build-step-args-ncurses.png differ diff --git a/documentation/images/build-a-module/add-build-step-ncurses.png b/documentation/images/build-a-module/add-build-step-ncurses.png new file mode 100644 index 0000000..1411db0 Binary files /dev/null and b/documentation/images/build-a-module/add-build-step-ncurses.png differ diff --git a/documentation/images/build-a-module/basic-configs-ncurses.png b/documentation/images/build-a-module/basic-configs-ncurses.png new file mode 100644 index 0000000..5760103 Binary files /dev/null and b/documentation/images/build-a-module/basic-configs-ncurses.png differ diff --git a/documentation/images/build-a-module/build-results-ncurses.png b/documentation/images/build-a-module/build-results-ncurses.png new file mode 100644 index 0000000..aea56fa Binary files /dev/null and b/documentation/images/build-a-module/build-results-ncurses.png differ diff --git a/documentation/images/build-a-module/ignore-recipes-ncurses.png b/documentation/images/build-a-module/ignore-recipes-ncurses.png new file mode 100644 index 0000000..f59aa53 Binary files /dev/null and b/documentation/images/build-a-module/ignore-recipes-ncurses.png differ diff --git a/documentation/images/build-a-module/pkg-configs-ncurses.png b/documentation/images/build-a-module/pkg-configs-ncurses.png new file mode 100644 index 0000000..9e9211c Binary files /dev/null and b/documentation/images/build-a-module/pkg-configs-ncurses.png differ diff --git a/documentation/images/build-a-simple-project/add-project.png b/documentation/images/build-a-simple-project/add-project.png new file mode 100644 index 0000000..93a441f Binary files /dev/null and b/documentation/images/build-a-simple-project/add-project.png differ diff --git a/documentation/images/build-a-simple-project/basic-config.png b/documentation/images/build-a-simple-project/basic-config.png new file mode 100644 index 0000000..a17f452 Binary files /dev/null and b/documentation/images/build-a-simple-project/basic-config.png differ diff --git a/documentation/images/build-a-simple-project/build-recipes-apply-cpp-exception.png b/documentation/images/build-a-simple-project/build-recipes-apply-cpp-exception.png new file mode 100644 index 0000000..1bc090b Binary files /dev/null and b/documentation/images/build-a-simple-project/build-recipes-apply-cpp-exception.png differ diff --git a/documentation/images/build-a-simple-project/build-results-tetris.png b/documentation/images/build-a-simple-project/build-results-tetris.png new file mode 100644 index 0000000..76a7dbd Binary files /dev/null and b/documentation/images/build-a-simple-project/build-results-tetris.png differ diff --git a/documentation/images/build-a-simple-project/build-steps-recommend.png b/documentation/images/build-a-simple-project/build-steps-recommend.png new file mode 100644 index 0000000..2fb6e06 Binary files /dev/null and b/documentation/images/build-a-simple-project/build-steps-recommend.png differ diff --git a/documentation/images/build-a-simple-project/configs-deps.png b/documentation/images/build-a-simple-project/configs-deps.png new file mode 100644 index 0000000..554f21c Binary files /dev/null and b/documentation/images/build-a-simple-project/configs-deps.png differ diff --git a/documentation/images/build-a-simple-project/editor-save-file.png b/documentation/images/build-a-simple-project/editor-save-file.png new file mode 100644 index 0000000..44d83dd Binary files /dev/null and b/documentation/images/build-a-simple-project/editor-save-file.png differ diff --git a/documentation/images/build-a-simple-project/get-started.png b/documentation/images/build-a-simple-project/get-started.png new file mode 100644 index 0000000..0c53b55 Binary files /dev/null and b/documentation/images/build-a-simple-project/get-started.png differ diff --git a/documentation/images/build-a-simple-project/run-tetris-game.png b/documentation/images/build-a-simple-project/run-tetris-game.png new file mode 100644 index 0000000..234e372 Binary files /dev/null and b/documentation/images/build-a-simple-project/run-tetris-game.png differ diff --git a/documentation/images/build-with-dependencies/add-deps-2048.png b/documentation/images/build-with-dependencies/add-deps-2048.png new file mode 100644 index 0000000..836a992 Binary files /dev/null and b/documentation/images/build-with-dependencies/add-deps-2048.png differ diff --git a/documentation/images/build-with-dependencies/build-results-2048.png b/documentation/images/build-with-dependencies/build-results-2048.png new file mode 100644 index 0000000..fa78423 Binary files /dev/null and b/documentation/images/build-with-dependencies/build-results-2048.png differ diff --git a/documentation/images/build-with-dependencies/handle-recipes-from-deps-2048.png b/documentation/images/build-with-dependencies/handle-recipes-from-deps-2048.png new file mode 100644 index 0000000..6e39ee3 Binary files /dev/null and b/documentation/images/build-with-dependencies/handle-recipes-from-deps-2048.png differ diff --git a/documentation/images/build-with-dependencies/overall-envs-2048.png b/documentation/images/build-with-dependencies/overall-envs-2048.png new file mode 100644 index 0000000..7701288 Binary files /dev/null and b/documentation/images/build-with-dependencies/overall-envs-2048.png differ diff --git a/documentation/images/build-with-dependencies/recipes-from-deps-2048.png b/documentation/images/build-with-dependencies/recipes-from-deps-2048.png new file mode 100644 index 0000000..b963ca4 Binary files /dev/null and b/documentation/images/build-with-dependencies/recipes-from-deps-2048.png differ diff --git a/documentation/images/build-with-dependencies/run-2048-game.png b/documentation/images/build-with-dependencies/run-2048-game.png new file mode 100644 index 0000000..af63558 Binary files /dev/null and b/documentation/images/build-with-dependencies/run-2048-game.png differ diff --git a/documentation/index.rst b/documentation/index.rst new file mode 100644 index 0000000..0f1da7a --- /dev/null +++ b/documentation/index.rst @@ -0,0 +1,27 @@ +.. _webinizer_docs: + +Welcome to Webinizer's documentation! +===================================== + +Webinizer is a tool to help you bring applications to the Web. The initial functionality accelerates the process of converting native code (such as C, C++) to build for Webassembly (WASM). It can be used to analyze your codebase and provide advice and in some cases automatically convert both build configuration and code to enable WASM builds. Webinizer can be extended with new build tools, languages, and code analyzers and advisors. In future Webinizer will check dependencies and search for WASM conversions in shared repositories (both public and private). Below is an overview of our documentation. + +.. toctree:: + :maxdepth: 1 + :caption: Using Webinizer + + installation-setup.rst + build-a-simple-project.rst + build-a-module.rst + build-a-project-with-dependencies.rst + +.. toctree:: + :maxdepth: 1 + :caption: Extending Webinizer + + extensions/index.rst + extensions/develop-an-extension.rst + extensions/use-an-extension.rst + extensions/install-an-extension.rst + extensions/test-an-extension.rst + + diff --git a/documentation/installation-setup.rst b/documentation/installation-setup.rst new file mode 100644 index 0000000..562d9b6 --- /dev/null +++ b/documentation/installation-setup.rst @@ -0,0 +1,119 @@ +.. _installation-setup: + +Installation and setup +###################### + +`Webinizer` provides scripts to build a `Docker` image that will setup everything for you and make `Webinizer` ready to use out of the box. + +Preparation +*********** + +To successfully build the docker image, the tools required are as follows; + +* `Docker Engine `_ or `Docker Desktop `_. +* `node` and `npm` +* `git` +* `curl` +* `patch` + +Setup +***** + +The main components in the Docker container are as follows; + +* `EMSDK` :sup:`3.1.31` +* `Node` :sup:`v16.17.1` +* `Webinizer` +* `Webinizer-webclient` + +These resource and toolchains will be auto installed and setup during the docker image building process. + +Configure docker +---------------- + +Proxy settings +============== + +If you have proxy settings in your system, please follow below guides to configure properly for docker. + +- `Configure proxy for docker daemon guide `_ +- `Configure proxy for docker client guide `_ + +Manage docker as non-root user +============================== + +- Add the docker group if it doesn't already exist: + + .. code-block:: bash + + sudo groupadd docker + +- Add the connected user `$USER` to the docker group. Change the user name to match your preferred user if you do not want to use your current user: + + .. code-block:: bash + + sudo gpasswd -a $USER docker + +- Either do a ``newgrp docker`` or log out/in to activate the changes to groups. + +Build +----- + +Clone the `webinizer-demo `_ repo. + +.. code-block:: bash + + $ git clone https://github.com/intel/webinizer-demo.git webinizer-demo + +``webinizer-demo/build/build.sh`` is the script to build docker image and pack necessary resources. Run the following command to start the building & packing process. + +.. code-block:: bash + + # Please make sure that `target_folder` doesn't exist before running the command + $ cd webinizer-demo/build + $ ./build.sh target_folder + + +Check targets +------------- + +``Webinizer:latest`` docker image and the following resources under ``target_folder/release`` directory will be generated once the build process successfully finishes. + +.. code-block:: bash + + target_folder/release + ├── README.md + ├── webinizer_demo/ # the directory containing the native projects to demo and start script + └── webinizer_img.tar # docker image archive file + + +List the docker images to check if ``Webinizer:Latest`` is generated successfully. + +.. code-block:: bash + + $ Docker images + REPOSITORY TAG IMAGE ID CREATED SIZE + webinizer latest be719be22d18 About a minute ago 2.47GB + +There is no further steps to be taken if ``Webinizer:latest`` docker image and release files are available locally. + +`If you want to deploy on another clean host from the previous generated release resources, then following command should be executed.` + +.. code-block:: bash + + # Load webinizer:latest docker image from archive file + $ docker loadNUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/extensions/node_modules/webinizer b/extensions/node_modules/webinizer new file mode 120000 index 0000000..a24d5e8 --- /dev/null +++ b/extensions/node_modules/webinizer @@ -0,0 +1 @@ +../../. \ No newline at end of file diff --git a/extensions/webinizer-extension-demo/package.json b/extensions/webinizer-extension-demo/package.json new file mode 100644 index 0000000..f3aa09f --- /dev/null +++ b/extensions/webinizer-extension-demo/package.json @@ -0,0 +1,37 @@ +{ + "name": "webinizer-extension-demo", + "version": "0.0.1", + "description": "This is a demo extension for webinizer.", + "main": "dist/index.js", + "scripts": { + "build": "rimraf dist && tsc -p .", + "pretest": "npm run build", + "test": "cross-env TS_NODE_PROJECT='./tsconfig.json' mocha -r ts-node/register tests/index.ts" + }, + "author": "", + "license": "ISC", + "webinizerExtMeta": { + "status": "enable", + "actions": [ + { + "__type__": "DemoAction", + "desc": "this is demo action" + } + ], + "advisors": [ + { + "__type__": "DemoAdvisor", + "desc": "this is demo advisor", + "tags": [ + "demo" + ] + } + ], + "builders": [ + { + "__type__": "DemoBuilder", + "desc": "this is demo builder" + } + ] + } +} diff --git a/extensions/webinizer-extension-demo/src/actions/demo_action.ts b/extensions/webinizer-extension-demo/src/actions/demo_action.ts new file mode 100644 index 0000000..afdcbd0 --- /dev/null +++ b/extensions/webinizer-extension-demo/src/actions/demo_action.ts @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; + +export class DemoAction implements webinizer.IAction { + static __type__ = "DemoAction"; + type: string = DemoAction.__type__; + desc: string; + + constructor(desc: string) { + this.desc = desc; + } + + async apply(): Promise { + return false; + } + toJson(): webinizer.IJsonObject { + return { + __type__: DemoAction.__type__, + desc: this.desc, + }; + } + + static fromJson(proj: webinizer.Project, o: webinizer.IJsonObject): DemoAction { + webinizer.checkJsonType(DemoAction.__type__, o); + return new DemoAction(o.desc as string); + } +} + +export default function onload() { + webinizer.ALL_ACTION_FACTORIES.register(DemoAction.__type__, DemoAction.fromJson); +} diff --git a/extensions/webinizer-extension-demo/src/advisors/demo_advisor.ts b/extensions/webinizer-extension-demo/src/advisors/demo_advisor.ts new file mode 100644 index 0000000..18fa91a --- /dev/null +++ b/extensions/webinizer-extension-demo/src/advisors/demo_advisor.ts @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; + +class DemoAdvisorFactory implements webinizer.IAdvisorFactory { + name = "DemoAdvisorFactory"; + desc = "Use this factory class to create DemoAdvisor instance"; + + createAdvisor(): webinizer.IAdvisor { + return new DemoAdvisor(); + } +} + +class DemoAdvisor implements webinizer.IAdvisor { + static __type__ = "DemoAdvisor"; + type = DemoAdvisor.__type__; + desc = "Demo advisor for Webinizer extension demo"; + + private _getSuggestionExample(): webinizer.SuggestionExample { + const before = `This is demo advisor for Webinizer Extension Demo`; + const after = `This is demo advisor for Webinizer Extension Demo!!!!!!`; + return new webinizer.SuggestionExample(before, after); + } + + private async _generateTestAdvise( + proj: webinizer.Project, + req: webinizer.ErrorAdviseRequest + ): Promise { + const action = new webinizer.ShowSuggestionAction( + "error", + `Demo Advisor for Webinizer Extension Demo.`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new webinizer.Recipe( + proj, + "Recipe for demo advisor of Webinizer extension demo", + this, + req, + action + ), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: webinizer.Project, + req: webinizer.IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof webinizer.ErrorAdviseRequest) { + const errorReq = req as webinizer.ErrorAdviseRequest; + if (errorReq.error.includes("demo builder error")) { + return this._generateTestAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + webinizer.registerAdvisorFactory(DemoAdvisor.__type__, new DemoAdvisorFactory()); +} diff --git a/extensions/webinizer-extension-demo/src/builders/demo_builder.ts b/extensions/webinizer-extension-demo/src/builders/demo_builder.ts new file mode 100644 index 0000000..1d9821b --- /dev/null +++ b/extensions/webinizer-extension-demo/src/builders/demo_builder.ts @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import shlex from "shlex"; +import * as webinizer from "webinizer"; + +const log = webinizer.getLogger("DemoBuilderStep"); + +class DemoBuilderFactory implements webinizer.IBuilderFactory { + name = "demo_builder"; + desc = "Demo builder for webinizer extension demo"; + /* eslint-disable @typescript-eslint/no-unused-vars */ + detect(proj: webinizer.Project): DemoBuilder | null { + // TODO. implement detect here + return null; + } + + createDefault(proj: webinizer.Project, args?: string): DemoBuilder { + // use project root as default rootBuildFilePath + return new DemoBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: webinizer.Project, o: webinizer.IJsonObject, index: number): webinizer.IBuilder { + webinizer.checkJsonType(DemoBuilder.__type__, o); + return new DemoBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class DemoBuilder implements webinizer.IBuilder { + static __type__ = "DemoBuilder"; + type = DemoBuilder.__type__; + desc = "demo builder"; + args: string[]; + id: number; + private _proj: webinizer.Project; + private _rootBuildFilePath: string; + + constructor(proj: webinizer.Project, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this.args = shlex.split(args); + this._rootBuildFilePath = rootBuildFilePath; + } + toJson(): webinizer.IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: webinizer.AdviseManager, errors: string) { + adviseManager.queueRequest(new webinizer.ErrorAdviseRequest(["demo"], errors, null, this.id)); + return; + } + + async build(adviseManager: webinizer.AdviseManager): Promise { + log.info("Start the build of demo builder..."); + const error = "demo builder error"; + await this._analyzeErrors(adviseManager, error); + return false; + } +} + +// loading +export default function onload() { + webinizer.ALL_BUILDER_FACTORIES.register(DemoBuilder.__type__, new DemoBuilderFactory()); +} diff --git a/extensions/webinizer-extension-demo/src/index.ts b/extensions/webinizer-extension-demo/src/index.ts new file mode 100644 index 0000000..56a8be7 --- /dev/null +++ b/extensions/webinizer-extension-demo/src/index.ts @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; +import path from "path"; + +const builderPath = path.join(__dirname, "builders"); +const advisorPath = path.join(__dirname, "advisors"); +const actionPath = path.join(__dirname, "actions"); +const moduleDirectories = [builderPath, advisorPath, actionPath]; + +export default async function load() { + for (const md of moduleDirectories) { + await webinizer.loadAllModulesInDirctory(md); + } +} diff --git a/extensions/webinizer-extension-demo/tests/assets/actions/DemoAction/test b/extensions/webinizer-extension-demo/tests/assets/actions/DemoAction/test new file mode 100644 index 0000000..3b45ebf --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/assets/actions/DemoAction/test @@ -0,0 +1 @@ +Test file for DemoAction testing. \ No newline at end of file diff --git a/extensions/webinizer-extension-demo/tests/assets/advisors/DemoAdvisor/.webinizer/config.json b/extensions/webinizer-extension-demo/tests/assets/advisors/DemoAdvisor/.webinizer/config.json new file mode 100644 index 0000000..892f8be --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/assets/advisors/DemoAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "DemoAdvisorTest", + "desc": "Test config file for DemoAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/extensions/webinizer-extension-demo/tests/assets/builders/DemoBuilder/.webinizer/config.json b/extensions/webinizer-extension-demo/tests/assets/builders/DemoBuilder/.webinizer/config.json new file mode 100644 index 0000000..bcab336 --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/assets/builders/DemoBuilder/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "DemoBuilderTest", + "desc": "Config file for DemoBuilder", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "builders": [ + { + "__type__": "DemoBuilder", + "id": 0, + "desc": "demo builder", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/extensions/webinizer-extension-demo/tests/demo_action_tests.ts b/extensions/webinizer-extension-demo/tests/demo_action_tests.ts new file mode 100644 index 0000000..5896236 --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/demo_action_tests.ts @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; +import { expect } from "chai"; +import path from "path"; +import { backupFolderSync, deleteFolder, renameFolder } from "./utils"; +import { DemoAction } from "../src/actions/demo_action"; + +const DEMO_ACTION_ASSETS_DIR = path.join(__dirname, "assets", "actions"); + +describe("action", () => { + before(() => { + //Backup the "assets/actions" folder + backupFolderSync(DEMO_ACTION_ASSETS_DIR, path.join(__dirname, "assets", ".actions")); + }); + + after(() => { + //Delete the older "assets/actions" and restore it from backup + deleteFolder(DEMO_ACTION_ASSETS_DIR); + renameFolder(path.join(__dirname, "assets", ".actions"), DEMO_ACTION_ASSETS_DIR); + }); + + it("DemoActionTest", async () => { + const action = new DemoAction("Demo Action Test"); + const result = await (action as webinizer.IAction).apply(); + + expect(result).to.equal(false); + }); +}); diff --git a/extensions/webinizer-extension-demo/tests/demo_advisor_tests.ts b/extensions/webinizer-extension-demo/tests/demo_advisor_tests.ts new file mode 100644 index 0000000..ba48480 --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/demo_advisor_tests.ts @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { + IAdviseRequest, + IAdviseResult, + IAdvisor, + advisorFactoryFromType, + Project as IProject, + Recipe, + ErrorAdviseRequest, +} from "webinizer"; +import { expect } from "chai"; +import path from "path"; +import { backupFolderSync, deleteFolder, renameFolder } from "./utils"; + +const DEMO_ADVISOR_ASSETS_DIR = path.join(__dirname, "assets", "advisors"); +async function advise(type: string, root: string, req: IAdviseRequest): Promise { + const advisor = advisorFactoryFromType(type)?.createAdvisor(); + const proj = new IProject(root); + expect(advisor).to.not.be.null; + return (advisor as IAdvisor).advise(proj, req, []); +} + +describe("advisor", () => { + before(() => { + //Backup the "assets/advisors" folder + backupFolderSync(DEMO_ADVISOR_ASSETS_DIR, path.join(__dirname, "assets", ".advisors")); + }); + + after(() => { + //Delete the older "assets/advisors" and restore it from backup + deleteFolder(DEMO_ADVISOR_ASSETS_DIR); + renameFolder(path.join(__dirname, "assets", ".advisors"), DEMO_ADVISOR_ASSETS_DIR); + }); + it("DemoAdvisorTest", async () => { + const errMsg = "demo builder error"; + const req = new ErrorAdviseRequest("demo", errMsg, null, 0); + const actionDesc = "Demo Advisor for Webinizer Extension Demo."; + const advisorType = "DemoAdvisor"; + const projRoot = path.join(DEMO_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); +}); diff --git a/extensions/webinizer-extension-demo/tests/demo_builder_tests.ts b/extensions/webinizer-extension-demo/tests/demo_builder_tests.ts new file mode 100644 index 0000000..2c6f56a --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/demo_builder_tests.ts @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; +import { expect } from "chai"; +import path from "path"; +import { backupFolderSync, deleteFolder, renameFolder } from "./utils"; + +const DEMO_BUILDER_ASSETS_DIR = path.join(__dirname, "assets", "builders"); + +async function build(root: string, target = "static"): Promise { + const proj = new webinizer.Project(root); + const builder = proj.config.getBuildConfigForTarget(target).builders?.[0]; + expect(builder).to.not.be.null; + return (builder as webinizer.IBuilder).build(new webinizer.AdviseManager(proj)); +} + +describe("builder", () => { + before(() => { + //Backup the "assets/builders" folder + backupFolderSync(DEMO_BUILDER_ASSETS_DIR, path.join(__dirname, "assets", ".builders")); + }); + + after(() => { + //Delete the older "assets/builders" and restore it from backup + deleteFolder(DEMO_BUILDER_ASSETS_DIR); + renameFolder(path.join(__dirname, "assets", ".builders"), DEMO_BUILDER_ASSETS_DIR); + }); + it("DemoBuilderTest", async () => { + const projRoot = path.join(DEMO_BUILDER_ASSETS_DIR, "DemoBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(false); + }); +}); diff --git a/extensions/webinizer-extension-demo/tests/index.ts b/extensions/webinizer-extension-demo/tests/index.ts new file mode 100644 index 0000000..008aa31 --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/index.ts @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as webinizer from "webinizer"; + +async function initTests() { + try { + await webinizer.init(); + } catch (e) { + // stop running tests if initialization failed. + process.exit(); + } +} + +initTests(); + +import "./demo_action_tests"; +import "./demo_advisor_tests"; +import "./demo_builder_tests"; diff --git a/extensions/webinizer-extension-demo/tests/utils.ts b/extensions/webinizer-extension-demo/tests/utils.ts new file mode 100644 index 0000000..28ec3a2 --- /dev/null +++ b/extensions/webinizer-extension-demo/tests/utils.ts @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import fs from "graceful-fs"; + +/** + * Backup a folder + * @param srcDir The folder directory to be backuped + * @param destDir The destination directory + */ +export function backupFolderSync(srcDir: string, destDir: string) { + try { + fs.cpSync(srcDir, destDir, { recursive: true }); + } catch (error) { + throw new Error(`An error occurred while copying folder '${srcDir}':\n${error}`); + } +} + +/** + * Delete a folder + * @param dir The folder directory to be deleted + */ +export function deleteFolder(dir: string) { + try { + fs.rmSync(dir, { recursive: true }); + } catch (error) { + throw new Error(`An error occurred while deleting folder '${dir}':\n${error}`); + } +} + +/** + * Rename a folder + * @param oldPath The old path of the folder + * @param newPath The new path of the folder + */ +export function renameFolder(oldPath: string, newPath: string) { + try { + fs.renameSync(oldPath, newPath); + } catch (error) { + throw new Error(`An error occurred while moving folder '${oldPath}':\n${error}`); + } +} diff --git a/extensions/webinizer-extension-demo/tsconfig.json b/extensions/webinizer-extension-demo/tsconfig.json new file mode 100644 index 0000000..1c0a6de --- /dev/null +++ b/extensions/webinizer-extension-demo/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*", "../../typings/webinizer.d.ts"], + "compilerOptions": { + "outDir": "./dist" + } +} diff --git a/files/SDL2_API.txt b/files/SDL2_API.txt new file mode 100644 index 0000000..02e8c50 --- /dev/null +++ b/files/SDL2_API.txt @@ -0,0 +1,778 @@ +SDL_acos +SDL_AddEventWatch +SDL_AddHintCallback +SDL_AddTimer +SDL_AllocFormat +SDL_AllocPalette +SDL_AllocRW +SDL_AndroidBackButton +SDL_AndroidGetActivity +SDL_AndroidGetExternalStoragePath +SDL_AndroidGetExternalStorageState +SDL_AndroidGetInternalStoragePath +SDL_AndroidGetJNIEnv +SDL_AndroidRequestPermission +SDL_AndroidSendMessage +SDL_AndroidShowToast +SDL_assert +SDL_assert_paranoid +SDL_assert_release +SDL_AtomicAdd +SDL_AtomicCAS +SDL_AtomicCASPtr +SDL_AtomicDecRef +SDL_AtomicGet +SDL_AtomicGetPtr +SDL_AtomicIncRef +SDL_AtomicLock +SDL_AtomicSet +SDL_AtomicSetPtr +SDL_AtomicTryLock +SDL_AtomicUnlock +SDL_AudioInit +SDL_AudioQuit +SDL_AudioStreamAvailable +SDL_AudioStreamClear +SDL_AudioStreamFlush +SDL_AudioStreamGet +SDL_AudioStreamPut +SDL_BlitScaled +SDL_BlitSurface +SDL_BuildAudioCVT +SDL_CalculateGammaRamp +SDL_CaptureMouse +SDL_ClearComposition +SDL_ClearError +SDL_ClearHints +SDL_ClearQueuedAudio +SDL_CloseAudio +SDL_CloseAudioDevice +SDL_COMPILEDVERSION +SDL_CompilerBarrier +SDL_ComposeCustomBlendMode +SDL_CondBroadcast +SDL_CondSignal +SDL_CondWait +SDL_CondWaitTimeout +SDL_ConvertAudio +SDL_ConvertPixels +SDL_ConvertSurface +SDL_ConvertSurfaceFormat +SDL_CreateColorCursor +SDL_CreateCond +SDL_CreateCursor +SDL_CreateMutex +SDL_CreateRenderer +SDL_CreateRGBSurface +SDL_CreateRGBSurfaceFrom +SDL_CreateRGBSurfaceWithFormat +SDL_CreateRGBSurfaceWithFormatFrom +SDL_CreateSemaphore +SDL_CreateShapedWindow +SDL_CreateSoftwareRenderer +SDL_CreateSystemCursor +SDL_CreateTexture +SDL_CreateTextureFromSurface +SDL_CreateThread +SDL_CreateThreadWithStackSize +SDL_CreateWindow +SDL_CreateWindowAndRenderer +SDL_CreateWindowFrom +SDL_Delay +SDL_DelEventWatch +SDL_DelHintCallback +SDL_DequeueAudio +SDL_DestroyCond +SDL_DestroyMutex +SDL_DestroyRenderer +SDL_DestroySemaphore +SDL_DestroyTexture +SDL_DestroyWindow +SDL_DetachThread +SDL_Direct3D9GetAdapterIndex +SDL_DisableScreenSaver +SDL_DXGIGetOutputInfo +SDL_EnableScreenSaver +SDL_EncloseFPoints +SDL_EnclosePoints +SDL_EventFilter +SDL_EventState +SDL_FillRect +SDL_FillRects +SDL_FilterEvents +SDL_FlashWindow +SDL_FlushEvent +SDL_FlushEvents +SDL_FRectEmpty +SDL_FRectEquals +SDL_FreeAudioStream +SDL_FreeCursor +SDL_FreeFormat +SDL_FreePalette +SDL_FreeRW +SDL_FreeSurface +SDL_FreeWAV +SDL_GameControllerAddMapping +SDL_GameControllerAddMappingsFromFile +SDL_GameControllerAddMappingsFromRW +SDL_GameControllerClose +SDL_GameControllerEventState +SDL_GameControllerFromInstanceID +SDL_GameControllerFromPlayerIndex +SDL_GameControllerGetAppleSFSymbolsNameForAxis +SDL_GameControllerGetAppleSFSymbolsNameForButton +SDL_GameControllerGetAttached +SDL_GameControllerGetAxis +SDL_GameControllerGetAxisFromString +SDL_GameControllerGetBindForAxis +SDL_GameControllerGetBindForButton +SDL_GameControllerGetButton +SDL_GameControllerGetButtonFromString +SDL_GameControllerGetFirmwareVersion +SDL_GameControllerGetJoystick +SDL_GameControllerGetNumTouchpadFingers +SDL_GameControllerGetNumTouchpads +SDL_GameControllerGetPlayerIndex +SDL_GameControllerGetProduct +SDL_GameControllerGetProductVersion +SDL_GameControllerGetSensorData +SDL_GameControllerGetSensorDataRate +SDL_GameControllerGetSerial +SDL_GameControllerGetStringForAxis +SDL_GameControllerGetStringForButton +SDL_GameControllerGetTouchpadFinger +SDL_GameControllerGetType +SDL_GameControllerGetVendor +SDL_GameControllerHasAxis +SDL_GameControllerHasButton +SDL_GameControllerHasLED +SDL_GameControllerHasRumble +SDL_GameControllerHasRumbleTriggers +SDL_GameControllerHasSensor +SDL_GameControllerIsSensorEnabled +SDL_GameControllerMapping +SDL_GameControllerMappingForDeviceIndex +SDL_GameControllerMappingForGUID +SDL_GameControllerMappingForIndex +SDL_GameControllerName +SDL_GameControllerNameForIndex +SDL_GameControllerNumMappings +SDL_GameControllerOpen +SDL_GameControllerPath +SDL_GameControllerPathForIndex +SDL_GameControllerRumble +SDL_GameControllerRumbleTriggers +SDL_GameControllerSendEffect +SDL_GameControllerSetLED +SDL_GameControllerSetPlayerIndex +SDL_GameControllerSetSensorEnabled +SDL_GameControllerTypeForIndex +SDL_GameControllerUpdate +SDL_GDKGetTaskQueue +SDL_GDKRunApp +SDL_GetAndroidSDKVersion +SDL_GetAssertionHandler +SDL_GetAssertionReport +SDL_GetAudioDeviceName +SDL_GetAudioDeviceSpec +SDL_GetAudioDeviceStatus +SDL_GetAudioDriver +SDL_GetAudioStatus +SDL_GetBasePath +SDL_GetClipboardText +SDL_GetClipRect +SDL_GetClosestDisplayMode +SDL_GetColorKey +SDL_GetCPUCacheLineSize +SDL_GetCPUCount +SDL_GetCurrentAudioDriver +SDL_GetCurrentDisplayMode +SDL_GetCurrentVideoDriver +SDL_GetCursor +SDL_GetDefaultAssertionHandler +SDL_GetDefaultAudioInfo +SDL_GetDefaultCursor +SDL_GetDesktopDisplayMode +SDL_GetDisplayBounds +SDL_GetDisplayDPI +SDL_GetDisplayMode +SDL_GetDisplayName +SDL_GetDisplayOrientation +SDL_GetDisplayUsableBounds +SDL_GetError +SDL_GetErrorMsg +SDL_GetEventFilter +SDL_GetEventState +SDL_GetGlobalMouseState +SDL_GetGrabbedWindow +SDL_GetHint +SDL_GetHintBoolean +SDL_GetInputDeviceName +SDL_GetJoystickGUIDInfo +SDL_GetKeyboardFocus +SDL_GetKeyboardState +SDL_GetKeyFromName +SDL_GetKeyFromScancode +SDL_GetKeyName +SDL_GetMemoryFunctions +SDL_GetModState +SDL_GetMouseFocus +SDL_GetMouseState +SDL_GetNumAllocations +SDL_GetNumAudioDevices +SDL_GetNumAudioDrivers +SDL_GetNumDisplayModes +SDL_GetNumInputDevices +SDL_GetNumRenderDrivers +SDL_GetNumTouchDevices +SDL_GetNumTouchFingers +SDL_GetNumVideoDisplays +SDL_GetNumVideoDrivers +SDL_GetOriginalMemoryFunctions +SDL_GetPerformanceCounter +SDL_GetPerformanceFrequency +SDL_GetPixelFormatName +SDL_GetPlatform +SDL_GetPointDisplayIndex +SDL_GetPowerInfo +SDL_GetPreferredLocales +SDL_GetPrefPath +SDL_GetPrimarySelectionText +SDL_GetQueuedAudioSize +SDL_GetRectDisplayIndex +SDL_GetRelativeMouseMode +SDL_GetRelativeMouseState +SDL_GetRenderDrawBlendMode +SDL_GetRenderDrawColor +SDL_GetRenderDriverInfo +SDL_GetRenderer +SDL_GetRendererInfo +SDL_GetRendererOutputSize +SDL_GetRenderTarget +SDL_GetRevision +SDL_GetRevisionNumber +SDL_GetRGB +SDL_GetRGBA +SDL_GetScancodeFromKey +SDL_GetScancodeFromName +SDL_GetScancodeName +SDL_GetShapedWindowMode +SDL_GetSurfaceAlphaMod +SDL_GetSurfaceBlendMode +SDL_GetSurfaceColorMod +SDL_GetSystemRAM +SDL_GetTextureAlphaMod +SDL_GetTextureBlendMode +SDL_GetTextureColorMod +SDL_GetTextureScaleMode +SDL_GetTextureUserData +SDL_GetThreadID +SDL_GetThreadName +SDL_GetTicks +SDL_GetTicks64 +SDL_GetTouchDevice +SDL_GetTouchDeviceType +SDL_GetTouchFinger +SDL_GetTouchName +SDL_GetVersion +SDL_GetVideoDriver +SDL_GetWindowBordersSize +SDL_GetWindowBrightness +SDL_GetWindowData +SDL_GetWindowDisplayIndex +SDL_GetWindowDisplayMode +SDL_GetWindowFlags +SDL_GetWindowFromID +SDL_GetWindowGammaRamp +SDL_GetWindowGrab +SDL_GetWindowICCProfile +SDL_GetWindowID +SDL_GetWindowKeyboardGrab +SDL_GetWindowMaximumSize +SDL_GetWindowMinimumSize +SDL_GetWindowMouseGrab +SDL_GetWindowMouseRect +SDL_GetWindowOpacity +SDL_GetWindowPixelFormat +SDL_GetWindowPosition +SDL_GetWindowSize +SDL_GetWindowSizeInPixels +SDL_GetWindowSurface +SDL_GetWindowTitle +SDL_GetWindowWMInfo +SDL_GetYUVConversionMode +SDL_GetYUVConversionModeForResolution +SDL_GL_BindTexture +SDL_GL_CreateContext +SDL_GL_DeleteContext +SDL_GL_ExtensionSupported +SDL_GL_GetAttribute +SDL_GL_GetCurrentContext +SDL_GL_GetCurrentWindow +SDL_GL_GetDrawableSize +SDL_GL_GetProcAddress +SDL_GL_GetSwapInterval +SDL_GL_LoadLibrary +SDL_GL_MakeCurrent +SDL_GL_ResetAttributes +SDL_GL_SetAttribute +SDL_GL_SetSwapInterval +SDL_GL_SwapWindow +SDL_GL_UnbindTexture +SDL_GL_UnloadLibrary +SDL_GUIDFromString +SDL_GUIDToString +SDL_HapticClose +SDL_HapticDestroyEffect +SDL_HapticEffectSupported +SDL_HapticGetEffectStatus +SDL_HapticIndex +SDL_HapticName +SDL_HapticNewEffect +SDL_HapticNumAxes +SDL_HapticNumEffects +SDL_HapticNumEffectsPlaying +SDL_HapticOpen +SDL_HapticOpened +SDL_HapticOpenFromJoystick +SDL_HapticOpenFromMouse +SDL_HapticPause +SDL_HapticQuery +SDL_HapticRumbleInit +SDL_HapticRumblePlay +SDL_HapticRumbleStop +SDL_HapticRumbleSupported +SDL_HapticRunEffect +SDL_HapticSetAutocenter +SDL_HapticSetGain +SDL_HapticStopAll +SDL_HapticStopEffect +SDL_HapticUnpause +SDL_HapticUpdateEffect +SDL_Has3DNow +SDL_HasAltiVec +SDL_HasARMSIMD +SDL_HasAVX +SDL_HasAVX2 +SDL_HasAVX512F +SDL_HasClipboardText +SDL_HasColorKey +SDL_HasEvent +SDL_HasEvents +SDL_HasIntersection +SDL_HasIntersectionF +SDL_HasLASX +SDL_HasLSX +SDL_HasMMX +SDL_HasNEON +SDL_HasPrimarySelectionText +SDL_HasRDTSC +SDL_HasScreenKeyboardSupport +SDL_HasSSE +SDL_HasSSE2 +SDL_HasSSE3 +SDL_HasSSE41 +SDL_HasSSE42 +SDL_HasSurfaceRLE +SDL_hid_ble_scan +SDL_hid_close +SDL_hid_device_change_count +SDL_hid_enumerate +SDL_hid_exit +SDL_hid_free_enumeration +SDL_hid_get_feature_report +SDL_hid_get_indexed_string +SDL_hid_get_manufacturer_string +SDL_hid_get_product_string +SDL_hid_get_serial_number_string +SDL_hid_init +SDL_hid_open +SDL_hid_open_path +SDL_hid_read +SDL_hid_read_timeout +SDL_hid_send_feature_report +SDL_hid_set_nonblocking +SDL_hid_write +SDL_HideWindow +SDL_iconv_string +SDL_Init +SDL_InitSubSystem +SDL_IntersectFRect +SDL_IntersectFRectAndLine +SDL_IntersectRect +SDL_IntersectRectAndLine +SDL_iPhoneSetAnimationCallback +SDL_iPhoneSetEventPump +SDL_IsAndroidTV +SDL_IsChromebook +SDL_IsDeviceDisconnected +SDL_IsDeXMode +SDL_IsGameController +SDL_IsScreenKeyboardShown +SDL_IsScreenSaverEnabled +SDL_IsShapedWindow +SDL_IsTablet +SDL_IsTextInputActive +SDL_IsTextInputShown +SDL_JoystickAttachVirtual +SDL_JoystickAttachVirtualEx +SDL_JoystickClose +SDL_JoystickCurrentPowerLevel +SDL_JoystickDetachVirtual +SDL_JoystickEventState +SDL_JoystickFromInstanceID +SDL_JoystickFromPlayerIndex +SDL_JoystickGetAttached +SDL_JoystickGetAxis +SDL_JoystickGetAxisInitialState +SDL_JoystickGetBall +SDL_JoystickGetButton +SDL_JoystickGetDeviceGUID +SDL_JoystickGetDeviceInstanceID +SDL_JoystickGetDevicePlayerIndex +SDL_JoystickGetDeviceProduct +SDL_JoystickGetDeviceProductVersion +SDL_JoystickGetDeviceType +SDL_JoystickGetDeviceVendor +SDL_JoystickGetFirmwareVersion +SDL_JoystickGetGUID +SDL_JoystickGetGUIDFromString +SDL_JoystickGetGUIDString +SDL_JoystickGetHat +SDL_JoystickGetPlayerIndex +SDL_JoystickGetProduct +SDL_JoystickGetProductVersion +SDL_JoystickGetSerial +SDL_JoystickGetType +SDL_JoystickGetVendor +SDL_JoystickHasLED +SDL_JoystickHasRumble +SDL_JoystickHasRumbleTriggers +SDL_JoystickInstanceID +SDL_JoystickIsHaptic +SDL_JoystickIsVirtual +SDL_JoystickName +SDL_JoystickNameForIndex +SDL_JoystickNumAxes +SDL_JoystickNumBalls +SDL_JoystickNumButtons +SDL_JoystickNumHats +SDL_JoystickOpen +SDL_JoystickPath +SDL_JoystickPathForIndex +SDL_JoystickRumble +SDL_JoystickRumbleTriggers +SDL_JoystickSendEffect +SDL_JoystickSetLED +SDL_JoystickSetPlayerIndex +SDL_JoystickSetVirtualAxis +SDL_JoystickSetVirtualButton +SDL_JoystickSetVirtualHat +SDL_JoystickUpdate +SDL_LinuxSetThreadPriority +SDL_LinuxSetThreadPriorityAndPolicy +SDL_LoadBMP +SDL_LoadBMP_RW +SDL_LoadDollarTemplates +SDL_LoadFile +SDL_LoadFile_RW +SDL_LoadFunction +SDL_LoadObject +SDL_LoadWAV +SDL_LoadWAV_RW +SDL_LockAudio +SDL_LockAudioDevice +SDL_LockJoysticks +SDL_LockMutex +SDL_LockSensors +SDL_LockSurface +SDL_LockTexture +SDL_LockTextureToSurface +SDL_Log +SDL_LogCritical +SDL_LogDebug +SDL_LogError +SDL_LogGetOutputFunction +SDL_LogGetPriority +SDL_LogInfo +SDL_LogMessage +SDL_LogMessageV +SDL_LogResetPriorities +SDL_LogSetAllPriority +SDL_LogSetOutputFunction +SDL_LogSetPriority +SDL_LogVerbose +SDL_LogWarn +SDL_LowerBlit +SDL_LowerBlitScaled +SDL_MapRGB +SDL_MapRGBA +SDL_MasksToPixelFormatEnum +SDL_MaximizeWindow +SDL_MemoryBarrierReleaseFunction +SDL_Metal_CreateView +SDL_Metal_DestroyView +SDL_Metal_GetDrawableSize +SDL_Metal_GetLayer +SDL_MinimizeWindow +SDL_MixAudio +SDL_MixAudioFormat +SDL_MostSignificantBitIndex32 +SDL_MouseIsHaptic +SDL_MUSTLOCK +SDL_NewAudioStream +SDL_NumHaptics +SDL_NumJoysticks +SDL_NumSensors +SDL_OpenAudio +SDL_OpenAudioDevice +SDL_OpenURL +SDL_PauseAudio +SDL_PauseAudioDevice +SDL_PeepEvents +SDL_PixelFormatEnumToMasks +SDL_PointInFRect +SDL_PointInRect +SDL_PollEvent +SDL_PremultiplyAlpha +SDL_PumpEvents +SDL_PushEvent +SDL_QueryTexture +SDL_QueueAudio +SDL_Quit +SDL_QuitRequested +SDL_QuitSubSystem +SDL_RaiseWindow +SDL_ReadBE16 +SDL_ReadBE32 +SDL_ReadBE64 +SDL_ReadLE16 +SDL_ReadLE32 +SDL_ReadLE64 +SDL_ReadU8 +SDL_RecordGesture +SDL_RectEmpty +SDL_RectEquals +SDL_RedetectInputDevices +SDL_RegisterApp +SDL_RegisterEvents +SDL_RemoveTimer +SDL_RenderClear +SDL_RenderCopy +SDL_RenderCopyEx +SDL_RenderCopyExF +SDL_RenderCopyF +SDL_RenderDrawLine +SDL_RenderDrawLineF +SDL_RenderDrawLines +SDL_RenderDrawLinesF +SDL_RenderDrawPoint +SDL_RenderDrawPointF +SDL_RenderDrawPoints +SDL_RenderDrawPointsF +SDL_RenderDrawRect +SDL_RenderDrawRectF +SDL_RenderDrawRects +SDL_RenderDrawRectsF +SDL_RenderFillRect +SDL_RenderFillRectF +SDL_RenderFillRects +SDL_RenderFillRectsF +SDL_RenderFlush +SDL_RenderGeometry +SDL_RenderGeometryRaw +SDL_RenderGetClipRect +SDL_RenderGetD3D11Device +SDL_RenderGetD3D12Device +SDL_RenderGetD3D9Device +SDL_RenderGetIntegerScale +SDL_RenderGetLogicalSize +SDL_RenderGetMetalCommandEncoder +SDL_RenderGetMetalLayer +SDL_RenderGetScale +SDL_RenderGetViewport +SDL_RenderGetWindow +SDL_RenderIsClipEnabled +SDL_RenderLogicalToWindow +SDL_RenderPresent +SDL_RenderReadPixels +SDL_RenderSetClipRect +SDL_RenderSetIntegerScale +SDL_RenderSetLogicalSize +SDL_RenderSetScale +SDL_RenderSetViewport +SDL_RenderSetVSync +SDL_RenderTargetSupported +SDL_RenderWindowToLogical +SDL_ResetAssertionReport +SDL_ResetHint +SDL_ResetKeyboard +SDL_RestoreWindow +SDL_REVISION +SDL_RWclose +SDL_RWFromConstMem +SDL_RWFromFile +SDL_RWFromFP +SDL_RWFromMem +SDL_RWread +SDL_RWseek +SDL_RWsize +SDL_RWtell +SDL_RWwrite +SDL_SaveAllDollarTemplates +SDL_SaveBMP +SDL_SaveBMP_RW +SDL_SaveDollarTemplate +SDL_SemPost +SDL_SemTryWait +SDL_SemValue +SDL_SemWait +SDL_SemWaitTimeout +SDL_SensorClose +SDL_SensorFromInstanceID +SDL_SensorGetData +SDL_SensorGetDeviceInstanceID +SDL_SensorGetDeviceName +SDL_SensorGetDeviceNonPortableType +SDL_SensorGetDeviceType +SDL_SensorGetInstanceID +SDL_SensorGetName +SDL_SensorGetNonPortableType +SDL_SensorGetType +SDL_SensorOpen +SDL_SensorUpdate +SDL_SetAssertionHandler +SDL_SetClipboardText +SDL_SetClipRect +SDL_SetColorKey +SDL_SetCursor +SDL_SetError +SDL_SetEventFilter +SDL_SetHint +SDL_SetHintWithPriority +SDL_SetMainReady +SDL_SetMemoryFunctions +SDL_SetModState +SDL_SetPaletteColors +SDL_SetPixelFormatPalette +SDL_SetPrimarySelectionText +SDL_SetRelativeMouseMode +SDL_SetRenderDrawBlendMode +SDL_SetRenderDrawColor +SDL_SetRenderTarget +SDL_SetSurfaceAlphaMod +SDL_SetSurfaceBlendMode +SDL_SetSurfaceColorMod +SDL_SetSurfacePalette +SDL_SetSurfaceRLE +SDL_SetTextInputRect +SDL_SetTextureAlphaMod +SDL_SetTextureBlendMode +SDL_SetTextureColorMod +SDL_SetTextureScaleMode +SDL_SetTextureUserData +SDL_SetThreadPriority +SDL_SetWindowAlwaysOnTop +SDL_SetWindowBordered +SDL_SetWindowBrightness +SDL_SetWindowData +SDL_SetWindowDisplayMode +SDL_SetWindowFullscreen +SDL_SetWindowGammaRamp +SDL_SetWindowGrab +SDL_SetWindowHitTest +SDL_SetWindowIcon +SDL_SetWindowInputFocus +SDL_SetWindowKeyboardGrab +SDL_SetWindowMaximumSize +SDL_SetWindowMinimumSize +SDL_SetWindowModalFor +SDL_SetWindowMouseGrab +SDL_SetWindowMouseRect +SDL_SetWindowOpacity +SDL_SetWindowPosition +SDL_SetWindowResizable +SDL_SetWindowShape +SDL_SetWindowSize +SDL_SetWindowsMessageHook +SDL_SetWindowTitle +SDL_SetYUVConversionMode +SDL_ShowCursor +SDL_ShowMessageBox +SDL_ShowSimpleMessageBox +SDL_ShowWindow +SDL_SIMDAlloc +SDL_SIMDFree +SDL_SIMDGetAlignment +SDL_SIMDRealloc +SDL_SoftStretch +SDL_SoftStretchLinear +SDL_StartTextInput +SDL_StopTextInput +SDL_Swap16 +SDL_Swap32 +SDL_Swap64 +SDL_SwapBE16 +SDL_SwapBE32 +SDL_SwapBE64 +SDL_SwapFloat +SDL_SwapFloatBE +SDL_SwapFloatLE +SDL_SwapLE16 +SDL_SwapLE32 +SDL_SwapLE64 +SDL_ThreadID +SDL_TICKS_PASSED +SDL_TLSCleanup +SDL_TLSCreate +SDL_TLSGet +SDL_TLSSet +SDL_TriggerBreakpoint +SDL_TryLockMutex +SDL_UIKitRunApp +SDL_UnionFRect +SDL_UnionRect +SDL_UnloadObject +SDL_UnlockAudio +SDL_UnlockAudioDevice +SDL_UnlockJoysticks +SDL_UnlockMutex +SDL_UnlockSurface +SDL_UnlockTexture +SDL_UnregisterApp +SDL_UpdateNVTexture +SDL_UpdateTexture +SDL_UpdateWindowSurface +SDL_UpdateWindowSurfaceRects +SDL_UpdateYUVTexture +SDL_UpperBlit +SDL_UpperBlitScaled +SDL_VERSION +SDL_VERSION_ATLEAST +SDL_VERSIONNUM +SDL_VideoInit +SDL_VideoQuit +SDL_Vulkan_CreateSurface +SDL_Vulkan_GetDrawableSize +SDL_Vulkan_GetInstanceExtensions +SDL_Vulkan_GetVkGetInstanceProcAddr +SDL_Vulkan_GetVkInstanceProcAddr +SDL_Vulkan_LoadLibrary +SDL_Vulkan_UnloadLibrary +SDL_WaitEvent +SDL_WaitEventTimeout +SDL_WaitThread +SDL_WarpMouseGlobal +SDL_WarpMouseInWindow +SDL_WasInit +SDL_WinRTGetDeviceFamily +SDL_WinRTGetFSPathUNICODE +SDL_WinRTGetFSPathUTF8 +SDL_WinRTRunApp +SDL_WriteBE16 +SDL_WriteBE32 +SDL_WriteBE64 +SDL_WriteLE16 +SDL_WriteLE32 +SDL_WriteLE64 +SDL_WriteU8 \ No newline at end of file diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..1c87bd3 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,3 @@ +{ + "ignore": ["node_modules/**/*", ".git", "src/settings.json"] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7898653 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,17058 @@ +{ + "name": "webinizer", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "webinizer", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "adm-zip": "^0.5.10", + "ajv": "^8.12.0", + "chalk": "^4.1.2", + "cors": "^2.8.5", + "directory-tree": "^3.5.1", + "dot-prop": "^6.0.1", + "express": "^4.18.2", + "express-validator": "^7.0.1", + "glob": "^8.0.3", + "graceful-fs": "^4.2.10", + "helmet": "^7.0.0", + "libnpmsearch": "^6.0.2", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "multiparty": "^4.2.3", + "npm-package-arg": "^10.1.0", + "pacote": "^15.1.1", + "prettier": "^2.8.2", + "pretty-format": "^29.3.1", + "semver": "^7.5.4", + "shelljs": "^0.8.5", + "shlex": "^2.1.2", + "write-file-atomic": "^5.0.0" + }, + "devDependencies": { + "@tsconfig/node16": "^1.0.3", + "@types/adm-zip": "^0.5.0", + "@types/chai": "^4.3.4", + "@types/configstore": "^6.0.0", + "@types/cors": "^2.8.13", + "@types/express": "^4.17.15", + "@types/graceful-fs": "^4.1.6", + "@types/libnpmsearch": "^2.0.3", + "@types/lodash": "^4.14.191", + "@types/mocha": "^10.0.1", + "@types/multiparty": "^0.0.33", + "@types/node": "^18.11.18", + "@types/npm-package-arg": "^6.1.1", + "@types/pacote": "^11.1.5", + "@types/prettier": "^2.7.3", + "@types/semver": "^7.3.13", + "@types/shelljs": "^0.8.11", + "@types/write-file-atomic": "^4.0.0", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "chai": "^4.3.7", + "concurrently": "^7.6.0", + "cross-env": "^7.0.3", + "dotenv": "^16.0.3", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-config-recommended": "^4.1.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.1.1", + "husky": "^8.0.3", + "mocha": "^10.2.0", + "nodemon": "^3.0.1", + "rimraf": "^3.0.2", + "shiki": "^0.12.1", + "ts-node": "^10.9.1", + "typedoc": "^0.23.24", + "typedoc-plugin-missing-exports": "^1.0.0", + "typedoc-plugin-rename-defaults": "^0.6.4", + "typescript": "^4.9.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jest/schemas": { + "version": "29.4.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.0.tgz", + "integrity": "sha512-0E01f/gOZeNTG76i5eWWSupvSHaIINrTie7vCyjiYFKgzNdyEGd12BUv4oNBFHOqlHDbtoJi3HrQ38KCC90NsQ==", + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", + "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", + "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.21", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", + "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@tufjs/models": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.0.tgz", + "integrity": "sha512-RRMu4uMxWnZlxaIBxahSb2IssFZiu188sndesZflWOe1cA/qUqtemSIoBWbuVKPvvdktapImWNnKpBcc+VrCQw==", + "dependencies": { + "minimatch": "^6.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/adm-zip": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz", + "integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "node_modules/@types/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-GUvNiia85zTDDIx0iPrtF3pI8dwrQkfuokEqxqPDE55qxH0U5SZz4awVZjiJLWN2ZZRkXCUqgsMUbygXY+kytA==", + "dev": true + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/glob": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.1.tgz", + "integrity": "sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/libnpmsearch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/libnpmsearch/-/libnpmsearch-2.0.3.tgz", + "integrity": "sha512-f/tTUDiOaUNk+m1mfvXO4/7ZasYUaKdosLgvzMdrFHNFqJENqwT9kKE+Gd6N3nsoD5kCZ7q4Pw7ApPIjXQArbA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/npm-registry-fetch": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "node_modules/@types/multiparty": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/multiparty/-/multiparty-0.0.33.tgz", + "integrity": "sha512-Il6cJUpSqgojT7NxbVJUvXkCblm50/yEJYtblISDsNIeNYf4yMAhdizzidUk6h8pJ8yhwK/3Fkb+3Dwcgtwl8w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz", + "integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==", + "dev": true + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-452/1Kp9IdM/oR10AyqAgZOxUt7eLbm+EMJ194L6oarMYdZNiFIFAOJ7IIr0OrZXTySgfHjJezh2oiyk2kc3ag==", + "dev": true + }, + "node_modules/@types/npm-registry-fetch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@types/npm-registry-fetch/-/npm-registry-fetch-8.0.4.tgz", + "integrity": "sha512-R9yEj6+NDmXLpKNS19cIaMyaHfV0aHjy/1qbo8K9jiHyjyaYg0CEmuOV/L0Q91DZDi3SuxlYY+2XYwh9TbB+eQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/node-fetch": "*", + "@types/npm-package-arg": "*", + "@types/npmlog": "*", + "@types/ssri": "*" + } + }, + "node_modules/@types/npmlog": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz", + "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==", + "dev": true + }, + "node_modules/@types/pacote": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@types/pacote/-/pacote-11.1.5.tgz", + "integrity": "sha512-kMsfmhP2G45ngnpvH0LKd1celWnjgdiws1FHu3vMmYuoElGdqnd0ydf1ucZzeXamYnLe0NvSzGP2gYiETOEiQA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/npm-registry-fetch": "*", + "@types/npmlog": "*", + "@types/ssri": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/shelljs": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", + "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", + "dev": true, + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ssri": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/ssri/-/ssri-7.1.1.tgz", + "integrity": "sha512-DPP/jkDaqGiyU75MyMURxLWyYLwKSjnAuGe9ZCsLp9QZOpXmDfuevk769F0BS86TmRuD5krnp06qw9nSoNO+0g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/write-file-atomic": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-piEKt2KKBUtye+feTlfdPjtW7uPFsAaLNX3/f6AJD+Y1T1YPTFwnqtlO9Y+gy9qGshrvxKa/Kay9vqbyVIuhwQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.50.0.tgz", + "integrity": "sha512-vwksQWSFZiUhgq3Kv7o1Jcj0DUNylwnIlGvKvLLYsq8pAWha6/WCnXUeaSoNNha/K7QSf2+jvmkxggC1u3pIwQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/type-utils": "5.50.0", + "@typescript-eslint/utils": "5.50.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.50.0.tgz", + "integrity": "sha512-KCcSyNaogUDftK2G9RXfQyOCt51uB5yqC6pkUYqhYh8Kgt+DwR5M0EwEAxGPy/+DH6hnmKeGsNhiZRQxjH71uQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.50.0.tgz", + "integrity": "sha512-rt03kaX+iZrhssaT974BCmoUikYtZI24Vp/kwTSy841XhiYShlqoshRFDvN1FKKvU2S3gK+kcBW1EA7kNUrogg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.50.0.tgz", + "integrity": "sha512-dcnXfZ6OGrNCO7E5UY/i0ktHb7Yx1fV6fnQGGrlnfDhilcs6n19eIRcvLBqx6OQkrPaFlDPk3OJ0WlzQfrV0bQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.50.0", + "@typescript-eslint/utils": "5.50.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.50.0.tgz", + "integrity": "sha512-atruOuJpir4OtyNdKahiHZobPKFvZnBnfDiyEaBf6d9vy9visE7gDjlmhl+y29uxZ2ZDgvXijcungGFjGGex7w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.50.0.tgz", + "integrity": "sha512-Gq4zapso+OtIZlv8YNAStFtT6d05zyVCK7Fx3h5inlLBx2hWuc/0465C2mg/EQDDU2LKe52+/jN4f0g9bd+kow==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.50.0.tgz", + "integrity": "sha512-v/AnUFImmh8G4PH0NDkf6wA8hujNNcrwtecqW4vtQ1UOSNBaZl49zP1SHoZ/06e+UiwzHpgb5zP5+hwlYYWYAw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.50.0.tgz", + "integrity": "sha512-cdMeD9HGu6EXIeGOh2yVW6oGf9wq8asBgZx7nsR/D36gTfQ0odE5kcRYe5M81vjEFAcPeugXrHg78Imu55F6gg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.50.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "dependencies": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/command-line-usage/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concurrently": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz", + "integrity": "sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.29.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/directory-tree": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-3.5.1.tgz", + "integrity": "sha512-HqjZ49fDzUnKYUhHxVw9eKBqbQ+lL0v4kSBInlDlaktmLtGoV9tC54a6A0ZfYeIrkMHWTE6MwwmUXP477+UEKQ==", + "dependencies": { + "command-line-args": "^5.2.0", + "command-line-usage": "^6.1.1" + }, + "bin": { + "directory-tree": "bin/index.js" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", + "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-esnext": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz", + "integrity": "sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA==", + "dev": true, + "dependencies": { + "babel-eslint": "^10.0.1", + "eslint": "^6.8.0", + "eslint-plugin-babel": "^5.2.1", + "eslint-plugin-import": "^2.14.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-esnext/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-esnext/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-esnext/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-esnext/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-config-esnext/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-esnext/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-esnext/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-esnext/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-esnext/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-esnext/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-node/-/eslint-config-node-4.1.0.tgz", + "integrity": "sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-node/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-config-node/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-node/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-node/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-node/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-node/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-node/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-node/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-node/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-config-node/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-node/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-node/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-node/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-node/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/eslint-config-node/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-node/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-node/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-node/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-node/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-node/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-native/-/eslint-config-react-native-4.1.0.tgz", + "integrity": "sha512-kNND+cs+ztawH7wgajf/K6FfNshjlDsFDAkkFZF9HAXDgH1w1sNMIfTfwzufg0hOcSK7rbiL4qbG/gg/oR507Q==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-native": "^3.8.1" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-config-react-native/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-react-native/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-react-native/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-react-native/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-react-native/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-react-native/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-config-react-native/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-react-native/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-react-native/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-react-native/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-react-native/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-react-native/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-react-native/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-react-native/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-react-native/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-recommended": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-4.1.0.tgz", + "integrity": "sha512-2evA0SX1VqtyFiExmBI2WAO4XQCKlr7wmNELE8rcT5PyZY2ixsY881ofVZWKuI/dywpgLiES1gR/XUQcnVLRzQ==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-config-node": "^4.1.0", + "eslint-config-react-native": "^4.1.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-recommended/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-recommended/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-recommended/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-recommended/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-config-recommended/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-recommended/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-recommended/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-recommended/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-recommended/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-recommended/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=4.0.0" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-validator": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz", + "integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==", + "dependencies": { + "lodash": "^4.17.21", + "validator": "^13.9.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/helmet": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", + "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/ignore-walk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", + "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "dependencies": { + "minimatch": "^6.1.6" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/inquirer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libnpmsearch": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-6.0.2.tgz", + "integrity": "sha512-p+5BF19AvnVg8mcIQhy6yWhI6jHQRVMYaIaKeITEfYAffWsqbottA/WZdMtHL76hViC6SFM1WdclM1w5eAIa1g==", + "dependencies": { + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/marked": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multiparty": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz", + "integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==", + "dependencies": { + "http-errors": "~1.8.1", + "safe-buffer": "5.2.1", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/multiparty/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multiparty/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multiparty/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", + "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz", + "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pacote": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", + "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.1.tgz", + "integrity": "sha512-dt/Z761JUVsrIKaY215o1xQJBGlSmTx/h4cSqXqjHLnU1+Kt+mavVE7UgqJJO5ukx5HjSswHfmXz4LjS2oIJfg==", + "dependencies": { + "@jest/schemas": "^29.4.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/read-package-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", + "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shiki": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz", + "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/shlex": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/shlex/-/shlex-2.1.2.tgz", + "integrity": "sha512-Nz6gtibMVgYeMEhUjp2KuwAgqaJA1K155dU/HuDaEJUGgnmYfVtVZah+uerVWdH8UGnyahhDCgABbYTbs254+w==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sigstore": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.1.1.tgz", + "integrity": "sha512-4hR3tPP1y59YWlaoAgAWFVZ7srTjNWOrrpkQXWu05qP0BvwFYyt3K3l848+IHo+mKhkOzGcNDf7ktASXLEPC+A==", + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/sigstore/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.1.tgz", + "integrity": "sha512-WTp382/PR96k0dI4GD5RdiRhgOU0rAC7+lnoih/5pZg3cyb3aNMqDozleEEWwyfT3+FOg7Qz9JU3n6A44tLSHw==", + "dependencies": { + "@tufjs/models": "1.0.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedoc": { + "version": "0.23.24", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz", + "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" + } + }, + "node_modules/typedoc-plugin-missing-exports": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-1.0.0.tgz", + "integrity": "sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA==", + "dev": true, + "peerDependencies": { + "typedoc": "0.22.x || 0.23.x" + } + }, + "node_modules/typedoc-plugin-rename-defaults": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.4.tgz", + "integrity": "sha512-0rAeNttAfu6ixbi1yu6d+DqNZN8SfRivj2QbnZ4zVa+5HcCPcmQrlR6WHjNzdDfpkGytiiqPTtRD6pAfW/yACg==", + "dev": true, + "peerDependencies": { + "typedoc": "0.22.x || 0.23.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/validator": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/write-file-atomic": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.0.tgz", + "integrity": "sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true + }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jest/schemas": { + "version": "29.4.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.0.tgz", + "integrity": "sha512-0E01f/gOZeNTG76i5eWWSupvSHaIINrTie7vCyjiYFKgzNdyEGd12BUv4oNBFHOqlHDbtoJi3HrQ38KCC90NsQ==", + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", + "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "requires": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==" + }, + "@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "requires": { + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/run-script": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", + "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==" + }, + "@sinclair/typebox": { + "version": "0.25.21", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", + "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==" + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@tufjs/models": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.0.tgz", + "integrity": "sha512-RRMu4uMxWnZlxaIBxahSb2IssFZiu188sndesZflWOe1cA/qUqtemSIoBWbuVKPvvdktapImWNnKpBcc+VrCQw==", + "requires": { + "minimatch": "^6.1.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@types/adm-zip": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz", + "integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-GUvNiia85zTDDIx0iPrtF3pI8dwrQkfuokEqxqPDE55qxH0U5SZz4awVZjiJLWN2ZZRkXCUqgsMUbygXY+kytA==", + "dev": true + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/glob": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.1.tgz", + "integrity": "sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==", + "dev": true, + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/libnpmsearch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/libnpmsearch/-/libnpmsearch-2.0.3.tgz", + "integrity": "sha512-f/tTUDiOaUNk+m1mfvXO4/7ZasYUaKdosLgvzMdrFHNFqJENqwT9kKE+Gd6N3nsoD5kCZ7q4Pw7ApPIjXQArbA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/npm-registry-fetch": "*" + } + }, + "@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "@types/multiparty": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/multiparty/-/multiparty-0.0.33.tgz", + "integrity": "sha512-Il6cJUpSqgojT7NxbVJUvXkCblm50/yEJYtblISDsNIeNYf4yMAhdizzidUk6h8pJ8yhwK/3Fkb+3Dwcgtwl8w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "18.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz", + "integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-452/1Kp9IdM/oR10AyqAgZOxUt7eLbm+EMJ194L6oarMYdZNiFIFAOJ7IIr0OrZXTySgfHjJezh2oiyk2kc3ag==", + "dev": true + }, + "@types/npm-registry-fetch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@types/npm-registry-fetch/-/npm-registry-fetch-8.0.4.tgz", + "integrity": "sha512-R9yEj6+NDmXLpKNS19cIaMyaHfV0aHjy/1qbo8K9jiHyjyaYg0CEmuOV/L0Q91DZDi3SuxlYY+2XYwh9TbB+eQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/node-fetch": "*", + "@types/npm-package-arg": "*", + "@types/npmlog": "*", + "@types/ssri": "*" + } + }, + "@types/npmlog": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz", + "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==", + "dev": true + }, + "@types/pacote": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@types/pacote/-/pacote-11.1.5.tgz", + "integrity": "sha512-kMsfmhP2G45ngnpvH0LKd1celWnjgdiws1FHu3vMmYuoElGdqnd0ydf1ucZzeXamYnLe0NvSzGP2gYiETOEiQA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/npm-registry-fetch": "*", + "@types/npmlog": "*", + "@types/ssri": "*" + } + }, + "@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/shelljs": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", + "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "@types/ssri": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/ssri/-/ssri-7.1.1.tgz", + "integrity": "sha512-DPP/jkDaqGiyU75MyMURxLWyYLwKSjnAuGe9ZCsLp9QZOpXmDfuevk769F0BS86TmRuD5krnp06qw9nSoNO+0g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/write-file-atomic": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-piEKt2KKBUtye+feTlfdPjtW7uPFsAaLNX3/f6AJD+Y1T1YPTFwnqtlO9Y+gy9qGshrvxKa/Kay9vqbyVIuhwQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.50.0.tgz", + "integrity": "sha512-vwksQWSFZiUhgq3Kv7o1Jcj0DUNylwnIlGvKvLLYsq8pAWha6/WCnXUeaSoNNha/K7QSf2+jvmkxggC1u3pIwQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/type-utils": "5.50.0", + "@typescript-eslint/utils": "5.50.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.50.0.tgz", + "integrity": "sha512-KCcSyNaogUDftK2G9RXfQyOCt51uB5yqC6pkUYqhYh8Kgt+DwR5M0EwEAxGPy/+DH6hnmKeGsNhiZRQxjH71uQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.50.0.tgz", + "integrity": "sha512-rt03kaX+iZrhssaT974BCmoUikYtZI24Vp/kwTSy841XhiYShlqoshRFDvN1FKKvU2S3gK+kcBW1EA7kNUrogg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.50.0.tgz", + "integrity": "sha512-dcnXfZ6OGrNCO7E5UY/i0ktHb7Yx1fV6fnQGGrlnfDhilcs6n19eIRcvLBqx6OQkrPaFlDPk3OJ0WlzQfrV0bQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.50.0", + "@typescript-eslint/utils": "5.50.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.50.0.tgz", + "integrity": "sha512-atruOuJpir4OtyNdKahiHZobPKFvZnBnfDiyEaBf6d9vy9visE7gDjlmhl+y29uxZ2ZDgvXijcungGFjGGex7w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.50.0.tgz", + "integrity": "sha512-Gq4zapso+OtIZlv8YNAStFtT6d05zyVCK7Fx3h5inlLBx2hWuc/0465C2mg/EQDDU2LKe52+/jN4f0g9bd+kow==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.50.0.tgz", + "integrity": "sha512-v/AnUFImmh8G4PH0NDkf6wA8hujNNcrwtecqW4vtQ1UOSNBaZl49zP1SHoZ/06e+UiwzHpgb5zP5+hwlYYWYAw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.50.0.tgz", + "integrity": "sha512-cdMeD9HGu6EXIeGOh2yVW6oGf9wq8asBgZx7nsR/D36gTfQ0odE5kcRYe5M81vjEFAcPeugXrHg78Imu55F6gg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.50.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "requires": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "cacache": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "requires": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concurrently": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz", + "integrity": "sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.29.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "directory-tree": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-3.5.1.tgz", + "integrity": "sha512-HqjZ49fDzUnKYUhHxVw9eKBqbQ+lL0v4kSBInlDlaktmLtGoV9tC54a6A0ZfYeIrkMHWTE6MwwmUXP477+UEKQ==", + "requires": { + "command-line-args": "^5.2.0", + "command-line-usage": "^6.1.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", + "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "eslint-config-esnext": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz", + "integrity": "sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA==", + "dev": true, + "requires": { + "babel-eslint": "^10.0.1", + "eslint": "^6.8.0", + "eslint-plugin-babel": "^5.2.1", + "eslint-plugin-import": "^2.14.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-node/-/eslint-config-node-4.1.0.tgz", + "integrity": "sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "dev": true, + "requires": {} + }, + "eslint-config-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-native/-/eslint-config-react-native-4.1.0.tgz", + "integrity": "sha512-kNND+cs+ztawH7wgajf/K6FfNshjlDsFDAkkFZF9HAXDgH1w1sNMIfTfwzufg0hOcSK7rbiL4qbG/gg/oR507Q==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-native": "^3.8.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-recommended": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-4.1.0.tgz", + "integrity": "sha512-2evA0SX1VqtyFiExmBI2WAO4XQCKlr7wmNELE8rcT5PyZY2ixsY881ofVZWKuI/dywpgLiES1gR/XUQcnVLRzQ==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-config-node": "^4.1.0", + "eslint-config-react-native": "^4.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "requires": {} + }, + "eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "express-validator": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz", + "integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.9.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "requires": { + "minipass": "^4.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "helmet": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", + "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==" + }, + "hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "requires": { + "lru-cache": "^7.5.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "ignore-walk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", + "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "requires": { + "minimatch": "^6.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==" + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==" + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "libnpmsearch": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-6.0.2.tgz", + "integrity": "sha512-p+5BF19AvnVg8mcIQhy6yWhI6jHQRVMYaIaKeITEfYAffWsqbottA/WZdMtHL76hViC6SFM1WdclM1w5eAIa1g==", + "requires": { + "npm-registry-fetch": "^14.0.3" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "requires": { + "minipass": "^3.1.1" + } + }, + "unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "marked": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==" + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multiparty": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz", + "integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==", + "requires": { + "http-errors": "~1.8.1", + "safe-buffer": "5.2.1", + "uid-safe": "2.1.5" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "requires": { + "abbrev": "^1.0.0" + } + } + } + }, + "nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "requires": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", + "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz", + "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==" + }, + "npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "requires": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "requires": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + } + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", + "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "requires": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==" + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "29.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.1.tgz", + "integrity": "sha512-dt/Z761JUVsrIKaY215o1xQJBGlSmTx/h4cSqXqjHLnU1+Kt+mavVE7UgqJJO5ukx5HjSswHfmXz4LjS2oIJfg==", + "requires": { + "@jest/schemas": "^29.4.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + } + } + }, + "proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "read-package-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", + "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "dev": true + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "shiki": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz", + "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "shlex": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/shlex/-/shlex-2.1.2.tgz", + "integrity": "sha512-Nz6gtibMVgYeMEhUjp2KuwAgqaJA1K155dU/HuDaEJUGgnmYfVtVZah+uerVWdH8UGnyahhDCgABbYTbs254+w==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "sigstore": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.1.1.tgz", + "integrity": "sha512-4hR3tPP1y59YWlaoAgAWFVZ7srTjNWOrrpkQXWu05qP0BvwFYyt3K3l848+IHo+mKhkOzGcNDf7ktASXLEPC+A==", + "requires": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + } + } + }, + "simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + } + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "requires": { + "minipass": "^4.0.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tuf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.1.tgz", + "integrity": "sha512-WTp382/PR96k0dI4GD5RdiRhgOU0rAC7+lnoih/5pZg3cyb3aNMqDozleEEWwyfT3+FOg7Qz9JU3n6A44tLSHw==", + "requires": { + "@tufjs/models": "1.0.0", + "make-fetch-happen": "^11.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedoc": { + "version": "0.23.24", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz", + "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==", + "dev": true, + "requires": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "typedoc-plugin-missing-exports": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-1.0.0.tgz", + "integrity": "sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA==", + "dev": true, + "requires": {} + }, + "typedoc-plugin-rename-defaults": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.4.tgz", + "integrity": "sha512-0rAeNttAfu6ixbi1yu6d+DqNZN8SfRivj2QbnZ4zVa+5HcCPcmQrlR6WHjNzdDfpkGytiiqPTtRD6pAfW/yACg==", + "dev": true, + "requires": {} + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "requires": { + "builtins": "^5.0.0" + } + }, + "validator": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "dev": true + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.0.tgz", + "integrity": "sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..30c20bc --- /dev/null +++ b/package.json @@ -0,0 +1,98 @@ +{ + "name": "webinizer", + "version": "0.0.1", + "description": "Toolkit to help the conversion of native apps/libs to Web version", + "main": "dist/webinizer.js", + "types": "typings/webinizer.d.ts", + "scripts": { + "build": "rimraf dist && tsc -b ./tsconfig.all.json", + "preserve": "npm run build", + "serve": "cross-env NODE_ENV=development concurrently \"tsc -b --watch ./tsconfig.all.json\" \"nodemon -q dist/server.js\"", + "prestart": "npm run build", + "start": "cross-env NODE_ENV=production node dist/server.js", + "lint": "eslint --fix src", + "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write", + "pretest": "npm run build", + "test": "cross-env TS_NODE_PROJECT='./tests/tsconfig.json' mocha -r ts-node/register tests/index.ts", + "doc": "rimraf docs && typedoc", + "prepare": "husky install" + }, + "repository": { + "type": "git", + "url": "https://github.com/intel/webinizer.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/intel/webinizer/issues" + }, + "homepage": "https://github.com/intel/webinizer#readme", + "devDependencies": { + "@tsconfig/node16": "^1.0.3", + "@types/adm-zip": "^0.5.0", + "@types/chai": "^4.3.4", + "@types/configstore": "^6.0.0", + "@types/cors": "^2.8.13", + "@types/express": "^4.17.15", + "@types/graceful-fs": "^4.1.6", + "@types/libnpmsearch": "^2.0.3", + "@types/lodash": "^4.14.191", + "@types/mocha": "^10.0.1", + "@types/multiparty": "^0.0.33", + "@types/node": "^18.11.18", + "@types/npm-package-arg": "^6.1.1", + "@types/pacote": "^11.1.5", + "@types/prettier": "^2.7.3", + "@types/semver": "^7.3.13", + "@types/shelljs": "^0.8.11", + "@types/write-file-atomic": "^4.0.0", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "chai": "^4.3.7", + "concurrently": "^7.6.0", + "cross-env": "^7.0.3", + "dotenv": "^16.0.3", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-config-recommended": "^4.1.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.1.1", + "husky": "^8.0.3", + "mocha": "^10.2.0", + "nodemon": "^3.0.1", + "rimraf": "^3.0.2", + "shiki": "^0.12.1", + "ts-node": "^10.9.1", + "typedoc": "^0.23.24", + "typedoc-plugin-missing-exports": "^1.0.0", + "typedoc-plugin-rename-defaults": "^0.6.4", + "typescript": "^4.9.4" + }, + "dependencies": { + "adm-zip": "^0.5.10", + "ajv": "^8.12.0", + "chalk": "^4.1.2", + "cors": "^2.8.5", + "directory-tree": "^3.5.1", + "dot-prop": "^6.0.1", + "express": "^4.18.2", + "express-validator": "^7.0.1", + "glob": "^8.0.3", + "graceful-fs": "^4.2.10", + "helmet": "^7.0.0", + "libnpmsearch": "^6.0.2", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "multiparty": "^4.2.3", + "npm-package-arg": "^10.1.0", + "pacote": "^15.1.1", + "prettier": "^2.8.2", + "pretty-format": "^29.3.1", + "semver": "^7.5.4", + "shelljs": "^0.8.5", + "shlex": "^2.1.2", + "write-file-atomic": "^5.0.0" + } +} diff --git a/src/action.ts b/src/action.ts new file mode 100644 index 0000000..79e45de --- /dev/null +++ b/src/action.ts @@ -0,0 +1,14 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "./helper"; +import { JsonFactories } from "./json_factory"; +import { IAction } from "webinizer"; + +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +const log = H.getLogger("action"); + +export const ALL_ACTION_FACTORIES = new JsonFactories("Action"); diff --git a/src/actions/args_change.ts b/src/actions/args_change.ts new file mode 100644 index 0000000..e51247d --- /dev/null +++ b/src/actions/args_change.ts @@ -0,0 +1,122 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import shlex from "shlex"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import { IAction, IArg, IJsonObject, Project as IProject } from "webinizer"; + +export function updateArgs(o: string, newArgs: IArg | IArg[]): string { + //FIXME. implement this in a more general way + // (i.e., 'merge' action with different separaters rather than " ") + const oldArgs = shlex.split(o); + for (const a of Array.isArray(newArgs) ? newArgs : [newArgs]) { + let argSet = false; + for (let i = 0; i < oldArgs.length; i++) { + if (oldArgs[i].includes(a.option)) { + if (a.type === "merge") { + oldArgs[i] = + a.value && !oldArgs[i].includes(a.value) ? oldArgs[i] + ` ${a.value}` : oldArgs[i]; + argSet = true; + break; + } else if (a.type === "replace") { + oldArgs[i] = a.value ? `${a.option}=${a.value}` : a.option; + argSet = true; + break; + } else if (a.type === "delete") { + oldArgs[i] = a.value ? oldArgs[i].replace(a.value, "") : ""; + break; + } else { + // a.type == "deleteAll", we don't break here as we need to ensure all satisfied options + // are removed. + oldArgs[i] = ""; + } + } + } + if (!argSet && a.type !== "delete" && a.type !== "deleteAll") { + oldArgs.push(`${a.option}${a.value ? "=" + a.value : ""}`); + } + } + return shlex.join(oldArgs.filter((o) => o)); +} + +export class BuilderArgsChangeAction implements IAction { + static __type__ = "BuilderArgsChange"; + type = BuilderArgsChangeAction.__type__; + proj: IProject; + desc: string; + args: IArg[]; + builderID: number; + refresh: boolean; + /** + * An action to change the build step arguments + * @param proj the Project object + * @param desc action description + * @param args args to be updated + * @param builderID the builder to be updated with `args` + * @param refresh whether refresh the cache or not when applying the action + */ + constructor(proj: IProject, desc: string, args: IArg[], builderID: number, refresh = true) { + this.proj = proj; + this.desc = desc; + this.args = args; + this.builderID = builderID; + this.refresh = refresh; + } + + async apply(): Promise { + const buildConfig = this.proj.config.getBuildConfigForTarget(this.proj.config.target); + const builders = buildConfig.rawBuilders; + if (builders) { + for (let i = 0; i < builders.length; i++) { + if (builders[i].id === this.builderID) { + // calculate the updated builders args @ apply instead of @ constructor + const newArgs = updateArgs(builders[i].args as string, this.args); + if (newArgs === (builders[i].args as string)) { + // if no differences in updated args, simply return without any updates + return true; + } else { + builders[i].args = newArgs; + break; + } + } + } + buildConfig.updateBuildConfig( + { + builders: builders, + }, + { refresh: this.refresh } + ); + return true; + } + return false; + } + + toJson(): IJsonObject { + return { + __type__: BuilderArgsChangeAction.__type__, + desc: this.desc, + args: this.args, + builderID: this.builderID, + refresh: this.refresh, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): BuilderArgsChangeAction { + checkJsonType(BuilderArgsChangeAction.__type__, o); + return new BuilderArgsChangeAction( + proj, + o.desc as string, + o.args as IArg[], + o.builderID as number, + o.refresh as boolean + ); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(BuilderArgsChangeAction.__type__, BuilderArgsChangeAction.fromJson); +} diff --git a/src/actions/build_step_change.ts b/src/actions/build_step_change.ts new file mode 100644 index 0000000..b6d87e1 --- /dev/null +++ b/src/actions/build_step_change.ts @@ -0,0 +1,171 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import errorCode from "../error_code"; +import { IAction, IJsonObject, IToJson, Project as IProject, IBuilderJson } from "webinizer"; + +const log = H.getLogger("build_step_change"); + +export class BuildStepRegion implements IToJson { + iStart: number; + iEnd: number; + + /** + * Represent a region/index range of build steps. [iStart, iEnd), 0 indexed + * @param iStart start of the region, 0 indexed + * @param iEnd end of the region, default is the same as iStart + */ + constructor(iStart: number, iEnd = iStart) { + H.assert(iEnd >= iStart && iStart >= 0, "Invalid line numbers!"); + this.iStart = iStart; + this.iEnd = iEnd; + } + + static fromJson(o: IJsonObject): BuildStepRegion { + checkJsonType("BuildStepRegion", o); + return new BuildStepRegion(o.iStart as number, o.iEnd as number); + } + toJson(): IJsonObject { + return { + __type__: "BuildStepRegion", + iStart: this.iStart, + iEnd: this.iEnd, + }; + } + + isIntersected(r: BuildStepRegion): boolean { + // if iStart or iEnd in previous recorded BuildStepRegion - intersect + return ( + (r.iStart <= this.iStart && this.iStart < r.iEnd) || + (r.iStart < this.iEnd && this.iEnd <= r.iEnd) + ); + } + + /** + * Index change if some build steps are changed previously + * @param r The region that is changed previously + * @param nNewSteps Number of build steps after changed this region + * @returns Indexes shift for this change + */ + indexesToAdjust(r: BuildStepRegion, nNewSteps: number): number { + if (this.isIntersected(r)) { + throw new H.WError( + `indexesToAdjust: ${H.prettyFormat(this)} intersects with ${H.prettyFormat(r)}`, + errorCode.WEBINIZER_ACTION_BUILDSTEP_INTERSECT + ); + } + if (r.iStart >= this.iEnd) { + return 0; + } + return nNewSteps - (r.iEnd - r.iStart); + } +} + +export class BuildStepChangeManager { + private _changes: BuildStepChangeAction[] = []; + + private _updateSteps(proj: IProject, region: BuildStepRegion, steps: IBuilderJson[]): boolean { + const buildConfig = proj.config.getBuildConfigForTarget(proj.config.target); + const builders = buildConfig.rawBuilders; + if (builders && builders.length) { + builders.splice(region.iStart, region.iEnd - region.iStart, ...steps); + buildConfig.updateBuildConfig({ builders }); + return true; + } + return false; + } + + async apply(action: BuildStepChangeAction): Promise { + const actualRegion = action.actualBuildStepRegion(this._changes); + if (!actualRegion) { + log.error("Build Step change conflicts for action", action); + return false; + } + if (this._updateSteps(action.proj, actualRegion, action.newBuildSteps)) { + this._changes.push(action); + return true; + } + return false; + } +} + +export class BuildStepChangeAction implements IAction { + static __type__ = "BuildStepChange"; + type = BuildStepChangeAction.__type__; + proj: IProject; + desc: string; + region: BuildStepRegion; + newBuildSteps: IBuilderJson[]; + nNewSteps = 0; + /** + * An action to change build steps + * @param proj the project + * @param desc action description + * @param region the build step regions to change + * @param newBuildSteps new build steps to change + */ + constructor( + proj: IProject, + desc: string, + region: BuildStepRegion, + newBuildSteps: IBuilderJson[] | null + ) { + this.proj = proj; + this.desc = desc; + this.region = region; + this.newBuildSteps = newBuildSteps || []; + if (newBuildSteps) { + this.nNewSteps = newBuildSteps.length; + } + } + + async apply(): Promise { + return await this.proj.buildStepChangeManager.apply(this); + } + + toJson(): IJsonObject { + return { + __type__: BuildStepChangeAction.__type__, + desc: this.desc, + region: this.region.toJson(), + newBuildSteps: this.newBuildSteps, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): BuildStepChangeAction { + checkJsonType(BuildStepChangeAction.__type__, o); + return new BuildStepChangeAction( + proj, + o.desc as string, + BuildStepRegion.fromJson(o.region as IJsonObject), + o.newBuildSteps as IBuilderJson[] + ); + } + + actualBuildStepRegion(changes: BuildStepChangeAction[]): BuildStepRegion | null { + let delta = 0; + for (const c of changes) { + try { + delta += this.region.indexesToAdjust(c.region, c.nNewSteps); + } catch (e) { + log.error( + "Build Steps change conflicts:", + H.prettyFormat(this.region), + H.prettyFormat(c.region) + ); + return null; + } + } + return new BuildStepRegion(this.region.iStart + delta, this.region.iEnd + delta); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(BuildStepChangeAction.__type__, BuildStepChangeAction.fromJson); +} diff --git a/src/actions/config_env_change.ts b/src/actions/config_env_change.ts new file mode 100644 index 0000000..e375549 --- /dev/null +++ b/src/actions/config_env_change.ts @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import { updateArgs } from "./args_change"; +import { EnvType, ProjectEnv, IAction, IArg, IJsonObject, Project as IProject } from "webinizer"; + +const log = H.getLogger("config_env_change"); + +export class ConfigEnvChangeAction implements IAction { + static __type__ = "ConfigEnvChange"; + type = ConfigEnvChangeAction.__type__; + proj: IProject; + desc: string; + properties = "envs"; + partToUpdate: Partial>; + /** + * An action to change the project compiler and linker flags + * @param proj the Project object + * @param desc action description + * @param partToUpdate the envs args to be updated + */ + constructor(proj: IProject, desc: string, partToUpdate: Partial>) { + this.proj = proj; + this.desc = desc; + this.partToUpdate = partToUpdate; + } + + async apply(): Promise { + // calculate the updated partToUpdate @ apply instead of @ creation to avoid conflicts + log.info("partToUpdate is:", this.partToUpdate); + const envParts = Object.keys(this.partToUpdate) as EnvType[]; + const buildConfig = this.proj.config.getBuildConfigForTarget(this.proj.config.target); + const updateEnv = (envs: ProjectEnv, k: EnvType, args: IArg | IArg[]) => { + log.info(`... to update ${k} with args to change are \n`, args); + // update envs and save + if (envs) { + const updatedArgs = updateArgs(envs[k], args); + if (updatedArgs !== envs[k]) { + envs[k] = updatedArgs; + } + } + }; + const envsToUpdate = Object.assign({}, buildConfig.envs); + for (const env of envParts) { + updateEnv(envsToUpdate, env, this.partToUpdate[env] as IArg[]); + } + buildConfig.updateBuildConfig({ envs: envsToUpdate }, { updateEnvParts: envParts }); + return true; + } + + toJson(): IJsonObject { + return { + __type__: ConfigEnvChangeAction.__type__, + desc: this.desc, + properties: this.properties, + partToUpdate: this.partToUpdate, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): ConfigEnvChangeAction { + checkJsonType(ConfigEnvChangeAction.__type__, o); + return new ConfigEnvChangeAction(proj, o.desc as string, o.partToUpdate as H.Dict); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(ConfigEnvChangeAction.__type__, ConfigEnvChangeAction.fromJson); +} diff --git a/src/actions/config_option_change.ts b/src/actions/config_option_change.ts new file mode 100644 index 0000000..af23505 --- /dev/null +++ b/src/actions/config_option_change.ts @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import { + BuildOptionType, + IProjectBuildOptions, + IAction, + IJsonObject, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("config_option_change"); + +export class ConfigOptionChangeAction implements IAction { + static __type__ = "ConfigOptionChange"; + type = ConfigOptionChangeAction.__type__; + proj: IProject; + desc: string; + properties = "options"; + partToUpdate: IProjectBuildOptions; + /** + * An action to change the project config options + * @param proj the Project object + * @param desc action description + * @param partToUpdate the config part to be updated + */ + constructor(proj: IProject, desc: string, partToUpdate: IProjectBuildOptions) { + this.proj = proj; + this.desc = desc; + this.partToUpdate = partToUpdate; + } + + async apply(): Promise { + // calculate the updated partToUpdate @ apply instead of @ creation to avoid conflicts + log.info("partToUpdate is:", this.partToUpdate); + const buildConfig = this.proj.config.getBuildConfigForTarget(this.proj.config.target); + const updateOptions: IProjectBuildOptions = {}; + if (buildConfig.options) { + Object.assign(updateOptions, buildConfig.options, this.partToUpdate); + } else { + Object.assign(updateOptions, this.partToUpdate); + } + buildConfig.updateBuildConfig( + { options: updateOptions }, + { updateOptParts: Object.keys(this.partToUpdate) as BuildOptionType[] } + ); + return true; + } + + toJson(): IJsonObject { + return { + __type__: ConfigOptionChangeAction.__type__, + desc: this.desc, + properties: this.properties, + partToUpdate: this.partToUpdate, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): ConfigOptionChangeAction { + checkJsonType(ConfigOptionChangeAction.__type__, o); + return new ConfigOptionChangeAction(proj, o.desc as string, o.partToUpdate as H.Dict); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register( + ConfigOptionChangeAction.__type__, + ConfigOptionChangeAction.fromJson + ); +} diff --git a/src/actions/file_change.ts b/src/actions/file_change.ts new file mode 100644 index 0000000..b6c842a --- /dev/null +++ b/src/actions/file_change.ts @@ -0,0 +1,245 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import fs from "graceful-fs"; +import writeFileAtomic from "write-file-atomic"; +import errorCode from "../error_code"; +import { IAction, IJsonObject, IToJson, Project as IProject, IFileChangeManager } from "webinizer"; + +const log = H.getLogger("file_change"); + +/** + * Some errors have file:line:col encoded in the error log + * @param s error log + * @param reverse find the first or last pattern occurrence in error log + * @returns FileLocation or null + * examples: CMake Error at /home/test/tests.cmake:146 (message): + */ +export function getFileLocation(s: string, reverse: boolean): FileLocation | null { + let lines = s.trimStart().split("\n"); + if (reverse) lines = lines.reverse(); + + // FIXME: this doesn't support file name which contains spaces. need to be fixed + const re = /\b(?[^:\s]+):(?\d+)(:(?\d+))?\b/; + + for (const line of lines) { + const m = line.match(re); + if (m && m.groups) { + return new FileLocation( + m.groups.file as string, + parseInt(m.groups.line as string), + m.groups.col ? parseInt(m.groups.col as string) : 0 + ); + } + } + return null; +} + +export class FileLocation implements IToJson { + file: string; + line: number; + col: number; + constructor(file: string, line: number, col: number) { + this.file = file; + this.line = line; + this.col = col; + } + static fromJson(o: IJsonObject): FileLocation { + checkJsonType("FileLocation", o); + return new FileLocation(o.file as string, o.line as number, o.col as number); + } + + toJson(): IJsonObject { + return { + __type__: "FileLocation", + file: this.file, + line: this.line, + col: this.col, + }; + } + + toFileRegion(): FileRegion { + return new FileRegion(this.file, this.line); + } +} + +// TODO: currently the granualarity is line, maybe in the future we could further improve it to be +// character based so to avoid conflicts +export class FileRegion implements IToJson { + file: string; // path + lineStart: number; + lineEnd: number; + + static fromJson(o: IJsonObject): FileRegion { + checkJsonType("FileRegion", o); + return new FileRegion(o.file as string, o.lineStart as number, o.lineEnd as number); + } + toJson(): IJsonObject { + return { + __type__: "FileRegion", + file: this.file, + lineStart: this.lineStart, + lineEnd: this.lineEnd, + }; + } + /** + * Represent a region of lines in the file. [LineStart, LineEnd), 0 indexed + * @param file path to the file + * @param lineStart start of the region, 0 indexed + * @param lineEnd end of the region + */ + constructor(file: string, lineStart: number, lineEnd = lineStart + 1) { + H.assert(lineEnd >= lineStart && lineStart >= 0, "Invalid line numbers!"); + this.file = file; + this.lineStart = lineStart; + this.lineEnd = lineEnd; + } + isIntersected(r: FileRegion): boolean { + if (r.file !== this.file) { + return false; + } + // if lineStart or lineEnd in previous recorded FileRegion - intersect + return ( + (r.lineStart <= this.lineStart && this.lineStart < r.lineEnd) || + (r.lineStart < this.lineEnd && this.lineEnd <= r.lineEnd) + ); + } + + /** + * Lines change change if some region in this file is changed + * @param r The region changed + * @param nNewLines Number of lines after changed that region + * @returns number of lines to change + */ + linesToAdjust(r: FileRegion, nNewLines: number): number { + if (this.isIntersected(r)) { + throw new H.WError( + `linesToAdjust: ${H.prettyFormat(this)} intersects with ${H.prettyFormat(r)}`, + errorCode.WEBINIZER_ACTION_FILE_INTERSECT + ); + } + if (r.file !== this.file || r.lineStart >= this.lineEnd) { + return 0; + } + return nNewLines - (r.lineEnd - r.lineStart); + } +} + +// Multiple FileChangeActions may change to one file, so we need one manager to coordinate all of +// them to ensure all histories in this one session is all tracked and managed +export class FileChangeManager { + _changes: { [key: string]: FileChangeAction[] } = {}; + + private _updateFile(region: FileRegion, content: string | null): void { + const lines = fs.readFileSync(region.file, "utf-8").split("\n"); + + lines.splice( + region.lineStart - 1, + region.lineEnd - region.lineStart, + ...(content !== null ? [content] : []) + ); + + writeFileAtomic.sync(region.file, lines.join("\n"), "utf-8"); + } + + async apply(action: FileChangeAction): Promise { + const file = action.region.file; + if (!(file in this._changes)) { + this._changes[file] = []; + } + const actualRegion = action.actualFileRegion(this._changes[file]); + if (!actualRegion) { + log.error("File change conflicts for action", action); + return false; + } + this._changes[file].push(action); + this._updateFile(actualRegion, action.newContent); + return true; + } +} + +export class FileChangeAction implements IAction { + static __type__ = "FileChange"; + type = FileChangeAction.__type__; + manager: IFileChangeManager; + desc: string; + region: FileRegion; + newContent: string | null; + nLinesNewContent = 0; + /** + * An action to change the content of files + * @param manager the manager to handle all changes + * @param desc action description + * @param region area to change + * @param content new content. It means delete if this is null + */ + constructor( + manager: IFileChangeManager, + desc: string, + region: FileRegion, + content: string | null + ) { + this.manager = manager; + this.desc = desc; + this.region = region; + this.newContent = content; + if (content !== null) { + this.nLinesNewContent = content.split("\n").length; + } + } + async apply(): Promise { + return await this.manager.apply(this); + } + + toJson(): IJsonObject { + return { + __type__: FileChangeAction.__type__, + desc: this.desc, + region: this.region.toJson(), + newContent: this.newContent, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): FileChangeAction { + checkJsonType(FileChangeAction.__type__, o); + return new FileChangeAction( + proj.fileChangeManager, + o.desc as string, + FileRegion.fromJson(o.region as IJsonObject), + o.newContent as string + ); + } + /** + * Actual region if the target file already changed by other actions + * @param changes A list of FileChangActions happen in advance + * @returns returns null if there is a conflict, otherwise the adjusted FileRegion. Conflict + * example: change line [10, 20] but there is somebody already changed line [15, 16] in this + * region + */ + actualFileRegion(changes: FileChangeAction[]): FileRegion | null { + let delta = 0; + for (const c of changes) { + try { + delta += this.region.linesToAdjust(c.region, c.nLinesNewContent); + } catch (e) { + log.error("File change conflicts:", H.prettyFormat(this.region), H.prettyFormat(c.region)); + return null; + } + } + return new FileRegion( + this.region.file, + this.region.lineStart + delta, + this.region.lineEnd + delta + ); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(FileChangeAction.__type__, FileChangeAction.fromJson); +} diff --git a/src/actions/get_user_input.ts b/src/actions/get_user_input.ts new file mode 100644 index 0000000..ce2cf8b --- /dev/null +++ b/src/actions/get_user_input.ts @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { IAction, IJsonObject } from "webinizer"; + +const ACTION_TYPE = "GetUserInputAction"; +export class GetUserInputAction implements IAction { + type = ACTION_TYPE; + desc = "This is GetUserInputAction"; + // TODO: it should send a request to frontend and get the user input and then run the customized + // callback to process the input + async apply(): Promise { + return false; + } + toJson(): IJsonObject { + return { + __type__: this.type, + desc: this.desc, + }; + } +} diff --git a/src/actions/show_dep_recipe.ts b/src/actions/show_dep_recipe.ts new file mode 100644 index 0000000..69f28c7 --- /dev/null +++ b/src/actions/show_dep_recipe.ts @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import { IAction, IJsonObject, Project as IProject } from "webinizer"; + +const log = H.getLogger("show_dep_recipe"); + +export class ShowDepRecipeAction implements IAction { + static __type__ = "ShowDepRecipe"; + type = ShowDepRecipeAction.__type__; + desc: string; + deps: string[]; + /** + * An action to show dependent projects that have recipes generated + * @param desc action description + * @param deps dependent projects + */ + constructor(desc: string, deps: string[]) { + this.desc = desc; + this.deps = deps; + } + + async apply(): Promise { + log.info("Dependent projects that have recipes generated:\n", `${this.deps.join("\n")}`); + return true; + } + + toJson(): IJsonObject { + return { + __type__: ShowDepRecipeAction.__type__, + desc: this.desc, + deps: this.deps, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): ShowDepRecipeAction { + checkJsonType(ShowDepRecipeAction.__type__, o); + return new ShowDepRecipeAction(o.desc as string, o.deps as string[]); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(ShowDepRecipeAction.__type__, ShowDepRecipeAction.fromJson); +} diff --git a/src/actions/show_suggestion.ts b/src/actions/show_suggestion.ts new file mode 100644 index 0000000..b03edca --- /dev/null +++ b/src/actions/show_suggestion.ts @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_ACTION_FACTORIES } from "../action"; +import { checkJsonType } from "../json_factory"; +import { FileRegion } from "./file_change"; +import { IAction, IJsonObject, IToJson, Project as IProject } from "webinizer"; + +const log = H.getLogger("show_suggestion"); + +// "option": suggestions generated based on user options +// "error": suggestions generated based on error requests +export type SuggestionInitiator = "option" | "error"; + +export class SuggestionExample implements IToJson { + before: string; //before modification + after: string; // after modification + constructor(before: string, after: string) { + this.before = before; + this.after = after; + } + + static fromJson(o: IJsonObject): SuggestionExample { + checkJsonType("SuggestionExample", o); + return new SuggestionExample(o.before as string, o.after as string); + } + + toJson(): IJsonObject { + return { + __type__: "SuggestionExample", + before: this.before, + after: this.after, + }; + } +} + +export class ShowSuggestionAction implements IAction { + static __type__ = "ShowSuggestion"; + type = ShowSuggestionAction.__type__; + initiator: SuggestionInitiator; + desc: string; + suggestion: SuggestionExample | null; + region: FileRegion | null; + /** + * An action to show suggestion to user + * @param init the initiator of the suggestion + * @param desc action description + * @param suggestion the suggestion example + * @param region the file region related with the suggestion + */ + constructor( + init: SuggestionInitiator, + desc: string, + suggestion: SuggestionExample | null, + region: FileRegion | null + ) { + this.initiator = init; + this.desc = desc; + this.suggestion = suggestion; + this.region = region; + } + + async apply(): Promise { + // display suggestion message for debugging + log.info( + `${this.region ? this.region.file + ":" + this.region.lineStart : "General:"} ${this.desc}` + ); + if (this.suggestion) { + log.info(`Example\nBefore:\n${this.suggestion.before}\nAfter:\n${this.suggestion.after}`); + } + return true; + } + + toJson(): IJsonObject { + return { + __type__: this.type, + initiator: this.initiator, + desc: this.desc, + suggestion: this.suggestion ? this.suggestion.toJson() : null, + region: this.region ? this.region.toJson() : null, + }; + } + + static fromJson(proj: IProject, o: IJsonObject): ShowSuggestionAction { + checkJsonType(ShowSuggestionAction.__type__, o); + return new ShowSuggestionAction( + o.initiator as SuggestionInitiator, + o.desc as string, + o.suggestion ? SuggestionExample.fromJson(o.suggestion as IJsonObject) : null, + o.region ? FileRegion.fromJson(o.region as IJsonObject) : null + ); + } +} + +export default function onload() { + ALL_ACTION_FACTORIES.register(ShowSuggestionAction.__type__, ShowSuggestionAction.fromJson); +} diff --git a/src/advise_requests/common_requests.ts b/src/advise_requests/common_requests.ts new file mode 100644 index 0000000..808e5eb --- /dev/null +++ b/src/advise_requests/common_requests.ts @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { FileLocation } from "../actions/file_change"; +import { ALL_ADVISE_REQUESTS_FACTORIES } from "../advisor"; +import { checkJsonType } from "../json_factory"; +import { IJsonObject, IAdviseRequest, Project as IProject } from "webinizer"; + +export class ErrorAdviseRequest implements IAdviseRequest { + static __type__ = "ErrorAdviseRequest"; + tags: string[]; + error: string; + location: FileLocation | null; + builderID: number; + constructor( + tags: string | string[], + error: string, + location: FileLocation | null, + builderID: number + ) { + if (!Array.isArray(tags)) { + tags = [tags]; + } + this.tags = tags; + this.error = error; + this.location = location; + this.builderID = builderID; + } + toJson(): IJsonObject { + return { + __type__: ErrorAdviseRequest.__type__, + tags: this.tags, + error: this.error, + location: this.location ? this.location.toJson() : null, + builder: this.builderID, + }; + } + static fromJson(proj: IProject, o: IJsonObject): ErrorAdviseRequest { + checkJsonType(ErrorAdviseRequest.__type__, o); + return new ErrorAdviseRequest( + o.tags as string[], + o.error as string, + o.location ? FileLocation.fromJson(o.location as IJsonObject) : null, + o.builder as number + ); + } +} + +// This is a plain AdviseRequest which means itself is a kind of Json so easy to fromJson() and +// toJson() +export class PlainAdviseRequest implements IAdviseRequest { + static __type__ = "PlainAdviseRequest"; + tags: string[]; + plainData: unknown; // the plain data + constructor(tags: string | string[], plainData: unknown) { + if (!Array.isArray(tags)) { + tags = [tags]; + } + this.tags = tags; + this.plainData = plainData; + } + toJson(): IJsonObject { + return { + __type__: PlainAdviseRequest.__type__, + tags: this.tags, + plainData: this.plainData, + }; + } + static fromJson(proj: IProject, o: IJsonObject): PlainAdviseRequest { + checkJsonType(PlainAdviseRequest.__type__, o); + return new PlainAdviseRequest(o.tags as string[], o.plainData); + } +} + +export default function onload() { + ALL_ADVISE_REQUESTS_FACTORIES.register(ErrorAdviseRequest.__type__, ErrorAdviseRequest.fromJson); + ALL_ADVISE_REQUESTS_FACTORIES.register(PlainAdviseRequest.__type__, PlainAdviseRequest.fromJson); +} diff --git a/src/advisor.ts b/src/advisor.ts new file mode 100644 index 0000000..dac1fea --- /dev/null +++ b/src/advisor.ts @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import chalk from "chalk"; +import * as H from "./helper"; +import { JsonFactories } from "./json_factory"; +import { type Recipe } from "./recipe"; +import { ErrorAdviseRequest } from "./advise_requests/common_requests"; +import { advisorPipelineFactory } from "./advisor_pipeline"; +import { + AdviseManager as IAdviseManager, + IAdviseRequest, + IAdvisorFactory, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("advisor"); + +export const ALL_ADVISE_REQUESTS_FACTORIES = new JsonFactories("AdviseRequest"); + +const _ALL_ADVISOR_FACTORIES = new Map(); + +export class AdviseManager implements IAdviseManager { + private _requestList: IAdviseRequest[] = []; + proj: IProject; + + constructor(proj: IProject) { + this.proj = proj; + } + + queueRequest(req: IAdviseRequest) { + this._requestList.push(req); + } + async advise(): Promise { + let requests = this._requestList; + const recipes: Recipe[] = []; + while (requests.length > 0) { + const req = requests.shift() as IAdviseRequest; + log.info(`advising request with tag: ${req.tags}`); + + const pipelines = advisorPipelineFactory.createAdvisorPipeline(req.tags); + let isBreak = false; + for (const pipeline of pipelines) { + for (const advisor of pipeline.advisors) { + const result = await advisor.advise(this.proj, req, requests); + if (result.handled) { + log.info(` - adviced by ${advisor.type}`); + if (result.recipe) { + recipes.push(result.recipe); + } + // the advisor may change the rest of the queue + if (result.newRequestQueue) { + requests = result.newRequestQueue; + } + // this is the default behavior, i.e. a request is only handled by only one advisor + if (!result.needPropagation) { + isBreak = true; + break; + } + } + } + if (isBreak) { + break; + } + } + + // No recipe generated for the ErrorAdviseRequest, get errors_not_handled advisor and generate recipe. + if (req instanceof ErrorAdviseRequest && !recipes.length) { + const defaultErrorAdvisor = + advisorFactoryFromType("ErrorsNotHandledAdvisor")?.createAdvisor(); + if (defaultErrorAdvisor) { + const result = await defaultErrorAdvisor.advise(this.proj, req, requests); + if (result.handled) { + log.info(` - errors not handled by Webinizer, running ${defaultErrorAdvisor.type}`); + if (result.recipe) { + recipes.push(result.recipe); + } + } + } + } + } + return recipes; + } +} + +export function registerAdvisorFactory(type: string, factory: IAdvisorFactory) { + H.assert( + !_ALL_ADVISOR_FACTORIES.has(type), + `Already registerred AdvisorFactory with type: ${type}` + ); + + _ALL_ADVISOR_FACTORIES.set(type, factory); + + log.info( + `* ${chalk.yellowBright("<< AdvisorFactory >>")} - registered ${chalk.cyanBright( + factory.name + )} with type ${chalk.cyanBright(type)}` + ); +} + +export function advisorFactoryFromType(type: string): IAdvisorFactory | null { + return _ALL_ADVISOR_FACTORIES.get(type) || null; +} diff --git a/src/advisor_pipeline.ts b/src/advisor_pipeline.ts new file mode 100644 index 0000000..0871499 --- /dev/null +++ b/src/advisor_pipeline.ts @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * AdvisorPipeline + * @module + */ +import { advisorFactoryFromType } from "./advisor"; +import * as H from "./helper"; +import fs from "graceful-fs"; +import path from "path"; +import { WEBINIZER_SRC_HOME } from "./constants"; +import errorCode from "./error_code"; +import { IAdvisor, IJsonObject, IToJson } from "webinizer"; + +const log = H.getLogger("advisor_pipeline"); + +interface IAdvisorPipelineConfigItem { + tag: string; + advisors: IJsonObject[]; +} + +export interface IAdvisorPipeline { + tag: string; + advisors: IAdvisor[]; +} + +class AdvisorPipelineConfig implements IToJson { + static __type__ = "AdvisorPipelineConfig"; + private _filePath = path.join(WEBINIZER_SRC_HOME, "advisor_pipelines.json"); + private _data: IJsonObject; + + constructor() { + this._data = { __type__: AdvisorPipelineConfig.__type__ }; + if (fs.existsSync(this._filePath)) { + this.load(); + } + } + + toJson(): IJsonObject { + return this._data; + } + + get data(): IJsonObject { + return this._data; + } + + get pipelines(): IAdvisorPipelineConfigItem[] | undefined { + return this.data.pipelines as IAdvisorPipelineConfigItem[]; + } + + get filePath(): string { + return this._filePath; + } + + private load() { + try { + const data = JSON.parse(fs.readFileSync(this._filePath, "utf8")) as IJsonObject; + H.assert(data.__type__ === this.data.__type__); + this._data = data; + //eslint-disable-next-line + } catch (err: any) { + let errMsg; + if (err.code === "ENOENT") { + errMsg = `Tried to load ${this.data.__type__} from an nonexist file: ${this.filePath}`; + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_ADVISOR_PIPELINE_FILE_NOEXT); + } else { + errMsg = + `Failed to load ${this.data.__type__} from file ${this.filePath} due to error:\n` + + H.normalizeErrorOutput(err as Error); + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_ADVISOR_PIPELINE_FILE_LOAD_FAIL); + } + } + } +} + +class AdvisorPipelineFactory { + private _config: AdvisorPipelineConfig; + private static _instance: AdvisorPipelineFactory; + + private constructor() { + this._config = new AdvisorPipelineConfig(); + } + + static getInstance(): AdvisorPipelineFactory { + if (!AdvisorPipelineFactory._instance) { + AdvisorPipelineFactory._instance = new AdvisorPipelineFactory(); + } + return AdvisorPipelineFactory._instance; + } + + private getPipelineItemFromTag(tag: string): IAdvisorPipelineConfigItem | null { + if (this._config.pipelines !== undefined && this._config.pipelines.length > 0) { + for (const item of this._config.pipelines) { + if (item.tag === tag) { + return item; + } + } + } + return null; + } + + createAdvisorPipeline(tags: string | string[]): IAdvisorPipeline[] { + const pipelines: IAdvisorPipeline[] = []; + if (!Array.isArray(tags)) { + tags = [tags]; + } + + for (const t of tags) { + const pipelineItem = this.getPipelineItemFromTag(t); + if ( + pipelineItem !== null && + pipelineItem.advisors != null && + pipelineItem.advisors.length > 0 + ) { + const advisors: IAdvisor[] = []; + for (const advisorItem of pipelineItem.advisors) { + const factory = advisorFactoryFromType(advisorItem.__type__); + if (factory != null) { + advisorItem.args + ? advisors.push(factory.createAdvisor(advisorItem.args as string)) + : advisors.push(factory.createAdvisor()); + } + } + pipelines.push({ tag: t, advisors: advisors }); + } + } + + return pipelines; + } +} + +export const advisorPipelineFactory = AdvisorPipelineFactory.getInstance(); diff --git a/src/advisor_pipelines.json b/src/advisor_pipelines.json new file mode 100644 index 0000000..f497aac --- /dev/null +++ b/src/advisor_pipelines.json @@ -0,0 +1,59 @@ +{ + "__type__": "AdvisorPipelineConfig", + "pipelines": [ + { + "tag": "make", + "advisors": [ + { "__type__": "BuildNativeToolAdvisor" }, + { "__type__": "HeaderMissingAdvisor" }, + { "__type__": "MakeTargetAdvisor" }, + { "__type__": "SDLAdvisor" }, + { "__type__": "TestTargetErrorAdvisor" } + ] + }, + { + "tag": "cmake", + "advisors": [{ "__type__": "SDLAdvisor" }] + }, + { + "tag": "pre-build", + "advisors": [ + { "__type__": "BuildPathValidateAdvisor" }, + { "__type__": "BuildStepValidateAdvisor" }, + { "__type__": "CppExceptionAdvisor" }, + { "__type__": "DepCheckAdvisor" }, + { "__type__": "ExportNameAdvisor" }, + { "__type__": "MainLoopAdvisor" }, + { "__type__": "PThreadAdvisor" }, + { "__type__": "TemplateLiteralValidateAdvisor" } + ] + }, + { + "tag": "cfg_args", + "advisors": [ + { "__type__": "BuildTargetSpecifyAdvisor" }, + { "__type__": "CCompilerAdvisor" }, + { "__type__": "ExportNameAdvisor" }, + { "__type__": "FpmathAdvisor" }, + { "__type__": "InitialMemoryAdvisor" }, + { "__type__": "InlineAsmAdvisor" }, + { "__type__": "RanlibAdvisor" }, + { "__type__": "SimdAdvisor" }, + { "__type__": "StripAdvisor" }, + { "__type__": "X86AsmAdvisor" } + ] + }, + { + "tag": "dep-build", + "advisors": [{ "__type__": "DepBuildAdvisor" }] + }, + { + "tag": "default", + "advisors": [{ "__type__": "ErrorsNotHandledAdvisor" }] + }, + { + "tag": "demo", + "advisors": [{ "__type__": "DemoAdvisor" }] + } + ] +} diff --git a/src/advisors/build_native_tool.ts b/src/advisors/build_native_tool.ts new file mode 100644 index 0000000..5cb9b4b --- /dev/null +++ b/src/advisors/build_native_tool.ts @@ -0,0 +1,119 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import * as H from "../helper"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class BuildNativeToolAdvisorFactory implements IAdvisorFactory { + name = "BuildNativeToolAdvisorFactory"; + desc = "Use this factory class to create BuildNativeToolAdvisor instance"; + + createAdvisor(): IAdvisor { + return new BuildNativeToolAdvisor(); + } +} + +class BuildNativeToolAdvisor implements IAdvisor { + static __type__ = "BuildNativeToolAdvisor"; + type = BuildNativeToolAdvisor.__type__; + desc = + "Advise issues related to build intermedium tools with native compiler other than Emscripten"; + + private async _fixBuildNativeToolErr( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + `The build process needs to build some tools to generate some intermedium files. These tools should be \`native\` binaries. You need to adopt native compiler/tool-chain (such as \`gcc\`) to build these tools. Otherwise, emscripten-built tools cannot work and will interrupt the build process.`, + null, + null + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for issue of building intermedium tools with native compiler other than Emscripten", + this, + req, + action + ), + }; + } + + private async _checkFileFormatNative(errLog: string): Promise { + let fileName = null; + let filePath = null; + let fullPath = null; + let cmd = null; + let tempIndex = 0; + const lines = errLog.split("\n"); + + for (let i = lines.length - 1; i >= 0; i--) { + if (lines[i].includes(": Permission denied")) { + fileName = lines[i] + .substring(lines[i].lastIndexOf("./") + 2, lines[i].indexOf(": Permission denied")) + .trim(); + tempIndex = i; + break; + } + } + + for (let i = tempIndex + 1; i < lines.length; i++) { + if (lines[i].includes("make[1]: Leaving directory")) { + filePath = lines[i].substring(lines[i].indexOf("'") + 1, lines[i].lastIndexOf("'")); + } + } + + if (filePath && fileName) { + fullPath = path.join(filePath, fileName); + } + + cmd = "file " + fullPath; + const results = await H.runCommand(cmd, { silent: true }); + if (results.code !== 0 && results.output.includes("ELF")) { + return true; + } + return false; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + errorReq.error.includes("Permission denied") && + !(await this._checkFileFormatNative(errorReq.error)).valueOf() + ) { + return this._fixBuildNativeToolErr(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(BuildNativeToolAdvisor.__type__, new BuildNativeToolAdvisorFactory()); +} diff --git a/src/advisors/build_path_validate.ts b/src/advisors/build_path_validate.ts new file mode 100644 index 0000000..c851a64 --- /dev/null +++ b/src/advisors/build_path_validate.ts @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import fs from "graceful-fs"; +import path from "path"; +import * as H from "../helper"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { isPrevBuildersAllNative } from "../builder"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class BuildPathValidateAdvisorFactory implements IAdvisorFactory { + name = "BuildPathValidateAdvisor"; + desc = "Use this factory class to create BuildPathValidateAdvisor instance"; + + createAdvisor(): IAdvisor { + return new BuildPathValidateAdvisor(); + } +} + +class BuildPathValidateAdvisor implements IAdvisor { + static __type__ = "BuildPathValidateAdvisor"; + type = BuildPathValidateAdvisor.__type__; + desc = "Advise issues related to invalid path"; + + private async _validateBuildPath( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + const results: H.Dict = {}; + + const builders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + if (builders && builders.length) { + const emptyPath: number[] = []; + const invalidBuildFile: number[] = []; + const outsideOfRoot: number[] = []; + const buildFileMap = new Map([ + ["CMakeBuilder", "CMakeLists.txt"], + ["ConfigureBuilder", "configure"], + ["MakeBuilder", "Makefile"], + ]); + const buildStepMap = new Map([ + ["CMakeBuilder", "CMake"], + ["ConfigureBuilder", "Configure"], + ["MakeBuilder", "Make"], + ["EmccBuilder", "emcc"], + ["NativeBuilder", "Native Command"], + ]); + for (let i = 0; i < builders.length; i++) { + const builder = builders[i]; + if (!builder.rootBuildFilePath) { + emptyPath.push(i); + continue; + } + const m = proj.validateTemplateLiterals(builder.rootBuildFilePath as string); + if (m.length) { + // invalid template literal used, bypass here as this will be taken care of by `TemplateLiteralValidateAdvisor` + continue; + } + const workingDir = proj.evalTemplateLiterals(builder.rootBuildFilePath as string); + + if (!fs.existsSync(workingDir)) { + invalidBuildFile.push(i); + continue; + } else { + if (buildFileMap.get(builder.__type__)) { + // builders with specified build file (cmake, configure and make) - check path for build file + if (!fs.existsSync(path.join(workingDir, buildFileMap.get(builder.__type__) || ""))) { + // build file path error - no such file + if (builder.__type__ === "MakeBuilder") { + // only check at pre-build for MakeBuilder if it's the first non-native builder + if (isPrevBuildersAllNative(proj, i)) { + invalidBuildFile.push(i); + continue; + } + } else { + invalidBuildFile.push(i); + continue; + } + } + } + } + + const relative = path.relative(proj.root, workingDir); + if (relative.startsWith("..") || path.isAbsolute(relative)) { + // build file path error - outside of project root + outsideOfRoot.push(i); + } + } + + const invalidBuildSteps: string[][] = []; + if (emptyPath.length) + emptyPath.forEach((idx) => { + invalidBuildSteps.push([ + `${idx + 1}`, + buildStepMap.get(builders[idx].__type__) || "", + `\`${builders[idx].rootBuildFilePath}\``, + "Empty working directory.", + ]); + }); + + if (invalidBuildFile.length) + invalidBuildFile.forEach((idx) => { + invalidBuildSteps.push([ + `${idx + 1}`, + buildStepMap.get(builders[idx].__type__) || "", + `\`${builders[idx].rootBuildFilePath}\``, + "Invalid working directory for build.", + ]); + }); + + if (outsideOfRoot.length) + outsideOfRoot.forEach((idx) => { + invalidBuildSteps.push([ + `${idx + 1}`, + buildStepMap.get(builders[idx].__type__) || "", + `\`${builders[idx].rootBuildFilePath}\``, + "Working directory is outside the project root.", + ]); + }); + + if (invalidBuildSteps.length) { + Object.assign(results, { + "Build Steps": H.constructMarkdownTable( + ["Build Step #", "Type", "Invalid Value", "Reason"], + invalidBuildSteps + ), + }); + } + } + + const preloads = proj.config.getBuildConfigForTarget(proj.config.target).preloadFiles; + if (preloads && preloads.length) { + const invalidPreloads: string[][] = []; + for (const p of preloads) { + const fileDir = p.split("@").shift()?.trim() || p; + if (proj.validateTemplateLiterals(fileDir).length) { + // handled in TemplateLiteralValidateAdvisor + continue; + } + const dir = proj.evalTemplateLiterals(fileDir); + if (!fs.existsSync(dir)) { + invalidPreloads.push([`\`${fileDir}\``, "File doesn't exist."]); + } + } + if (invalidPreloads.length) + Object.assign(results, { + "Local Data Files": H.constructMarkdownTable(["Files", "Reason"], invalidPreloads), + }); + } + + if (Object.keys(results).length) { + const descs = Object.keys(results) + .map((item) => { + let link = ""; + if (item === "Build Steps") link = `/buildSteps`; + else if (item === "Dependencies") link = `/basic`; + else link = `/config`; + return `[**_${item}_**](${link})\n${results[item]}`; + }) + .join("\n\n"); + const action = new ShowSuggestionAction( + "error", + `Below are the \`invalid\` paths we detected in project configuration:\n\n${descs}\n\nPlease modify them with correct ones.\n\n#\n\n Below are available template literals and their values for your reference:\n${proj + .getTemplateLiterals(true) + .map((t) => "- " + t) + .join("\n")}`, + null, + null + ); + return { + handled: true, + recipe: new Recipe(proj, "Recipe for invalid path in project config", this, req, action), + needPropagation: true, + }; + } + + return { + handled: false, + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + return this._validateBuildPath(proj, plainReq); + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(BuildPathValidateAdvisor.__type__, new BuildPathValidateAdvisorFactory()); +} diff --git a/src/advisors/build_step_validate.ts b/src/advisors/build_step_validate.ts new file mode 100644 index 0000000..6de08f4 --- /dev/null +++ b/src/advisors/build_step_validate.ts @@ -0,0 +1,93 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { findFirstBuilder } from "../builder"; +import { BuildStepChangeAction, BuildStepRegion } from "../actions/build_step_change"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + IBuilderJson, + Project as IProject, +} from "webinizer"; + +class BuildStepValidateAdvisorFactory implements IAdvisorFactory { + name = "BuildStepValidateAdvisorFactory"; + desc = "Use this factory class to create BuildStepValidateAdvisor instance"; + + createAdvisor(): IAdvisor { + return new BuildStepValidateAdvisor(); + } +} + +class BuildStepValidateAdvisor implements IAdvisor { + static __type__ = "BuildStepValidateAdvisor"; + type = BuildStepValidateAdvisor.__type__; + desc = "Advise issues related to invalid build file path"; + + private async _validateBuildSteps( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + // check if there is a 'clean' step before 'make' to ensure a clean build environment + const makeIdx = findFirstBuilder(proj, "MakeBuilder"); + const rawBuilders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + if (makeIdx >= 0 && rawBuilders) { + const builder = rawBuilders[makeIdx]; + if (!(builder.args as string).includes("clean")) { + // add action to insert an 'clean' step before actual make + const newBuilder: IBuilderJson = { + __type__: "MakeBuilder", + id: 0 /* set to default 0 as this will be re-set in next build*/, + desc: "Make", + args: "clean", + rootBuildFilePath: builder.rootBuildFilePath as string, + }; + const action = new BuildStepChangeAction( + proj, + "Add a `make clean` step before `make` to ensure a clean build environment.", + new BuildStepRegion(makeIdx), + [newBuilder] + ); + return { + handled: true, + recipe: new Recipe(proj, "Recipe for changing build steps", this, req, action, true), + needPropagation: true, + }; + } + } + return { + handled: false, + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if ( + req instanceof PlainAdviseRequest && + !proj.config.getBuildConfigForTarget(proj.config.target).getDisabledAdvisorFlag(this.type) + ) { + const plainReq = req as PlainAdviseRequest; + return this._validateBuildSteps(proj, plainReq); + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(BuildStepValidateAdvisor.__type__, new BuildStepValidateAdvisorFactory()); +} diff --git a/src/advisors/build_target_specify.ts b/src/advisors/build_target_specify.ts new file mode 100644 index 0000000..a6d0204 --- /dev/null +++ b/src/advisors/build_target_specify.ts @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class BuildTargetSpecifyAdvisorFactory implements IAdvisorFactory { + name = "BuildTargetSpecifyAdvisorFactory"; + desc = "Use this factory class to create BuildTargetSpecifyAdvisor instance"; + + createAdvisor(): IAdvisor { + return new BuildTargetSpecifyAdvisor(); + } +} + +class BuildTargetSpecifyAdvisor implements IAdvisor { + static __type__ = "BuildTargetSpecifyAdvisor"; + type = BuildTargetSpecifyAdvisor.__type__; + desc = "Advise issues related to host specification"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --enable-static\n --disable-cli`; + const after = `./configure\n --enable-static\n --disable-cli\n --host=i686-gnu`; + return new SuggestionExample(before, after); + } + + private async _generateBuildTargetSpecifyAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + "Please specify the build target as `32-bit` architecture while configuring the build, i.e., `x86_32`, `i686`, etc.", + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for build target specification issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errLogStr = "must specify -mwasm64 to process wasm64 object files"; + const errorReq = req as ErrorAdviseRequest; + if ( + (await H.findPatternInFiles(errLogStr, proj.root, [C.buildDir, C.dependencyDir])).length > 0 + ) { + return this._generateBuildTargetSpecifyAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory( + BuildTargetSpecifyAdvisor.__type__, + new BuildTargetSpecifyAdvisorFactory() + ); +} diff --git a/src/advisors/cc.ts b/src/advisors/cc.ts new file mode 100644 index 0000000..9a51079 --- /dev/null +++ b/src/advisors/cc.ts @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class CCompilerAdvisorFactory implements IAdvisorFactory { + name = "CCompilerAdvisorFactory"; + desc = "Use this factory class to create CCompilerAdvisor instance"; + + createAdvisor(): IAdvisor { + return new CCompilerAdvisor(); + } +} + +class CCompilerAdvisor implements IAdvisor { + static __type__ = "CCompilerAdvisor"; + type = CCompilerAdvisor.__type__; + desc = "Advise issues related to C compiler"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --target-os=none\n --arch=x86_32`; + const after = `./configure\n --target-os=none\n --arch=x86_32\n --cc=emcc`; + return new SuggestionExample(before, after); + } + + private async _fixCCompilerErr(proj: IProject, req: ErrorAdviseRequest): Promise { + const action = new ShowSuggestionAction( + "error", + `You're using \`gcc\` instead of \`emcc\`, which is a drop-in replacement for a standard compiler (like gcc or clang) to compile to WebAssembly. Please check if the build system has it hardcoded (i.e., cc_default="gcc"), or requires you to pass an option to specify \`emcc\` instead.`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for C Compiler issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + errorReq.error.includes("C compiler test failed") && + errorReq.error.includes("gcc is unable to create an executable file") + ) { + return this._fixCCompilerErr(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(CCompilerAdvisor.__type__, new CCompilerAdvisorFactory()); +} diff --git a/src/advisors/cpp_exception.ts b/src/advisors/cpp_exception.ts new file mode 100644 index 0000000..5cbfdbc --- /dev/null +++ b/src/advisors/cpp_exception.ts @@ -0,0 +1,148 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigOptionChangeAction } from "../actions/config_option_change"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("CppExceptionAdvisor"); + +class CppExceptionAdvisorFactory implements IAdvisorFactory { + name = "CppExceptionAdvisorFactory"; + desc = "Use this factory class to create CppExceptionAdvisor instance"; + + createAdvisor(): IAdvisor { + return new CppExceptionAdvisor(); + } +} + +class CppExceptionAdvisor implements IAdvisor { + static __type__ = "CppExceptionAdvisor"; + type = CppExceptionAdvisor.__type__; + desc = "Advise issues related to C++ exception handling"; + + private async _generateCppExceptionAdvise( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + const throwPattern = "throw "; // use keyword 'throw' as identifier for exception catching pattern + const fileExt = C.CXX_ENDINGS.concat(C.HEADER_ENDINGS); + const throwPatternUsed: string[] = []; + + const matched = await H.findPatternInFiles(throwPattern, proj.root, [ + C.buildDir, + C.dependencyDir, + ]); + if (matched.length) { + for (const m of matched) { + // FIXME. detect if this line is in a multi-line block comment + if ( + fileExt.includes(path.extname(m.file)) && + !m.content.trim().startsWith("//") && + !m.content.trim().startsWith("/*") + ) { + log.info( + `The line with throw pattern is in file ${m.file} @ line ${m.line}:\n${m.content}` + ); + throwPatternUsed.push( + `- [${m.file}](/edit?type=0&path=${encodeURIComponent( + path.join(proj.root, m.file) + )}&resourceType=file) at line **${m.line}**: \`${m.content}\`` + ); + } + } + } + + if ( + !throwPatternUsed.length && + proj.config.getBuildConfigForTarget(proj.config.target).getOption("needCppException") + ) { + // set option 'needCppException' to false + const action = new ConfigOptionChangeAction( + proj, + "We didn't detect C++ exception used in codebase, but it's enabled in project configuration for building phase, which might bring extra performance overhead. We recommend to disable `C++ exception` option if you don't want this feature.", + { needCppException: false } + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for C++ exception", + this, + req, + action, + true /* showNoAdvisor = true */ + ), + needPropagation: true, + }; + } + + if ( + throwPatternUsed.length && + !proj.config.getBuildConfigForTarget(proj.config.target).getOption("needCppException") + ) { + // set option 'needCppException' to true + const action = new ConfigOptionChangeAction( + proj, + `We detected C++ exception used in codebase, but it's disabled in project configuration for building phase, which will disable exception catching. We recommend to enable \`C++ exception\` option if you want this feature.\n${throwPatternUsed.join( + "\n" + )}`, + { needCppException: true } + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for C++ exception", + this, + req, + action, + true /* showNoAdvisor = true */ + ), + needPropagation: true, + }; + } + return { handled: true, needPropagation: true }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + // skip to run this advisor if disabledAdvisor flag is set from user. + if ( + !proj.config.getBuildConfigForTarget(proj.config.target).getDisabledAdvisorFlag(this.type) + ) { + return this._generateCppExceptionAdvise(proj, plainReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(CppExceptionAdvisor.__type__, new CppExceptionAdvisorFactory()); +} diff --git a/src/advisors/dep_build.ts b/src/advisors/dep_build.ts new file mode 100644 index 0000000..2430c07 --- /dev/null +++ b/src/advisors/dep_build.ts @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ShowDepRecipeAction } from "../actions/show_dep_recipe"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class DepBuildAdvisorFactory implements IAdvisorFactory { + name = "DepBuildAdvisorFactory"; + desc = "Use this factory class to create DepBuildAdvisor instance"; + + createAdvisor(): IAdvisor { + return new DepBuildAdvisor(); + } +} + +class DepBuildAdvisor implements IAdvisor { + static __type__ = "DepBuildAdvisor"; + type = DepBuildAdvisor.__type__; + desc = "Advisor to handle recipes generated from dependent projects build"; + + private async _generateRecipeForDepBuild( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + if (req.plainData) { + const action = new ShowDepRecipeAction( + "Recipes are generated for below dependent projects. Please go to the corresponding page of each dependent project for more details.", + Array.isArray(req.plainData) ? req.plainData : [req.plainData] + ); + return { + handled: true, + recipe: new Recipe(proj, "Recipes generated for dependent projects", this, req, action), + }; + } + return { + handled: false, + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + return this._generateRecipeForDepBuild(proj, plainReq); + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(DepBuildAdvisor.__type__, new DepBuildAdvisorFactory()); +} diff --git a/src/advisors/dep_check.ts b/src/advisors/dep_check.ts new file mode 100644 index 0000000..8191161 --- /dev/null +++ b/src/advisors/dep_check.ts @@ -0,0 +1,217 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import fs from "graceful-fs"; +import * as H from "../helper"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { FileChangeAction, FileRegion } from "../actions/file_change"; +import { ConfigEnvChangeAction } from "../actions/config_env_change"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { preloadFontFiles } from "./sdl"; +import { isPrevBuildersAllNative, findFirstBuilder } from "../builder"; +import { + IAction, + IArg, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +export async function generateEmPorts(): Promise> { + const ports = {} as H.Dict; // + const results = await H.runCommand("emcc --show-ports", { silent: true }); + if (results.code === 0) { + const lines = results.all.split("\n"); + const portReg = /(?.*) \(((?.*);)?.*\)/; + for (const line of lines) { + if (line.trim() !== "Available ports:") { + const m = line.trim().match(portReg); + if (m && m.groups) { + const pkgName = m.groups.pkg.toLowerCase().replace(/_/g, ""); + if (!Object.keys(ports).includes(pkgName)) { + if (m.groups.cmd) { + if (m.groups.cmd.trim().startsWith("-s")) { + ports[pkgName] = m.groups.cmd.trim().replace("-s", ""); + } else ports[pkgName] = m.groups.cmd; + } else { + switch (m.groups.pkg) { + case "SDL2_net": + ports[pkgName] = "USE_SDL_NET=2"; + break; + case "SDL2_gfx": + ports[pkgName] = "USE_SDL_GFX=2"; + break; + default: // no special handling for other libraries + } + } + } + } else if (line.trim() === "cocos2d") { + ports["cocos2d"] = "USE_COCOS2D=3"; + } + } + } + } + return ports; +} + +class DepCheckAdvisorFactory implements IAdvisorFactory { + name = "DepCheckAdvisorFactory"; + desc = "Use this factory class to create DepCheckAdvisor instance"; + + createAdvisor(): IAdvisor { + return new DepCheckAdvisor(); + } +} + +class DepCheckAdvisor implements IAdvisor { + static __type__ = "DepCheckAdvisor"; + type = DepCheckAdvisor.__type__; + desc = "Advise issues related to project dependencies"; + + private async _generateDepCheckAdviseForCMake( + proj: IProject, + req: PlainAdviseRequest, + emPorts: H.Dict + ): Promise { + // generate for CMake - find find_package( REQUIRED) pattern + const pkgReg = /find_package\((\s*)?(?\S*) .*REQUIRED.*\)/; + const actions = [] as IAction[]; + const nonPorts = [] as string[]; + const rawBuilders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + if (rawBuilders) { + const workingDir = ( + rawBuilders[findFirstBuilder(proj, "CMakeBuilder")].rootBuildFilePath as string + ).replace("${projectRoot}", proj.root); + const file = path.join(workingDir, "CMakeLists.txt"); + const relative = path.relative(proj.root, file); + if ( + fs.existsSync(file) && + relative && + !relative.startsWith("..") && + !path.isAbsolute(relative) + ) { + const lines = fs.readFileSync(file, "utf-8").split("\n"); + for (let i = 0; i < lines.length; i++) { + // ignore comment out lines + if (!lines[i].trim().startsWith("#")) { + const m = lines[i].match(pkgReg); + if (m && m.groups) { + // handle variants of the emPorts names: SDL2_ttf -> sdl2ttf, SDL2ttf, etc. + const pkgName = m.groups.pkg.toLowerCase().replace(/_/g, ""); + // dependent package is one of the emcc ports + if (Object.keys(emPorts).includes(pkgName)) { + // 1. remove find_package statement from CMakeLists.txt file + actions.push( + new FileChangeAction( + proj.fileChangeManager, + `Remove \`find_package()\` statement for \`${ + m.groups.pkg + }\` from \`CMakeLists.txt\` at line **${i + 1}**`, + new FileRegion(file, i + 1), + null + ) + ); + // 2. add related compiler and linker flags. + // TODO. add more knowledge on possible fixes of other ported libraries + const opt = "-s" + emPorts[pkgName].trim().split("=")[0]; + const val = emPorts[pkgName].trim().split("=")[1]; + const addCflags = [{ option: opt, value: val, type: "replace" }] as IArg[]; + const addLdflags = [{ option: opt, value: val, type: "replace" }] as IArg[]; + + if (pkgName === "sdl2ttf") { + // add flags for preload font files for SDL2ttf package + const ttfFontFix = await preloadFontFiles(proj); + ttfFontFix.opts.forEach((opt) => { + addLdflags.push({ option: opt, value: null, type: "replace" }); + }); + actions.push(...ttfFontFix.actions); + } + + actions.push( + new ConfigEnvChangeAction( + proj, + `Add compiler and linker flags to use Emscripten ported package of \`${m.groups.pkg}\``, + { + cflags: addCflags, + ldflags: addLdflags, + } + ) + ); + } else { + nonPorts.push(m.groups.pkg); + } + } + } + if (nonPorts.length > 0) + // show suggestion to user to build non EMCC ported dependent packages from source + actions.push( + new ShowSuggestionAction( + "option", + `We detect that your project depends on below requiured packages:\n${nonPorts.join( + ", " + )}\nHowever, we can't use native build versions of them. Instead, please build them from source with Webinizer first - add them to your dependent projects and then link them against the current main project.`, + null, + null + ) + ); + } + } + } + if (actions.length > 0) + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for checking project dependent packages", + this, + req, + actions, + true /* show no advisor */ + ), + needPropagation: true, + }; + return { handled: true, needPropagation: true }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + // skip to run this advisor if disabledAdvisor flag is set from user. + if ( + !proj.config.getBuildConfigForTarget(proj.config.target).getDisabledAdvisorFlag(this.type) + ) { + const emPorts = await generateEmPorts(); + const rawBuilders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + // FIXME. currently we only support checking for CMake file + if ( + rawBuilders && + ((rawBuilders[0].__type__ as string) === "CMakeBuilder" || + isPrevBuildersAllNative(proj, findFirstBuilder(proj, "CMakeBuilder"))) + ) { + return this._generateDepCheckAdviseForCMake(proj, plainReq, emPorts); + } + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(DepCheckAdvisor.__type__, new DepCheckAdvisorFactory()); +} diff --git a/src/advisors/errors_not_handled.ts b/src/advisors/errors_not_handled.ts new file mode 100644 index 0000000..03802e5 --- /dev/null +++ b/src/advisors/errors_not_handled.ts @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class ErrorsNotHandledAdvisorFactory implements IAdvisorFactory { + name = "ErrorsNotHandledAdvisorFactory"; + desc = "Use this factory class to create ErrorsNotHandledAdvisor instance"; + + createAdvisor(): IAdvisor { + return new ErrorsNotHandledAdvisor(); + } +} + +class ErrorsNotHandledAdvisor implements IAdvisor { + static __type__ = "ErrorsNotHandledAdvisor"; + type = ErrorsNotHandledAdvisor.__type__; + desc = "Default advisor for errors not handled by Webinizer"; + + private async _generateRecipeToShowErrors( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + `This error is \`not\` handled by Webinizer, please try to resolve it manually:\n\n\`\`\`${req.error}\`\`\``, + null, + req.location ? req.location.toFileRegion() : null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for errors not handled by Webinizer", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + return this._generateRecipeToShowErrors(proj, errorReq); + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(ErrorsNotHandledAdvisor.__type__, new ErrorsNotHandledAdvisorFactory()); +} diff --git a/src/advisors/export_name.ts b/src/advisors/export_name.ts new file mode 100644 index 0000000..5f3692f --- /dev/null +++ b/src/advisors/export_name.ts @@ -0,0 +1,107 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest, PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigEnvChangeAction } from "../actions/config_env_change"; +import { + IArg, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class ExportNameAdvisorFactory implements IAdvisorFactory { + name = "ExportNameAdvisorFactory"; + desc = "Use this factory class to create ExportNameAdvisor instance"; + + createAdvisor(): IAdvisor { + return new ExportNameAdvisor(); + } +} + +class ExportNameAdvisor implements IAdvisor { + static __type__ = "ExportNameAdvisor"; + type = ExportNameAdvisor.__type__; + desc = "Advise issues related to export name of wasm module"; + + private async _fixExportNameError( + proj: IProject, + req: ErrorAdviseRequest | PlainAdviseRequest + ): Promise { + const exportName = proj.config.name ? proj.config.name.replace(/\s/g, "") : "WebinizerProj"; + const action = new ConfigEnvChangeAction( + proj, + `Enable \`Pthreads + MODULARIZE\` currently require you to set \`-sEXPORT_NAME=Something\` to \`Something != Module\`. Specify the WASM module name as \`${exportName}\` (${ + exportName === "WebinizerProj" ? "default name as project name is not set" : "project name" + }) instead of the default \`Module\`.`, + { + ldflags: [ + { + option: "-sEXPORT_NAME", + value: exportName, + type: "replace", + }, + ] as IArg[], + } + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for exporting name of wasm module issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + // pre-build check + const plainReq = req as PlainAdviseRequest; + const buildConfig = proj.config.getBuildConfigForTarget(proj.config.target); + if ( + buildConfig.getOption("needPthread") && + buildConfig.getOption("needModularize") && + (!buildConfig.getEnv("ldflags").includes("-sEXPORT_NAME=") || + buildConfig.getEnv("ldflags").includes("-sEXPORT_NAME=Module")) + ) { + return this._fixExportNameError(proj, plainReq); + } + } + + if (req instanceof ErrorAdviseRequest) { + // build check + const errorReq = req as ErrorAdviseRequest; + if ( + ( + await H.findPatternInFiles( + "emcc: error: pthreads + MODULARIZE currently require you to set -sEXPORT_NAME=Something (see settings.js) to Something != Module, so that the .worker.js file can work", + proj.root, + [C.buildDir, C.dependencyDir] + ) + ).length > 0 + ) { + return this._fixExportNameError(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(ExportNameAdvisor.__type__, new ExportNameAdvisorFactory()); +} diff --git a/src/advisors/fpmath.ts b/src/advisors/fpmath.ts new file mode 100644 index 0000000..cdf3c45 --- /dev/null +++ b/src/advisors/fpmath.ts @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { FileChangeAction, FileRegion } from "../actions/file_change"; +import { + IAction, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class FpmathAdvisorFactory implements IAdvisorFactory { + name = "FpmathAdvisorFactory"; + desc = "Use this factory class to create FpmathAdvisor instance"; + + createAdvisor(): IAdvisor { + return new FpmathAdvisor(); + } +} + +class FpmathAdvisor implements IAdvisor { + static __type__ = "FpmathAdvisor"; + type = FpmathAdvisor.__type__; + desc = "Advise issues related to fpmath"; + + private _getSuggestionExample(): SuggestionExample { + const before = "-mfpmath=sse -msse -msse2"; + const after = "-msse -msse2"; + return new SuggestionExample(before, after); + } + + private async _generateFpmathAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const fileName = ["configure", "CMakeLists.txt", "Makefile"]; + const actions = [] as IAction[]; + + const matched = await H.findPatternInFiles("mfpmath=", proj.root, [ + C.buildDir, + C.dependencyDir, + ]); + if (matched.length) { + for (const m of matched) { + if (fileName.includes(m.file)) { + actions.push( + new FileChangeAction( + proj.fileChangeManager, + `Remove argument \`-mfpmath\` from \`${m.file}\` at line **${m.line}**`, + new FileRegion(path.join(proj.root, m.file), m.line), + m.content.replace(/-mfpmath=[^\s]*/gm, "") + ) + ); + } + } + } else { + // if we didn't find the flags setting in common configuration files, suggest the user to modify themselves. + actions.push( + new ShowSuggestionAction( + "error", + "Please remove all related '-mfpmath' compiler flags in your project.", + this._getSuggestionExample(), + null + ) + ); + } + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for fpmath issue", this, req, actions), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + (await H.findPatternInFiles("unknown FP unit", proj.root, [C.buildDir, C.dependencyDir])) + .length > 0 + ) { + return this._generateFpmathAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(FpmathAdvisor.__type__, new FpmathAdvisorFactory()); +} diff --git a/src/advisors/header_missing.ts b/src/advisors/header_missing.ts new file mode 100644 index 0000000..963665e --- /dev/null +++ b/src/advisors/header_missing.ts @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class HeaderMissingAdvisorFactory implements IAdvisorFactory { + name = "HeaderMissingAdvisorFactory"; + desc = "Use this factory class to create HeaderMissingAdvisor instance"; + + createAdvisor(): IAdvisor { + return new HeaderMissingAdvisor(); + } +} + +class HeaderMissingAdvisor implements IAdvisor { + static __type__ = "HeaderMissingAdvisor"; + type = HeaderMissingAdvisor.__type__; + desc = "Advise issues related to missing header files."; + + private async _generateHeaderMissingAdvise( + proj: IProject, + req: ErrorAdviseRequest, + errorMsg: string + ): Promise { + const searchStr = errorMsg.slice(errorMsg.indexOf("fatal error")); + const suggestionContent = `A header file is missing. There might be several reasons:\n +- The related library is \`not\` installed. You can search \`${searchStr}\` in Google and find out which library is missing. Note that the library should be built by emscripten. If this library has no emscripten-built precompiled binary available online, you could download the source code and try to build it with Webinizer. +- If the library has already been installed, then the reason may be that the header directory is not included in compiler/linker flags, please add \`-I\${HEADER_PATH}\` to compiler/linker flags while building.`; + const action = new ShowSuggestionAction( + "error", + `**Error log**\n\n\`\`\`${errorMsg}\`\`\`\n\n${suggestionContent}`, + null, + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for issue of missing header file", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + const lines = errorReq.error.split("\n"); + const headerMissReg = /fatal error: '.*.h' file not found/; + for (const line of lines) { + if (line.match(headerMissReg)) + return this._generateHeaderMissingAdvise(proj, errorReq, line); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(HeaderMissingAdvisor.__type__, new HeaderMissingAdvisorFactory()); +} diff --git a/src/advisors/initial_memory.ts b/src/advisors/initial_memory.ts new file mode 100644 index 0000000..17fcd04 --- /dev/null +++ b/src/advisors/initial_memory.ts @@ -0,0 +1,93 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigEnvChangeAction } from "../actions/config_env_change"; +import { + IArg, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class InitialMemoryAdvisorFactory implements IAdvisorFactory { + name = "InitialMemoryAdvisorFactory"; + desc = "Use this factory class to create InitialMemoryAdvisor instance"; + + createAdvisor(): IAdvisor { + return new InitialMemoryAdvisor(); + } +} + +class InitialMemoryAdvisor implements IAdvisor { + static __type__ = "InitialMemoryAdvisor"; + type = InitialMemoryAdvisor.__type__; + desc = "Advise issues related to initial memory"; + + private getNeededMemorySize(errStr: string): number { + const lines = errStr.split("\n"); + const sizeReg = /initial memory too small, (?.*) bytes needed/; + + for (let i = lines.length - 1; i > 0; i--) { + const m = lines[i].match(sizeReg); + if (m && m.groups) { + const required_size = m.groups.size.trim(); + return Math.pow(2, Math.ceil(Math.log2(Number(required_size)))); + } + } + return NaN; + } + + private async _fixInitMemoryTooSmallErr( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const needed_size = this.getNeededMemorySize(req.error); + // if we didn't get the needed_size from error log, set the size to maximum one 2GB + const set_size = needed_size ? needed_size : Number(2147483648); + const action = new ConfigEnvChangeAction( + proj, + `The initial amount of memory to use is too \`small\` for your application, we need to set it to \`${set_size}\` byte and allow memory growth at runtime.`, + { + ldflags: [ + { option: "-sINITIAL_MEMORY", value: `${set_size}`, type: "replace" }, + { option: "-sALLOW_MEMORY_GROWTH", value: "1", type: "replace" }, + ] as IArg[], + } + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for initial memory size issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if (errorReq.error.includes("initial memory too small")) { + return this._fixInitMemoryTooSmallErr(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(InitialMemoryAdvisor.__type__, new InitialMemoryAdvisorFactory()); +} diff --git a/src/advisors/inline_asm.ts b/src/advisors/inline_asm.ts new file mode 100644 index 0000000..2fb94dc --- /dev/null +++ b/src/advisors/inline_asm.ts @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class InlineAsmAdvisorFactory implements IAdvisorFactory { + name = "InlineAsmAdvisorFactory"; + desc = "Use this factory class to create InlineAsmAdvisor instance"; + + createAdvisor(): IAdvisor { + return new InlineAsmAdvisor(); + } +} + +class InlineAsmAdvisor implements IAdvisor { + static __type__ = "InlineAsmAdvisor"; + type = InlineAsmAdvisor.__type__; + desc = "Advise issues related to inline asm"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --target-os=none\n --arch=x86_32`; + const after = `./configure\n --target-os=none\n --arch=x86_32\n --disable-inline-asm`; + return new SuggestionExample(before, after); + } + + private async _generateInlineAsmAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + `Code with architecture-specific inline assembly (like an \`asm()\` containing x86 code) is not portable. That code would need to be replaced with portable C or C++.\nSometimes a codebase will have both portable code and optional inline assembly as an optimization, so you might find an option to disable the inline assembly (i.e., \`--disable-inline-asm\`).`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for inline assembly issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if (errorReq.error.includes("in asm")) { + return this._generateInlineAsmAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(InlineAsmAdvisor.__type__, new InlineAsmAdvisorFactory()); +} diff --git a/src/advisors/main_loop.ts b/src/advisors/main_loop.ts new file mode 100644 index 0000000..2bf4042 --- /dev/null +++ b/src/advisors/main_loop.ts @@ -0,0 +1,141 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("MainLoopAdvisor"); + +class MainLoopAdvisorFactory implements IAdvisorFactory { + name = "MainLoopAdvisorFactory"; + desc = "Use this factory class to create MainLoopAdvisor instance"; + + createAdvisor(): IAdvisor { + return new MainLoopAdvisor(); + } +} + +class MainLoopAdvisor implements IAdvisor { + static __type__ = "MainLoopAdvisor"; + type = MainLoopAdvisor.__type__; + desc = "Advise issues related to main loop"; + + private _getSuggestionExample(): SuggestionExample { + const before = ` +#include "game.h" + +int main() { + Game game; + while (game.loop()); + return 0; +}`; + const after = ` +#include "game.h" +#include + +int main() { + emscripten_set_main_loop( + []() { + static Game game; + game.loop(); + }, 0, 1); + return 0; +}`; + return new SuggestionExample(before, after); + } + + private async _generateMainLoopAdvise( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + const mainLoopAPIs = ["emscripten_set_main_loop", "emscripten_request_animation_frame_loop"]; + const fileExt = C.C_ENDINGS.concat(C.CXX_ENDINGS, C.HEADER_ENDINGS); + let isMainLoopAPIUsed = false; + for (const api of mainLoopAPIs) { + const matched = await H.findPatternInFiles(api, proj.root, [C.buildDir, C.dependencyDir]); + if (matched.length) { + for (const m of matched) { + // FIXME. detect if this line is in a multi-line block comment + if ( + !m.file.startsWith(C.dependencyDir) && + fileExt.includes(path.extname(m.file)) && + !m.content.trim().startsWith("//") && + !m.content.trim().startsWith("/*") + ) { + log.info( + `The line using emscripten main_loop API is in file ${m.file} @ line ${m.line}:\n${m.content}` + ); + isMainLoopAPIUsed = true; + break; + } + } + } + } + + if ( + !isMainLoopAPIUsed && + proj.config.getBuildConfigForTarget(proj.config.target).getOption("needMainLoop") + ) { + const action = new ShowSuggestionAction( + "option", + `Main loop implementation using Emscripten API is not detected. If you are using infinite loop in your application (i.e., for rendering / animation, etc.), please follow the example below to use [\`emscripten_set_main_loop()\`](https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop) API to modify. Otherwise, please click \`IGNORE\` to dismiss this recipe.`, + this._getSuggestionExample(), + null + ); + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for main loop issue", + this, + req, + action, + true /* showNoAdvisor = true */ + ), + needPropagation: true, + }; + } + + return { handled: true, needPropagation: true }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + // skip to run this advisor if disabledAdvisor flag is set from user. + if ( + !proj.config.getBuildConfigForTarget(proj.config.target).getDisabledAdvisorFlag(this.type) + ) { + return this._generateMainLoopAdvise(proj, plainReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(MainLoopAdvisor.__type__, new MainLoopAdvisorFactory()); +} diff --git a/src/advisors/make_target.ts b/src/advisors/make_target.ts new file mode 100644 index 0000000..e749b84 --- /dev/null +++ b/src/advisors/make_target.ts @@ -0,0 +1,108 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class MakeTargetAdvisorFactory implements IAdvisorFactory { + name = "MakeTargetAdvisorFactory"; + desc = "Use this factory class to create MakeTargetAdvisor instance"; + + createAdvisor(): IAdvisor { + return new MakeTargetAdvisor(); + } +} + +class MakeTargetAdvisor implements IAdvisor { + static __type__ = "MakeTargetAdvisor"; + type = MakeTargetAdvisor.__type__; + desc = "Advise issues related to make target"; + + private _getSuggestionExample(): SuggestionExample { + const before = `make`; + const after = `make -Csrc`; + return new SuggestionExample(before, after); + } + + private async _generateMakeTargetAdvise( + proj: IProject, + req: ErrorAdviseRequest, + target: string, + dir: string + ): Promise { + const action = new ShowSuggestionAction( + "error", + `You are failed to build the target \`${target}\` in directory \`${dir}\`, which seems to be not required for build.\nPlease specify a build directory or target to avoid such unnecessary builds (i.e., \`make -Csrc, make main_target\`).`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for make target issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + const lines = errorReq.error.split("\n"); + let i = 0; + let target = ""; + let dir = ""; + // General logic + // 1. find the failure build target that appears the first + // Example: make[3]: *** [gnuplot.gih] Error 126 + const targetReg = /make.*: \*\*\* \[(?.*)\] Error [0-9]*/; + for (i = 0; i < lines.length; i++) { + const m = lines[i].match(targetReg); + if (m && m.groups) { + target = m.groups.target.trim(); + break; + } + } + // 2. find the make directory of build target + // Example: make[3]: Entering directory '/home/work/projects/gnuplot-repos/gnuplot-5.4.3/docs' + const dirReg = /make.*: Entering directory '(?.*)'/; + for (let j = i - 1; j >= 0; j--) { + const m = lines[j].match(dirReg); + if (m && m.groups) { + dir = m.groups.dir.trim(); + break; + } + } + // 3. check if the make directory is a auxilliaryDir that is not necessary to build + // FIXME. extend the hardcode here to cover more cases + const auxilliaryDir = ["doc", "docs", "demo", "man", "test"]; + if (target && dir && auxilliaryDir.includes(path.relative(path.resolve(proj.root), dir))) { + return this._generateMakeTargetAdvise(proj, errorReq, target, dir); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(MakeTargetAdvisor.__type__, new MakeTargetAdvisorFactory()); +} diff --git a/src/advisors/pthread.ts b/src/advisors/pthread.ts new file mode 100644 index 0000000..15d17b2 --- /dev/null +++ b/src/advisors/pthread.ts @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import path from "path"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigOptionChangeAction } from "../actions/config_option_change"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("PThreadAdvisor"); + +class PThreadAdvisorFactory implements IAdvisorFactory { + name = "PThreadAdvisorFactory"; + desc = "Use this factory class to create PThreadAdvisor instance"; + + createAdvisor(): IAdvisor { + return new PThreadAdvisor(); + } +} + +class PThreadAdvisor implements IAdvisor { + static __type__ = "PThreadAdvisor"; + type = PThreadAdvisor.__type__; + desc = "Advise issues related to pthread"; + + private async _generatePThreadAdvise( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + const pthreadPattern = "#include "; // use keyword '#include ' as identifier for pthread usage pattern + const fileExt = C.C_ENDINGS.concat(C.CXX_ENDINGS, C.HEADER_ENDINGS); + const pthreadPatternUsed: string[] = []; + + const matched = await H.findPatternInFiles(pthreadPattern, proj.root, [ + C.buildDir, + C.dependencyDir, + ]); + if (matched.length) { + for (const m of matched) { + // FIXME. detect if this line is in a multi-line block comment + if ( + fileExt.includes(path.extname(m.file)) && + !m.content.trim().startsWith("//") && + !m.content.trim().startsWith("/*") + ) { + log.info(`The line using pthread is in file ${m.file} @ line ${m.line}:\n${m.content}`); + pthreadPatternUsed.push( + `- [${m.file}](/edit?type=0&path=${encodeURIComponent( + path.join(proj.root, m.file) + )}&resourceType=file) at line **${m.line}**: \`${m.content}\`` + ); + } + } + } + + if ( + !pthreadPatternUsed.length && + proj.config.getBuildConfigForTarget(proj.config.target).getOption("needPthread") + ) { + // set option 'needPthread' to false + const action = new ConfigOptionChangeAction( + proj, + "We didn't detect pthread usage in codebase, but it's enabled in project configuration for building phase. Do you want to disable the pthread support from webinizer?", + { needPthread: false } + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for pthread support", + this, + req, + action, + true /* showNoAdvisor = true */ + ), + needPropagation: true, + }; + } + + if ( + pthreadPatternUsed.length && + !proj.config.getBuildConfigForTarget(proj.config.target).getOption("needPthread") + ) { + // set option 'needPthread' to true + const action = new ConfigOptionChangeAction( + proj, + `We detected pthread usage in codebase, but it's disabled in project configuration for building phase. We recommend to enable \`Pthread\` option if you want this feature.\n${pthreadPatternUsed.join( + "\n" + )}`, + { needPthread: true } + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for pthread support", + this, + req, + action, + true /* showNoAdvisor = true */ + ), + needPropagation: true, + }; + } + return { handled: true, needPropagation: true }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + // skip to run this advisor if disabledAdvisor flag is set from user. + if ( + !proj.config.getBuildConfigForTarget(proj.config.target).getDisabledAdvisorFlag(this.type) + ) { + return this._generatePThreadAdvise(proj, plainReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(PThreadAdvisor.__type__, new PThreadAdvisorFactory()); +} diff --git a/src/advisors/ranlib.ts b/src/advisors/ranlib.ts new file mode 100644 index 0000000..16649eb --- /dev/null +++ b/src/advisors/ranlib.ts @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class RanlibAdvisorFactory implements IAdvisorFactory { + name = "RanlibAdvisorFactory"; + desc = "Use this factory class to create RanlibAdvisor instance"; + + createAdvisor(): IAdvisor { + return new RanlibAdvisor(); + } +} + +class RanlibAdvisor implements IAdvisor { + static __type__ = "RanlibAdvisor"; + type = RanlibAdvisor.__type__; + desc = "Advise issues related to ranlib"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --target-os=none\n --arch=x86_32`; + const after = `./configure\n --target-os=none\n --arch=x86_32\n --ranlib=emranlib`; + return new SuggestionExample(before, after); + } + + private async _fixRanlibErr(proj: IProject, req: ErrorAdviseRequest): Promise { + const action = new ShowSuggestionAction( + "error", + `You're using the system \`ranlib\` instead of \`emranlib\` (which calls llvm-ranlib).Please check if the build system has it hardcoded (i.e., ranlib_default="ranlib"), or requires you to pass an option to use \`emranlib\` instead.`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for ranlib issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + errorReq.error.includes("wasm-ld: error: ") && + errorReq.error.includes("archive has no index; run ranlib to add one") + ) { + return this._fixRanlibErr(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(RanlibAdvisor.__type__, new RanlibAdvisorFactory()); +} diff --git a/src/advisors/sdl.ts b/src/advisors/sdl.ts new file mode 100644 index 0000000..8042184 --- /dev/null +++ b/src/advisors/sdl.ts @@ -0,0 +1,366 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { FileRegion, FileChangeAction } from "../actions/file_change"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigEnvChangeAction } from "../actions/config_env_change"; +import path from "path"; +import fs from "graceful-fs"; +import { + IAction, + IArg, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +export async function preloadFontFiles( + proj: IProject +): Promise<{ opts: string[]; actions: IAction[] }> { + const preloadOpts: string[] = []; + const actions: IAction[] = []; + + const matchedFiles = H.matchFilePath("**/*(*.ttf|*.TTF)", proj.root, [C.dependencyDir]); + const fontFiles: H.Dict<{ fontPath: string; add: boolean }> = {}; + for (const f of matchedFiles) { + const fontName = path.basename(f); + if (Object.keys(fontFiles).includes(fontName)) break; + else { + fontFiles[fontName] = { fontPath: path.join("${projectRoot}", f), add: false }; + } + } + + // find TTF_OpenFont(...) in src files, and modify the font file names as below: + // 1. use file name directly -> no change + // 2. use a relative or absolute file path -> change to use just the file name + // 3. use variables/expressions to set the font file / can't find required font file + // -> ShowSuggestionAction to notify user + const patterns = await H.findPatternInFiles("TTF_OpenFont(", proj.root, [ + C.buildDir, + C.dependencyDir, + ]); + const fileExt = C.C_ENDINGS.concat(C.CXX_ENDINGS, C.HEADER_ENDINGS); + if (patterns.length) { + const re = /TTF_OpenFont\((?[^;]+),(?[^;]+)\)/; + for (const p of patterns) { + if (fileExt.includes(path.extname(p.file)) && !p.content.trim().startsWith("//")) { + // Suppose only one pattern match per line (for most cases) + const m = p.content.match(re); + if (m && m.groups) { + const fontFile = m.groups.fontLoc.trim(); + if (fontFile.startsWith('"') && fontFile.endsWith('"')) { + // fontLoc is a path or file name + const fontPath = fontFile.replace(/"/g, ""); + const font = path.basename(fontPath); + if (Object.keys(fontFiles).includes(font)) { + // add --preload-file to linker options if needed + if (!fontFiles[font].add) { + preloadOpts.push(`--preload-file ${fontFiles[font].fontPath}@/`); + fontFiles[font].add = true; + } + // change file if needed, ensure add preload options and change file are happening together + if (fontPath !== path.basename(fontPath)) { + actions.push( + new FileChangeAction( + proj.fileChangeManager, + `Update \`TTF_OpenFont()\` statement to use the font name directly instead of the path to it.`, + new FileRegion(path.join(p.rootDir, p.file), p.line), + p.content.replace(fontPath, path.basename(fontPath)) + ) + ); + } + } else { + actions.push( + new ShowSuggestionAction( + "error", + `Font file is \`not\` found, please ensure it's inside project directory.`, + null, + new FileRegion(path.join(p.rootDir, p.file), p.line) + ) + ); + } + } else { + actions.push( + new ShowSuggestionAction( + "error", + `Font file is set with expression in \`TTF_OpenFont()\`, please directly use font file name.`, + new SuggestionExample( + `font_ = TTF_OpenFont(font_file, 18);`, + `font_ = TTF_OpenFont("PressStart2P.ttf", 18);` + ), + new FileRegion(path.join(p.rootDir, p.file), p.line) + ) + ); + } + } + } + } + } + + return { opts: preloadOpts, actions: actions }; +} + +class SDLAdvisorFactory implements IAdvisorFactory { + name = "SDLAdvisorFactory"; + desc = "Use this factory class to create SDLAdvisor instance"; + + createAdvisor(): IAdvisor { + return new SDLAdvisor(); + } +} + +class SDLAdvisor implements IAdvisor { + static __type__ = "SDLAdvisor"; + type = SDLAdvisor.__type__; + desc = "Advise issues related to SDL"; + + private _getCMakeFixTemplate(linkerOpts: string[], pkg: string, ver?: number): string { + const fixTemplate = + `set(USE_FLAGS "-sUSE_${pkg}${ver ? "=" + ver : ""}")\n` + + 'set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${USE_FLAGS}")\n' + + 'set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${USE_FLAGS}")\n' + + 'set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${USE_FLAGS}' + + ` ${linkerOpts.join(" ")}` + + ' ")'; + return fixTemplate; + } + + private _format(content: string, location: FileRegion): string { + const fileData = fs.readFileSync(location.file, "utf-8"); + const lines = fileData.split("\n"); + let indent = 0; + + // search for the closest previous line with content and use that indention + for (let i = location.lineStart - 1; i > 0; i--) { + if (lines[i].trim().length > 0) { + for (const c of lines[i]) { + if (c === " ") indent++; + else break; + } + break; + } + } + if (indent) { + const f = content.split("\n").map((s) => " ".repeat(indent) + s); + return f.join("\n"); + } + + return content; + } + + private async _fixCMakeSDL2Missing( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + H.assert(req.location !== null, "No file location in the error"); + const actions = [] as IAction[]; + const location = req.location?.toFileRegion() as FileRegion; + location.file = path.join(proj.root, location.file); + // delete find_package() statement + actions.push( + new FileChangeAction( + proj.fileChangeManager, + `Remove \`find_package()\` statement for SDL2 from \`CMakeLists.txt\` at line **${location.lineStart}**`, + location, + null + ) + ); + // add emscripten flags + actions.push( + new ConfigEnvChangeAction( + proj, + `Add related compiler and linker flags to use Emscripten ported \`SDL2\` library.`, + { + cflags: [{ option: "-sUSE_SDL", value: "2", type: "replace" }], + ldflags: [{ option: "-sUSE_SDL", value: "2", type: "replace" }], + } + ) + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for SDL2 missing issue in CMake", this, req, actions), + }; + } + + private async _fixMakeSDL2OptionNotSet( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ConfigEnvChangeAction( + proj, + `Add related compiler and linker flags to use Emscripten ported \`SDL2\` library.`, + { + cflags: [{ option: "-sUSE_SDL", value: "2", type: "replace" }], + ldflags: [{ option: "-sUSE_SDL", value: "2", type: "replace" }], + } + ); + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for SDL2 related symbols undefined issue in Make", + this, + req, + action + ), + }; + } + + private async _fixSDL2ttfCore(proj: IProject): Promise { + const actions = [] as IAction[]; + const fixFontPreload = await preloadFontFiles(proj); + const addFlags = new ConfigEnvChangeAction( + proj, + `Add related compiler and linker flags to use Emscripten ported \`SDL2_ttf\` library and preload \`font files\` if any.`, + { + cflags: [{ option: "-sUSE_SDL_TTF", value: "2", type: "replace" }], + ldflags: [ + { option: "-sUSE_SDL_TTF", value: "2", type: "replace" }, + ...fixFontPreload.opts.map((o) => { + return { option: o, value: null, type: "replace" }; + }), + ] as IArg[], + } + ); + + actions.push(...[addFlags, ...fixFontPreload.actions]); + return actions; + } + + private async _fixCMakeSDL2ttfMissing( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + H.assert(req.location !== null, "No file location in the error"); + const actions: IAction[] = []; + const location = req.location?.toFileRegion() as FileRegion; + location.file = path.join(proj.root, location.file); + // delete find_package() statement + actions.push( + new FileChangeAction( + proj.fileChangeManager, + `Remove \`find_package()\` statement for \`SDL2_ttf\` from \`CMakeLists.txt\` at line **${location.lineStart}**`, + location, + null + ) + ); + // add emscripten flags + const addSDL2ttfFlags = await this._fixSDL2ttfCore(proj); + actions.push(...addSDL2ttfFlags); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for SDL2_ttf missing issue in CMake", this, req, actions), + }; + } + + private async _fixMakeSDL2ttfOptionNotSet( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const actions = await this._fixSDL2ttfCore(proj); + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for SDL2_ttf related symbols undefined issue in Make", + this, + req, + actions + ), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + // cmake error advices + if (errorReq.error.includes('not providing "FindSDL2.cmake"')) { + return this._fixCMakeSDL2Missing(proj, errorReq); + } + if ( + errorReq.error.includes("Could NOT find SDL2_ttf") || + errorReq.error.includes('not providing "FindSDL2_ttf.cmake"') + ) { + return this._fixCMakeSDL2ttfMissing(proj, errorReq); + } + + // make error advices + const SDLFuncSymbols = fs.readFileSync("files/SDL2_API.txt", "utf-8").split("\n"); + // TODO. below is just a limited set of APIs, maybe we should read APIs from file instead + const ttfFuncSymbols = [ + // freetype APIs + "FT_Done_Face", + "FT_Done_FreeType", + "FT_Done_Glyph", + "FT_Get_Glyph", + "FT_Glyph_Stroke", + "FT_Glyph_To_Bitmap", + "FT_Init_FreeType", + "FT_Load_Glyph", + "FT_MulFix", + "FT_Open_Face", + "FT_Outline_Transform", + "FT_Outline_Translate", + "FT_Render_Glyph", + "FT_Select_Size", + "FT_Set_Char_Size", + "FT_Set_Charmap", + "FT_Stroker_Done", + "FT_Stroker_New", + "FT_Stroker_Set", + // harfbuzz APIs + "hb_buffer_add_utf8", + "hb_buffer_create", + "hb_buffer_destroy", + "hb_buffer_get_glyph_infos", + "hb_buffer_get_glyph_positions", + "hb_buffer_set_direction", + "hb_buffer_set_script", + "hb_font_destroy", + "hb_ft_font_changed", + "hb_ft_font_create", + "hb_ft_font_set_load_flags", + "hb_shape", + ]; + const lines = errorReq.error.split("\n"); + const re = + /error: undefined symbol: (?.*) \(referenced by top-level compiled C\/C\+\+ code\)/; + for (const line of lines) { + const m = line.match(re); + if (m && m.groups) { + if (SDLFuncSymbols.includes(m.groups.func.trim())) + // SDL2 port in cache but option -sUSE_SDL=2 is not set + return this._fixMakeSDL2OptionNotSet(proj, errorReq); + if (ttfFuncSymbols.includes(m.groups.func.trim())) + // SDL2_ttf port in cache but option -sUSE_SDL_TTF=2 is not set + return this._fixMakeSDL2ttfOptionNotSet(proj, errorReq); + } + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(SDLAdvisor.__type__, new SDLAdvisorFactory()); +} diff --git a/src/advisors/simd.ts b/src/advisors/simd.ts new file mode 100644 index 0000000..5d93869 --- /dev/null +++ b/src/advisors/simd.ts @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ConfigOptionChangeAction } from "../actions/config_option_change"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class SimdAdvisorFactory implements IAdvisorFactory { + name = "SimdAdvisorFactory"; + desc = "Use this factory class to create SimdAdvisor instance"; + + createAdvisor(): IAdvisor { + return new SimdAdvisor(); + } +} + +class SimdAdvisor implements IAdvisor { + static __type__ = "SimdAdvisor"; + type = SimdAdvisor.__type__; + desc = "Advise issues related to SIMD"; + + private async _generateSimdAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ConfigOptionChangeAction( + proj, + "If you want to port `SIMD` code targeting WebAssembly, we should enable the `SIMD support` option.", + { needSimd: true } + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for SIMD issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const ErrlogStr = + "emcc: error: Passing any of -msse, -msse2, -msse3, -mssse3, -msse4.1, -msse4.2, -msse4, -mavx, -mfpu=neon flags also requires passing -msimd128!"; + const errorReq = req as ErrorAdviseRequest; + if ( + (await H.findPatternInFiles(ErrlogStr, proj.root, [C.buildDir, C.dependencyDir])).length > 0 + ) { + return this._generateSimdAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(SimdAdvisor.__type__, new SimdAdvisorFactory()); +} diff --git a/src/advisors/strip.ts b/src/advisors/strip.ts new file mode 100644 index 0000000..a2d9ef1 --- /dev/null +++ b/src/advisors/strip.ts @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class StripAdvisorFactory implements IAdvisorFactory { + name = "StripAdvisorFactory"; + desc = "Use this factory class to create StripAdvisor instance"; + + createAdvisor(): IAdvisor { + return new StripAdvisor(); + } +} + +class StripAdvisor implements IAdvisor { + static __type__ = "StripAdvisor"; + type = StripAdvisor.__type__; + desc = "Advise issues related to file strip"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --target-os=none\n --arch=x86_32`; + const after = `./configure\n --target-os=none\n --arch=x86_32\n --disable-stripping`; + return new SuggestionExample(before, after); + } + + private async _generateStripAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + "Native tools such as `GNU strip` are not aware of the WebAssembly object format and cannot create archive indexes. Please disable strip if possible.", + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for strip issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + const lines = errorReq.error.split("\n"); + const stripReg = /strip:.* (File|file) format not recognized/; + for (const line of lines) { + if (line.match(stripReg)) return this._generateStripAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(StripAdvisor.__type__, new StripAdvisorFactory()); +} diff --git a/src/advisors/template_literal_validate.ts b/src/advisors/template_literal_validate.ts new file mode 100644 index 0000000..7647691 --- /dev/null +++ b/src/advisors/template_literal_validate.ts @@ -0,0 +1,171 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { PlainAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { + EnvType, + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class TemplateLiteralValidateAdvisorFactory implements IAdvisorFactory { + name = "TemplateLiteralValidateAdvisorFactory"; + desc = "Use this factory class to create TemplateLiteralValidateAdvisor instance"; + + createAdvisor(): IAdvisor { + return new TemplateLiteralValidateAdvisor(); + } +} + +class TemplateLiteralValidateAdvisor implements IAdvisor { + static __type__ = "TemplateLiteralValidateAdvisor"; + type = TemplateLiteralValidateAdvisor.__type__; + desc = "Advise issues related to invalid template literals"; + + private async _validateTemplateLiterals( + proj: IProject, + req: PlainAdviseRequest + ): Promise { + const results: H.Dict = {}; + const buildConfig = proj.config.getBuildConfigForTarget(proj.config.target); + const builders = buildConfig.rawBuilders; + if (builders && builders.length) { + const invalidSteps: string[][] = []; + for (let i = 0; i < builders.length; i++) { + const b = builders[i]; + // check args and working directory + const validateArgs = proj.validateTemplateLiterals(b.args as string); + const validatePath = proj.validateTemplateLiterals(b.rootBuildFilePath as string); + if (validateArgs.length) { + invalidSteps.push([ + `**${i + 1}**`, + "Arguments", + `${validateArgs.map((p) => `\`${p}\``).join(", ")}`, + ]); + } + if (validatePath.length) { + invalidSteps.push([ + `**${i + 1}**`, + "Working directory", + `${validatePath.map((p) => `\`${p}\``).join(", ")}`, + ]); + } + } + if (invalidSteps.length) { + Object.assign(results, { + "Build Steps": H.constructMarkdownTable( + ["Build Step #", "Invalid Config", "Invalid Values"], + invalidSteps + ), + }); + } + } + + const envs = buildConfig.envs; + if (envs) { + const invalidEnvs: string[][] = []; + for (const e in envs) { + const validation = proj.validateTemplateLiterals(envs[e as EnvType]); + if (validation.length) { + invalidEnvs.push([ + `${e === "cflags" ? "Compiler flags" : "Linker flags"}`, + validation.map((e) => `\`${e}\``).join(", "), + ]); + } + } + if (invalidEnvs.length) { + Object.assign(results, { + "Environment Variables": H.constructMarkdownTable( + ["Environment Variables", "Invalid Values"], + invalidEnvs + ), + }); + } + } + + const preloads = buildConfig.preloadFiles; + if (preloads && preloads.length) { + const invalidPreload: string[][] = []; + for (const p of preloads) { + const validation = proj.validateTemplateLiterals(p); + if (validation.length) { + invalidPreload.push([`${p}`, validation.map((f) => `\`${f}\``).join(", ")]); + } + } + if (invalidPreload.length) { + Object.assign(results, { + "Local Data Files": H.constructMarkdownTable(["Files", "Invalid Values"], invalidPreload), + }); + } + } + + if (Object.keys(results).length) { + const descs = Object.keys(results) + .map((item) => { + let link = ""; + if (item === "Build Steps") link = `/buildSteps`; + else if (item === "Dependencies") link = `/basic`; + else link = `/config`; + return `[**_${item}_**](${link})\n${results[item]}`; + }) + .join("\n\n"); + const action = new ShowSuggestionAction( + "error", + `Below are the \`invalid\` template literals we detected in project configuration:\n\n${descs}\n\n#\n\nYou can refer to below available template literals to modify accordingly:\n${proj + .getTemplateLiterals(true) + .map((t) => `- ${t}`) + .join("\n")}`, + null, + null + ); + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for invalid template literals in project config", + this, + req, + action + ), + needPropagation: true, + }; + } + + return { + handled: false, + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof PlainAdviseRequest) { + const plainReq = req as PlainAdviseRequest; + return this._validateTemplateLiterals(proj, plainReq); + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory( + TemplateLiteralValidateAdvisor.__type__, + new TemplateLiteralValidateAdvisorFactory() + ); +} diff --git a/src/advisors/test_target_error.ts b/src/advisors/test_target_error.ts new file mode 100644 index 0000000..2cc4f57 --- /dev/null +++ b/src/advisors/test_target_error.ts @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { registerAdvisorFactory } from "../advisor"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { ShowSuggestionAction } from "../actions/show_suggestion"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class TestTargetErrorAdvisorFactory implements IAdvisorFactory { + name = "TestTargetErrorAdvisorFactory"; + desc = "Use this factory class to create TestTargetErrorAdvisor instance"; + + createAdvisor(): IAdvisor { + return new TestTargetErrorAdvisor(); + } +} + +class TestTargetErrorAdvisor implements IAdvisor { + static __type__ = "TestTargetErrorAdvisor"; + type = TestTargetErrorAdvisor.__type__; + desc = "Advise issues related to errors while building test targets with emscripten."; + + private async _fixTestTargetErr(proj: IProject, req: ErrorAdviseRequest): Promise { + const action = new ShowSuggestionAction( + "error", + `Most test related targets are aimed to build&execute with native compiler/environment and probably have errors while building with emscripten. + You'd better remove/comment out these targets in Makefile to make the whole build process succeed.`, + null, + null + ); + + return { + handled: true, + recipe: new Recipe( + proj, + "Recipe for issue of errors while building test targets with emscripten", + this, + req, + action + ), + }; + } + + private _isLeavingTestDir(errLog: string, projRoot: string): boolean { + const lines = errLog.split("\n"); + let tempIndex = -1; + + for (let i = lines.length - 1; i > 0; i--) { + if (lines[i].includes("Leaving directory")) { + tempIndex = i; + break; + } + } + + if ( + tempIndex > 0 && + lines[tempIndex] + .slice(projRoot.length, lines[tempIndex].length) + .toLowerCase() + .includes("test") + ) { + return true; + } + + return false; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + errorReq.error.includes("emmake: error:") && + this._isLeavingTestDir(errorReq.error, proj.root) + ) { + return this._fixTestTargetErr(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(TestTargetErrorAdvisor.__type__, new TestTargetErrorAdvisorFactory()); +} diff --git a/src/advisors/x86asm.ts b/src/advisors/x86asm.ts new file mode 100644 index 0000000..e407209 --- /dev/null +++ b/src/advisors/x86asm.ts @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as C from "../constants"; +import { registerAdvisorFactory } from "../advisor"; +import { ShowSuggestionAction, SuggestionExample } from "../actions/show_suggestion"; +import { Recipe } from "../recipe"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { + IAdviseRequest, + IAdviseResult, + IAdvisorFactory, + IAdvisor, + Project as IProject, +} from "webinizer"; + +class X86AsmAdvisorFactory implements IAdvisorFactory { + name = "X86AsmAdvisorFactory"; + desc = "Use this factory class to create X86AsmAdvisor instance"; + + createAdvisor(): IAdvisor { + return new X86AsmAdvisor(); + } +} + +class X86AsmAdvisor implements IAdvisor { + static __type__ = "X86AsmAdvisor"; + type = X86AsmAdvisor.__type__; + desc = "Advise issues related to x86asm"; + + private _getSuggestionExample(): SuggestionExample { + const before = `./configure\n --target-os=none\n --arch=x86_32`; + const after = `./configure\n --target-os=none\n --arch=x86_32\n --disable-x86asm`; + return new SuggestionExample(before, after); + } + + private async _generateAsmAdvise( + proj: IProject, + req: ErrorAdviseRequest + ): Promise { + const action = new ShowSuggestionAction( + "error", + `Emscripten does \`not\` support \`x86 SIMD assembly\`, all code should be written to use SIMD intrinsic functions or compiler vector extensions. Otherwise it would need to be replaced with portable C or C++.\nSometimes a codebase will have both portable code and optional architectures-specific assembly as an optimization, so you might find an option to disable it (i.e., \`--disable-x86asm\`, \`--disable-asm\`).`, + this._getSuggestionExample(), + null + ); + + return { + handled: true, + recipe: new Recipe(proj, "Recipe for asm issue", this, req, action), + }; + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + async advise( + proj: IProject, + req: IAdviseRequest, + requestList: ReadonlyArray // one can only return newRequestQueue to change it + ): Promise { + if (req instanceof ErrorAdviseRequest) { + const errorReq = req as ErrorAdviseRequest; + if ( + errorReq.error.includes("nasm/yasm not found or too old.") || + ( + await H.findPatternInFiles("nasm: command not found", proj.root, [ + C.buildDir, + C.dependencyDir, + ]) + ).length > 0 + ) { + return this._generateAsmAdvise(proj, errorReq); + } + } + return { + handled: false, + }; + } +} + +// loading +export default function onload() { + registerAdvisorFactory(X86AsmAdvisor.__type__, new X86AsmAdvisorFactory()); +} diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..00e747a --- /dev/null +++ b/src/api.ts @@ -0,0 +1,548 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "./helper"; +import * as C from "./constants"; +import fs from "graceful-fs"; +import writeFileAtomic from "write-file-atomic"; +import path from "path"; +import { buildDirTree, IDtreeJson } from "./dtree"; +import { Project, ProjectConfig, ProjectResult } from "./project"; +import { IProjectProfile } from "./project_profiles"; +import { recipeArrayFromJson, type Recipe } from "./recipe"; +import { ALL_BUILDER_FACTORIES } from "./builder"; +import { buildStatus, type StatusType } from "./status"; +import errorCode from "./error_code"; +import { handleUploadProject, cloneProject, fetchProjectFromRegistry } from "./create_project"; +import { deleteProjectSoftly } from "./delete_project"; +import { getProfilesFromDetection } from "./project_profiles"; +import { search as searchPackage, IPackageSearchResult } from "./package_manager/search"; +import { Settings } from "./settings"; +import { EnvType, BuildOptionType, IJsonObject, IBuilder } from "webinizer"; + +const log = H.getLogger("api"); + +function validateProjectRoot(root: string) { + if (!root) { + throw new H.WError("Project root path can't be empty.", errorCode.WEBINIZER_ROOT_EMPTY); + } + if (!fs.existsSync(root)) { + throw new H.WError("Project root path doesn't exist.", errorCode.WEBINIZER_ROOT_NOEXT); + } +} + +export async function resetBuildStatus(root: string, hardReset = false) { + // expose this method from Project class for direct calls from the server layer + validateProjectRoot(root); + const proj = new Project(root); + await proj.resetBuildStatus(hardReset); +} + +export function getProjectProfilesFromDetection(projectPoolDir?: string): IProjectProfile[] { + return getProfilesFromDetection(projectPoolDir); +} + +export function getProjectConfig(root: string): ProjectConfig { + validateProjectRoot(root); + const proj = new Project(root); + return proj.config; +} + +export async function updatePartOfProjectConfig( + root: string, + configPart: H.Dict +): Promise { + validateProjectRoot(root); + const proj = new Project(root); + let needActualUpdate = false; + let needCreateBuildTargetsField = false; + let needUpdateBuildTargets = false; + const configJson = proj.config.toJson(); + + for (const k in configPart) { + if (Object.keys(configJson).includes(k)) { + // to-be-updated part is in current proj.config, compare and update + // wrap the value with a temp object to do the comparison + const diff = H.getObjDifference( + { [k]: configJson[k] }, + { [k]: configPart[k] } + ) as H.Dict; + if (Object.keys(diff).length) { + if (!needActualUpdate) needActualUpdate = true; + if (k === "buildTargets") needUpdateBuildTargets = true; + } + } else { + // to-be-updated part is not in current proj.config, update directly + if (!needActualUpdate) needActualUpdate = true; + if (k === "buildTargets") { + needCreateBuildTargetsField = true; + needUpdateBuildTargets = true; + } + } + } + if (needActualUpdate) { + log.info("... actual update on project config"); + await proj.resetBuildStatus(); + const needBackupDepsDir = Object.keys(configPart).includes("dependencies") ? true : false; + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + // backup the dependency folder if needed + if (needBackupDepsDir) proj.backupDependencyDir(); + if (needUpdateBuildTargets) { + // configPart includes update on `buildTargets`, update `buildTarget` separately + // then update rest configs without `buildTarget` + if (needCreateBuildTargetsField) { + proj.config.updateRawJson({ buildTargets: {} }); + } + await updateProjectBuildConfig(root, configPart["buildTargets"] as H.Dict); + const configWithoutBuildTargets = Object.assign({}, configPart); + delete configWithoutBuildTargets.buildTargets; + await proj.config.updateRawJson(configWithoutBuildTargets); + } else { + // configPart has no update on `buildTargets`, simply update + await proj.config.updateRawJson(configPart); + } + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + // restore dependency folder if needed + if (needBackupDepsDir) { + if ((err as H.WError).name === "WEBINIZER_DIR_COPY_FAIL") { + // if the failure was happened at the backup dependency directory stage, just clean the backup folder only + proj.cleanDependencyDirBackup(); + } else { + proj.restoreDependencyDir(); + } + } + throw err; + } finally { + // cleanup the backup files in last step + proj.cleanBackupFiles(); + if (needBackupDepsDir) proj.cleanDependencyDirBackup(); + } + } + + return proj.config; +} + +export async function resetProjectConfig(root: string): Promise { + validateProjectRoot(root); + const proj = new Project(root); + await proj.resetBuildStatus(); + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + proj.config.getBuildConfigForTarget(proj.config.target).resetBuildConfig(); + proj.cleanBackupFiles(); + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } + return proj.config; +} + +export async function updateProjectBuildConfig( + root: string, + config: H.Dict +): Promise { + validateProjectRoot(root); + const proj = new Project(root); + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + for (const target in config) { + const buildConfigToUpdate = config[target] as H.Dict; + const buildConfigJson = proj.config.getRawBuildConfigForTarget(target); + if (buildConfigJson === undefined) { + // to create a new target + await proj.resetBuildStatus(); + proj.config.setRawBuildConfigForTarget(target, buildConfigToUpdate); + proj.config.getBuildConfigForTarget(target).updateBuildConfig(buildConfigToUpdate); + } else { + // to update a current target + // const buildConfigJson = proj.config.getRawBuildConfigForTarget(target); + let needActualUpdate = false; + let updateEnvParts: EnvType[] | undefined = undefined; + let updateOptParts: BuildOptionType[] | undefined = undefined; + + for (const k in buildConfigToUpdate) { + if (Object.keys(buildConfigJson).includes(k)) { + // to-be-updated part is in current proj.config.buildTargets.[target], compare and update + // wrap the value with a temp object to do the comparison + const diff = H.getObjDifference( + { [k]: buildConfigJson[k] }, + { [k]: buildConfigToUpdate[k] } + ) as H.Dict; + if (Object.keys(diff).length) { + if (!needActualUpdate) needActualUpdate = true; + if (k === "envs") + updateEnvParts = Object.keys( + diff[Object.keys(diff)[0]] as H.Dict + ) as EnvType[]; + else if (k === "options") + updateOptParts = Object.keys( + diff[Object.keys(diff)[0]] as H.Dict + ) as BuildOptionType[]; + } + } else { + // to-be-updated part is not in current proj.config, update directly + if (!needActualUpdate) needActualUpdate = true; + } + } + if (needActualUpdate) { + log.info(`... actual update on project config for target ${target}`); + await proj.resetBuildStatus(); + const buildConfig = proj.config.getBuildConfigForTarget(target); + buildConfig.updateBuildConfig(buildConfigToUpdate, { updateEnvParts, updateOptParts }); + } + } + } + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } finally { + // cleanup the backup files in last step + proj.cleanBackupFiles(); + } + return proj.config; +} + +export async function updateOverallEnvsFromDeps(root: string): Promise { + validateProjectRoot(root); + const proj = new Project(root); + await proj.resetBuildStatus(); + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + await proj.config.updateOverallEnvsFromDeps(); + proj.cleanBackupFiles(); + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } + return proj.config; +} + +export function recommendBuildersToUse(root: string): IBuilder[] { + validateProjectRoot(root); + const proj = new Project(root); + return proj.recommendBuildersToUse(); +} + +export function getAllBuilders(root: string): IBuilder[] { + validateProjectRoot(root); + const proj = new Project(root); + const builders: IBuilder[] = []; + + for (const bf of ALL_BUILDER_FACTORIES.factoriesMap().values()) { + builders.push(bf.createDefault(proj)); + } + + return builders; +} + +export async function disableAdvisorToUse(root: string, advisor: string): Promise { + validateProjectRoot(root); + const proj = new Project(root); + await proj.resetBuildStatus(); + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + proj.config.getBuildConfigForTarget(proj.config.target).setDisabledAdvisorFlag(advisor, true); + proj.cleanBackupFiles(); + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } + return proj.config; +} + +export async function resetAdvisors(root: string): Promise { + validateProjectRoot(root); + const proj = new Project(root); + await proj.resetBuildStatus(); + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + proj.config.getBuildConfigForTarget(proj.config.target).resetAdvisors(); + proj.cleanBackupFiles(); + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } + return proj.config; +} + +export async function build(root: string, r: IJsonObject[] | null): Promise { + validateProjectRoot(root); + // we create a brand new project everytime + const proj = new Project(root); + const recipes = r ? recipeArrayFromJson(proj, r) : null; + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + // build with recipes + const res = await proj.build(recipes); + // cleanup the backup files + proj.cleanBackupFiles(); + return res; + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + throw err; + } +} + +export function getRecipes(root: string): IJsonObject[] { + validateProjectRoot(root); + const proj = new Project(root); + return proj.recipe.toJson().recipes as IJsonObject[]; +} + +export async function getFileContent(root: string, name: string): Promise { + validateProjectRoot(root); + if (!fs.existsSync(name)) { + throw new H.WError(`File doesn't exist.`, errorCode.WEBINIZER_FILE_NOEXT); + } + const relative = path.relative(root, name); + if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) { + // check file type before reading it, throw error for unsupported file format (binary, etc...) + const fileType = await H.runCommand(`file -b ${name}`, { silent: true }); + if ( + fileType.code === 0 && + (fileType.all.includes("ASCII text") || + fileType.all.includes("UTF-8 Unicode text") || + fileType.all.includes("JSON data") || + fileType.all.includes("empty")) + ) { + return fs.readFileSync(name, "utf-8"); + } else if (fileType.code === 0 && fileType.all.includes("symbolic link to")) { + // handle file redirection with symbolic link + const redir = fileType.all.match(/symbolic link to (?[\S]*)/); + if (redir && redir.groups) { + return getFileContent(root, path.join(path.dirname(name), redir.groups.dir)); + } + throw new H.WError( + `File is symbolic link to an unknown file.`, + errorCode.WEBINIZER_FILE_UNKNOWN_SYMBOLIC + ); + } else { + throw new H.WError( + "Can't open file because it is either binary or uses an unsupported text encoding.", + errorCode.WEBINIZER_FILE_UNSUPPORTED_ENCODING + ); + } + } else { + throw new H.WError( + `File is outside the project root and cannot be accessed.`, + errorCode.WEBINIZER_FILE_OUTSIDE_ROOT + ); + } +} + +export async function updateFileContent( + root: string, + name: string, + content: string +): Promise { + validateProjectRoot(root); + const proj = new Project(root); + if (!fs.existsSync(name)) { + throw new H.WError(`File doesn't exist.`, errorCode.WEBINIZER_FILE_NOEXT); + } + // config.json is readonly + if (name === proj.config.path) { + throw new H.WError( + `File ${path.basename(name)} is readonly.`, + errorCode.WEBINIZER_FILE_READONLY + ); + } + // files from dependency project is readonly + const relativeToDeps = path.relative(path.join(root, C.dependencyDir), name); + if (relativeToDeps && !relativeToDeps.startsWith("..") && !path.isAbsolute(relativeToDeps)) { + throw new H.WError( + `File ${path.basename(name)} is from dependency project and readonly.`, + errorCode.WEBINIZER_FILE_READONLY + ); + } + // update package metadata file, do validation before actually updating it + if (name === proj.meta.path) { + if (content === fs.readFileSync(name, "utf-8")) { + // no config update, skip validations and return + return content; + } + let metaToUpdate: H.Dict = {}; + try { + metaToUpdate = JSON.parse(content); + } catch (err) { + throw new H.WError( + `Failed to parse ${path.basename(name)} content due to error:\n${(err as Error).message}`, + errorCode.WEBINIZER_META_PARSE_FAILED + ); + } + // apply metadata schema validation + proj.meta.validateMetaSchema(metaToUpdate); + await proj.resetBuildStatus(); + const diffContent = H.getObjDifference(proj.meta.data, metaToUpdate); + const needBackupDepsDir = Object.keys(diffContent).includes("dependencies") ? true : false; + try { + // backup meta and config files before updating configs + proj.backupConfigFiles(); + // backup the dependency folder if needed + if (needBackupDepsDir) proj.backupDependencyDir(); + // handle metadata update + await proj.meta.updateMetaAndConfig(metaToUpdate); + // cleanup the backup files and dependency folder if needed + proj.cleanBackupFiles(); + if (needBackupDepsDir) proj.cleanDependencyDirBackup(); + return fs.readFileSync(name, "utf8"); + } catch (err) { + // errors happened during configs update, restore meta and config before update + proj.restoreConfigsFromBackupFiles(); + // restore the dependency folder if needed + if (needBackupDepsDir) { + if ((err as H.WError).name === "WEBINIZER_DIR_COPY_FAIL") { + // if the failure was happened at the backup dependency directory stage, just clean the backup folder only + proj.cleanDependencyDirBackup(); + } else { + proj.restoreDependencyDir(); + } + } + throw err; + } + } + // editing files from main project + const relativeToRoot = path.relative(root, name); + if (relativeToRoot && !relativeToRoot.startsWith("..") && !path.isAbsolute(relativeToRoot)) { + await proj.resetBuildStatus(); + writeFileAtomic.sync(name, content, "utf-8"); + return content; + } else { + throw new H.WError( + `File is outside the project root and cannot be accessed.`, + errorCode.WEBINIZER_FILE_OUTSIDE_ROOT + ); + } +} + +export async function createNewFile(root: string, name: string, content: string) { + validateProjectRoot(root); + const proj = new Project(root); + if (fs.existsSync(name)) { + throw new H.WError( + `File already exists, please specify another directory.`, + errorCode.WEBINIZER_FILE_EXT + ); + } + const relative = path.relative(root, name); + if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) { + await proj.resetBuildStatus(); + fs.mkdirSync(path.dirname(name), { mode: 0o0700, recursive: true }); + writeFileAtomic.sync(name, content, { + mode: 0o0600, + }); + } else { + throw new H.WError( + `File is outside the project root and cannot be accessed.`, + errorCode.WEBINIZER_FILE_OUTSIDE_ROOT + ); + } +} + +export function getBuildLog(root: string): string { + validateProjectRoot(root); + const proj = new Project(root); + return proj.log.getContent(); +} + +export function getDirTree(root: string, dirPath: string): IDtreeJson { + validateProjectRoot(root); + const relative = path.relative(root, dirPath); + // relative == "" --> root == dirPath will work + if (!relative.startsWith("..") && !path.isAbsolute(relative)) { + const tree = buildDirTree(dirPath); + return { tree }; + } else { + throw new H.WError( + `Directory ${dirPath} is outside the project root and cannot be accessed.`, + errorCode.WEBINIZER_DIR_OUTSIDE_ROOT + ); + } +} + +export function getBuildResult(root: string): ProjectResult { + validateProjectRoot(root); + const proj = new Project(root); + return proj.result; +} + +export function getTemplates(root: string): string[] { + validateProjectRoot(root); + const proj = new Project(root); + return proj.getTemplateLiterals(); +} + +export function evalTemplates(root: string, v: string): string { + validateProjectRoot(root); + const proj = new Project(root); + return proj.evalTemplateLiterals(v); +} + +export async function getStatus(root: string): Promise { + validateProjectRoot(root); + const status = await buildStatus.getBuildStatus(root); + return status; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function acceptProjectProfile(req: any, res: any) { + await handleUploadProject(req, res); +} + +export async function addProjectByGitClone( + repoPath: string, + configPart: H.Dict +): Promise { + return cloneProject(repoPath, configPart); +} + +export async function addProjectFromRegistry( + spec: H.Dict, + config: H.Dict +): Promise { + return fetchProjectFromRegistry(spec, config); +} + +export function deleteProject(projPath: string): IProjectProfile[] { + validateProjectRoot(projPath); + deleteProjectSoftly(projPath); + return getProfilesFromDetection(); +} + +export async function publishProject(root: string) { + validateProjectRoot(root); + const proj = new Project(root); + await proj.publishToRegistry(); +} + +export async function searchProject(text: string): Promise { + return searchPackage(text); +} + +export function getSettings(): IJsonObject { + return Settings.toJson(); +} + +export async function updateSettings(jsonParts: H.Dict): Promise { + await Settings.updateSettings(jsonParts); + return Settings.toJson(); +} diff --git a/src/builder.ts b/src/builder.ts new file mode 100644 index 0000000..3afc7ae --- /dev/null +++ b/src/builder.ts @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Builder + * @module + */ +import * as H from "./helper"; +import { JsonFactories } from "./json_factory"; +import { IBuilder, IBuilderFactory, Project as IProject } from "webinizer"; + +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +const log = H.getLogger("builder"); + +export const ALL_BUILDER_FACTORIES = new JsonFactories("Builder"); + +export function isPrevBuildersAllNative(proj: IProject, idx: number): boolean { + const builders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + if (builders && builders.length && idx >= 0 && idx < builders.length) { + for (let i = 0; i < idx; i++) { + if ( + builders[i].__type__ === "NativeBuilder" || + (builders[i].__type__ === "MakeBuilder" && (builders[i].args as string).includes("clean")) + ) + continue; + else { + return false; + } + } + return true; + } + return false; +} + +export function findFirstBuilder(proj: IProject, builder: string): number { + const builders = proj.config.getBuildConfigForTarget(proj.config.target).rawBuilders; + if (builders) { + const builderArr = builders.map((b) => b.__type__); + return builderArr.findIndex((v) => v === builder); + } + return -1; +} diff --git a/src/builders/cmake.ts b/src/builders/cmake.ts new file mode 100644 index 0000000..ab19a2f --- /dev/null +++ b/src/builders/cmake.ts @@ -0,0 +1,205 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import shlex from "shlex"; +import * as H from "../helper"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { checkJsonType } from "../json_factory"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { getFileLocation } from "../actions/file_change"; +import { isPrevBuildersAllNative } from "../builder"; +import { dependencyDir } from "../constants"; +import { + IBuilder, + IBuilderFactory, + IBuilderJson, + IJsonObject, + AdviseManager as IAdviseManager, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("CMakeBuildStep"); + +class CMakeBuilderFactory implements IBuilderFactory { + name = "emcmake (in place of CMake)"; + desc = "Use this builder if native project is built with CMake"; + detect(proj: IProject): CMakeBuilder | null { + log.info("... detecting CMakeLists.txt in", proj.root); + const cmakeFiles = H.matchFilePath("**/CMakeLists.txt", proj.root, [dependencyDir]); + if (cmakeFiles.length > 0) { + return new CMakeBuilder( + proj, + 0 /*set builder id as 0 by default*/, + path.join("${projectRoot}", path.dirname(cmakeFiles[0])), + "" /*no args by default from detection*/ + ); + } + return null; + } + + createDefault(proj: IProject, args?: string): CMakeBuilder { + // use project root as default rootBuildFilePath + return new CMakeBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: IProject, o: IJsonObject, index: number): IBuilder { + checkJsonType(CMakeBuilder.__type__, o); + return new CMakeBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class CMakeBuilder implements IBuilder { + static __type__ = "CMakeBuilder"; + type = CMakeBuilder.__type__; + desc = "CMake"; + id: number; + args: string[]; + private _proj: IProject; + private _rootBuildFilePath: string; // file dirname (w/o file name) + constructor(proj: IProject, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this._rootBuildFilePath = rootBuildFilePath; + this.args = shlex.split(args); + } + toJson(): IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: IAdviseManager, errors: string) { + let isAdvised = false; + const blocks = errors.split("\n\n"); + // each error should start from "CMake Error" + const errorHeader = "CMake Error"; + for (const block of blocks) { + const lines = block.trim().split("\n"); + let i; + for (i = 0; i < lines.length; ++i) { + if (lines[i].trimStart().startsWith(errorHeader)) { + break; + } + } + if (i < lines.length) { + const err = lines.slice(i).join("\n"); + // pass the entire block of error message instead of a single line to get file location + // use getFileLocation() from first line will not capture the error line from file CMakeLists.txt correctly + // i.e., get "/usr/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:137" but need "CMakeLists.txt:15 (find_package)"" + // search from last line instead (entry of callstack) + adviseManager.queueRequest( + new ErrorAdviseRequest( + "cmake", + err, + getFileLocation(err, true /*search from last*/), + this.id + ) + ); + if (!isAdvised) isAdvised = true; + } + } + if (!isAdvised) { + // if the error log is not captured with `errorHeader`, send an `ErrorAdviseRequest` with the whole error log + adviseManager.queueRequest(new ErrorAdviseRequest("cmake", errors, null, this.id)); + } + } + + async build(adviseManager: IAdviseManager): Promise { + const dumpLog = (data: string) => { + this._proj.log.update(data); + }; + + let envCmds = ""; + const buildConfig = this._proj.config.getBuildConfigForTarget(this._proj.config.target); + // apply env variables to the first non-native builder + if (this.id === 0 || isPrevBuildersAllNative(this._proj, this.id)) { + // cmake specific methods, remove "'" from cmds + const compilerFlags = this._proj.config.getOverallEnv("cflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("cflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + const linkerFlags = this._proj.config.getOverallEnv("ldflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("ldflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + // define install path + const prefixFlags = this._proj.config.isLibrary + ? ` -DCMAKE_INSTALL_PREFIX=${this._proj.constant.projectDist}` + : ""; + // update project prefix in `pkgConfig` field + if ( + prefixFlags && + this._proj.evalTemplateLiterals(buildConfig.getPkgConfigEnv("prefix")) !== + this._proj.constant.projectDist + ) { + buildConfig.setPkgConfigEnv( + "prefix", + this._proj.constant.projectDist.replace(this._proj.root, "${projectRoot}") + ); + } + envCmds = + (compilerFlags + ? ` -DCMAKE_C_FLAGS="${compilerFlags}" -DCMAKE_CXX_FLAGS="${compilerFlags}"` + : "") + + (linkerFlags ? ` -DCMAKE_EXE_LINKER_FLAGS="${linkerFlags}"` : "") + + prefixFlags; + } + + const cmd = + "emcmake cmake ./ " + + (this.args + ? shlex + .join([...new Set(this.args.map((a) => this._proj.evalTemplateLiterals(a)))]) + .replace(/'/g, "") + : "") + + envCmds; + log.info(`... running emcmake command: ${cmd}`, dumpLog); + const results = await H.runCommand( + cmd, + { cwd: this._proj.evalTemplateLiterals(this._rootBuildFilePath) }, + dumpLog, + dumpLog + ); + + if (results.code !== 0) { + log.warn("CMake ", `Got errors with return code ${results.code} ...`, dumpLog); + await this._analyzeErrors(adviseManager, results.error); + return false; + } else { + log.info(`... cmake successfully!`, dumpLog); + return true; + } + } +} + +// loading +export default function onload() { + ALL_BUILDER_FACTORIES.register(CMakeBuilder.__type__, new CMakeBuilderFactory()); +} diff --git a/src/builders/configure.ts b/src/builders/configure.ts new file mode 100644 index 0000000..dd5809a --- /dev/null +++ b/src/builders/configure.ts @@ -0,0 +1,198 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import shlex from "shlex"; +import * as H from "../helper"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { BuilderArgsChangeAction } from "../actions/args_change"; +import { checkJsonType } from "../json_factory"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { isPrevBuildersAllNative } from "../builder"; +import { buildDir, dependencyDir } from "../constants"; +import { + IBuilder, + IBuilderFactory, + IBuilderJson, + IJsonObject, + AdviseManager as IAdviseManager, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("ConfigureBuildStep"); + +class ConfigureBuilderFactory implements IBuilderFactory { + name = "configure"; + desc = "configure of the Autotools build system"; + detect(proj: IProject): ConfigureBuilder | null { + log.info("... detecting configure file in", proj.root); + const cfgFiles = H.matchFilePath("**/configure", proj.root, [dependencyDir]); + if (cfgFiles.length > 0) { + return new ConfigureBuilder( + proj, + 0 /*set builder id as 0 by default*/, + path.join("${projectRoot}", path.dirname(cfgFiles[0])), + "" /*no args by default from detection*/ + ); + } + return null; + } + + createDefault(proj: IProject, args?: string): ConfigureBuilder { + // use project root as default rootBuildFilePath + return new ConfigureBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: IProject, o: IJsonObject, index: number): IBuilder { + checkJsonType(ConfigureBuilder.__type__, o); + return new ConfigureBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class ConfigureBuilder implements IBuilder { + static __type__ = "ConfigureBuilder"; + type = ConfigureBuilder.__type__; + desc = "configure"; + args: string[]; + id: number; + private _proj: IProject; + private _rootBuildFilePath: string; // file dirname (w/o file name) + + constructor(proj: IProject, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this._rootBuildFilePath = rootBuildFilePath; + this.args = shlex.split(args); + } + + toJson(): IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: IAdviseManager, errors: string) { + adviseManager.queueRequest(new ErrorAdviseRequest("cfg_args", errors, null, this.id)); + return; + } + + private async _updatePrefixArg() { + log.info("... add prefix arg"); + const argsChange = new BuilderArgsChangeAction( + this._proj, + `Add --prefix argument to configure options`, + [ + { + option: "--prefix", + value: path.join("${projectRoot}", buildDir), + type: "replace", + }, + ], + this.id, + false /* no cache refresh as this is from builder to cache */ + ); + await argsChange.apply(); + + // get the updated args for builder + const rawBuilders = this._proj.config.getBuildConfigForTarget( + this._proj.config.target + ).rawBuilders; + this.args = shlex.split(rawBuilders ? (rawBuilders[this.id].args as string) : ""); + } + + async build(adviseManager: IAdviseManager): Promise { + const dumpLog = (data: string) => { + this._proj.log.update(data); + }; + + let envCmds = ""; + const buildConfig = this._proj.config.getBuildConfigForTarget(this._proj.config.target); + // apply env variables to the first non-native builder + if (this.id === 0 || isPrevBuildersAllNative(this._proj, this.id)) { + // general env methods, remove "'" from cmds + const compilerFlags = this._proj.config.getOverallEnv("cflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("cflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + const linkerFlags = this._proj.config.getOverallEnv("ldflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("ldflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + envCmds = + (compilerFlags ? `CFLAGS="${compilerFlags}" CXXFLAGS="${compilerFlags}" ` : "") + + (linkerFlags ? `LDFLAGS="${linkerFlags}" ` : ""); + + if (this._proj.config.isLibrary) { + // define install path + await this._updatePrefixArg(); + // update project prefix in `pkgConfig` field + if ( + this._proj.evalTemplateLiterals(buildConfig.getPkgConfigEnv("prefix")) !== + this._proj.constant.projectDist + ) { + buildConfig.setPkgConfigEnv( + "prefix", + this._proj.constant.projectDist.replace(this._proj.root, "${projectRoot}") + ); + } + } + } + + // run cmd + const cmd = + envCmds + + "emconfigure ./configure " + + (this.args + ? shlex + .join([...new Set(this.args.map((a) => this._proj.evalTemplateLiterals(a)))]) + .replace(/'/g, "") + : ""); + log.info(`... running configure command: ${cmd}`, dumpLog); + const results = await H.runCommand( + cmd, + { cwd: this._proj.evalTemplateLiterals(this._rootBuildFilePath) }, + dumpLog, + dumpLog + ); + + if (results.code !== 0) { + log.warn("configure ", `Got errors with return code ${results.code} ...`, dumpLog); + await this._analyzeErrors(adviseManager, results.output + results.error); + return false; + } else { + log.info(`... configure successfully!`, dumpLog); + return true; + } + } +} + +// loading +export default function onload() { + ALL_BUILDER_FACTORIES.register(ConfigureBuilder.__type__, new ConfigureBuilderFactory()); +} diff --git a/src/builders/emcc.ts b/src/builders/emcc.ts new file mode 100644 index 0000000..c796c3f --- /dev/null +++ b/src/builders/emcc.ts @@ -0,0 +1,120 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import shlex from "shlex"; +import * as H from "../helper"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { checkJsonType } from "../json_factory"; +import { + IBuilder, + IBuilderFactory, + IBuilderJson, + IJsonObject, + AdviseManager as IAdviseManager, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("EmccBuildStep"); + +class EmccBuilderFactory implements IBuilderFactory { + name = "emcc (in place of CC)"; + desc = "Use this if native project is built with CC (gcc, clang etc.)"; + /* eslint-disable @typescript-eslint/no-unused-vars */ + detect(proj: IProject): EmccBuilder | null { + return null; + } + + createDefault(proj: IProject, args?: string): EmccBuilder { + // use project root as default rootBuildFilePath + return new EmccBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: IProject, o: IJsonObject, index: number): IBuilder { + checkJsonType(EmccBuilder.__type__, o); + return new EmccBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class EmccBuilder implements IBuilder { + static __type__ = "EmccBuilder"; + type = EmccBuilder.__type__; + desc = "emcc"; + args: string[]; + id: number; + private _proj: IProject; + private _rootBuildFilePath: string; + + constructor(proj: IProject, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this.args = shlex.split(args); + this._rootBuildFilePath = rootBuildFilePath; + } + toJson(): IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: IAdviseManager, errors: string) { + adviseManager.queueRequest( + new ErrorAdviseRequest(["cfg_args", "make", "cmake"], errors, null, this.id) + ); + return; + } + + async build(adviseManager: IAdviseManager): Promise { + const dumpLog = (data: string) => { + this._proj.log.update(data); + }; + + // get the union of compiler, linker flags and builder args and apply to emcc directly + const argsUnion = [ + ...new Set([ + ...(this._proj.config.getOverallEnv("cflags") + ? shlex.split(this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("cflags"))) + : []), + ...(this._proj.config.getOverallEnv("ldflags") + ? shlex.split(this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("ldflags"))) + : []), + ...this.args.map((a) => this._proj.evalTemplateLiterals(a)), + ]), + ]; + + const cmd = "emcc " + shlex.join(argsUnion).replace(/'/g, ""); + log.info(`... running emcc command: ${cmd}`, dumpLog); + const results = await H.runCommand( + cmd, + { cwd: this._proj.evalTemplateLiterals(this._rootBuildFilePath) }, + dumpLog, + dumpLog + ); + + if (results.code !== 0) { + log.warn("emcc ", `Got errors with return code ${results.code}...`, dumpLog); + await this._analyzeErrors(adviseManager, results.error); + return false; + } else { + log.info(`... emcc successfully!`, dumpLog); + return true; + } + } +} + +// loading +export default function onload() { + ALL_BUILDER_FACTORIES.register(EmccBuilder.__type__, new EmccBuilderFactory()); +} diff --git a/src/builders/make.ts b/src/builders/make.ts new file mode 100644 index 0000000..3f89179 --- /dev/null +++ b/src/builders/make.ts @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import shlex from "shlex"; +import * as H from "../helper"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { checkJsonType } from "../json_factory"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { isPrevBuildersAllNative } from "../builder"; +import { dependencyDir } from "../constants"; +import { + IBuilder, + IBuilderFactory, + IBuilderJson, + IJsonObject, + AdviseManager as IAdviseManager, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("MakeBuildStep"); + +class MakeBuilderFactory implements IBuilderFactory { + name = "emmake (in place of Make)"; + desc = "Use this builder if native project is built with Make"; + detect(proj: IProject): MakeBuilder | null { + log.info("... detecting Makefile in", proj.root); + const makeFiles = H.matchFilePath("**/Makefile", proj.root, [dependencyDir]); + if (makeFiles.length > 0) { + return new MakeBuilder( + proj, + 0 /*set builder id as 0 by default*/, + path.join("${projectRoot}", path.dirname(makeFiles[0])), + "" /*no args by default from detection*/ + ); + } + return null; + } + + createDefault(proj: IProject, args?: string): MakeBuilder { + // use project root as default rootBuildFilePath + return new MakeBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: IProject, o: IJsonObject, index: number): IBuilder { + checkJsonType(MakeBuilder.__type__, o); + return new MakeBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class MakeBuilder implements IBuilder { + static __type__ = "MakeBuilder"; + type = MakeBuilder.__type__; + desc = "make"; + id: number; + private _proj: IProject; + private _rootBuildFilePath: string; // file dirname (w/o file name) + args: string[]; // build args + constructor(proj: IProject, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this._rootBuildFilePath = rootBuildFilePath; + this.args = shlex.split(args); + } + toJson(): IBuilderJson { + return { + __type__: MakeBuilder.__type__, + id: this.id, + desc: this.desc, + args: shlex.join(this.args), + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: IAdviseManager, errors: string) { + adviseManager.queueRequest(new ErrorAdviseRequest(["cfg_args", "make"], errors, null, this.id)); + return; + } + + async build(adviseManager: IAdviseManager): Promise { + const dumpLog = (data: string) => { + this._proj.log.update(data); + }; + + let envCmds = ""; + const buildConfig = this._proj.config.getBuildConfigForTarget(this._proj.config.target); + // apply env variables to the first non-native non-clean builder + if ( + (this.id === 0 || (this.id !== 0 && isPrevBuildersAllNative(this._proj, this.id))) && + !this.args.includes("clean") + ) { + // general env methods, remove "'" from cmds + const compilerFlags = this._proj.config.getOverallEnv("cflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("cflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + const linkerFlags = this._proj.config.getOverallEnv("ldflags") + ? shlex + .join([ + ...new Set( + shlex.split( + this._proj.evalTemplateLiterals(this._proj.config.getOverallEnv("ldflags")) + ) + ), + ]) + .replace(/'/g, "") + : ""; + // define install path + const prefixFlags = this._proj.config.isLibrary + ? `PREFIX=${this._proj.constant.projectDist} ` + : ""; + // update project prefix in `pkgConfig` field + if ( + prefixFlags && + this._proj.evalTemplateLiterals(buildConfig.getPkgConfigEnv("prefix")) !== + this._proj.constant.projectDist + ) { + buildConfig.setPkgConfigEnv( + "prefix", + this._proj.constant.projectDist.replace(this._proj.root, "${projectRoot}") + ); + } + envCmds = + (compilerFlags ? `CFLAGS="${compilerFlags}" CXXFLAGS="${compilerFlags}" ` : "") + + (linkerFlags ? `LDFLAGS="${linkerFlags}" ` : "") + + prefixFlags; + } + + const cmd = + envCmds + + "emmake make -j4 " + + (this.args + ? shlex + .join([...new Set(this.args.map((a) => this._proj.evalTemplateLiterals(a)))]) + .replace(/'/g, "") + : ""); + log.info(`... running emmake command: ${cmd}`, dumpLog); + const results = await H.runCommand( + cmd, + { cwd: this._proj.evalTemplateLiterals(this._rootBuildFilePath) }, + dumpLog, + dumpLog + ); + + if (results.code !== 0) { + log.warn("Make ", `Got errors with return code ${results.code} ...`, dumpLog); + await this._analyzeErrors(adviseManager, results.all); + return false; + } else { + log.info(`... make successfully!`, dumpLog); + return true; + } + } +} + +// loading +export default function onload() { + ALL_BUILDER_FACTORIES.register(MakeBuilder.__type__, new MakeBuilderFactory()); +} diff --git a/src/builders/native.ts b/src/builders/native.ts new file mode 100644 index 0000000..e346533 --- /dev/null +++ b/src/builders/native.ts @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { ErrorAdviseRequest } from "../advise_requests/common_requests"; +import { checkJsonType } from "../json_factory"; +import { + IBuilder, + IBuilderFactory, + IBuilderJson, + IJsonObject, + AdviseManager as IAdviseManager, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("NativeCommand"); + +class NativeBuilderFactory implements IBuilderFactory { + name = "native commands"; + desc = "Use this to run native commands without Emscripten related configs"; + /* eslint-disable @typescript-eslint/no-unused-vars */ + detect(proj: IProject): NativeBuilder | null { + return null; + } + + createDefault(proj: IProject, args?: string): NativeBuilder { + // use project root as default rootBuildFilePath + return new NativeBuilder(proj, 0, "${projectRoot}", args || ""); + } + + fromJson(proj: IProject, o: IJsonObject, index: number): IBuilder { + checkJsonType(NativeBuilder.__type__, o); + return new NativeBuilder( + proj, + index, + o.rootBuildFilePath as string, + o.args ? (o.args as string) : "" + ); + } +} + +class NativeBuilder implements IBuilder { + static __type__ = "NativeBuilder"; + type = NativeBuilder.__type__; + desc = "Run native commands without emscripten related configs"; + args: string[]; + id: number; + private _proj: IProject; + private _rootBuildFilePath: string; + + constructor(proj: IProject, id: number, rootBuildFilePath: string, args: string) { + this._proj = proj; + this.id = id; + this.args = [args]; // don't operate on the args but execute directly + this._rootBuildFilePath = rootBuildFilePath; + } + toJson(): IBuilderJson { + return { + __type__: this.type, + id: this.id, + desc: this.desc, + args: this.args[0], + rootBuildFilePath: this._rootBuildFilePath, + }; + } + + private async _analyzeErrors(adviseManager: IAdviseManager, errors: string) { + adviseManager.queueRequest(new ErrorAdviseRequest(["native"], errors, null, this.id)); + return; + } + + async build(adviseManager: IAdviseManager): Promise { + const dumpLog = (data: string) => { + this._proj.log.update(data); + }; + + const cmd = this._proj.evalTemplateLiterals(this.args[0]); + log.info(`... running native command: ${cmd}`, dumpLog); + const results = await H.runCommand( + cmd, + { cwd: this._proj.evalTemplateLiterals(this._rootBuildFilePath) }, + dumpLog, + dumpLog + ); + + if (results.code !== 0) { + log.warn( + "Native command ", + `${cmd} `, + `Got errors with return code ${results.code}...`, + dumpLog + ); + await this._analyzeErrors(adviseManager, results.error); + return false; + } else { + log.info(`... native command runs successfully!`, dumpLog); + return true; + } + } +} + +// loading +export default function onload() { + ALL_BUILDER_FACTORIES.register(NativeBuilder.__type__, new NativeBuilderFactory()); +} diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..22f2c2e --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Commonly shared constants + */ + +import path from "path"; + +// define source file extensions based on emcc implementation +export const C_ENDINGS = [".c", ".i"]; +export const CXX_ENDINGS = [ + ".cpp", + ".cxx", + ".cc", + ".c++", + ".CPP", + ".CXX", + ".C", + ".CC", + ".C++", + ".ii", +]; +export const HEADER_ENDINGS = [".h", ".hxx", ".hpp", ".hh", ".H", ".HXX", ".HPP", ".HH"]; + +// build directory for webinizer output +export const buildDir = "webinizer_build"; + +// dependent packages directory +export const dependencyDir = "webinizer_deps"; + +// root directory for project pool +export const projectPool = "/projects"; + +export const ALLOWED_UPLOADED_FILE_TYPE = ["application/x-zip-compressed"]; + +export const UPLOAD_PROJECT_REPO_PATH = "/webinizer/uploaded_proj"; + +export const WEBINIZER_HOME = "/webinizer/webinizer"; +export const WEBINIZER_SRC_HOME = path.join(WEBINIZER_HOME, "src"); +export const WEBINIZER_DIST_HOME = + process.env.npm_lifecycle_event === "test" + ? path.join(WEBINIZER_HOME, "src") + : path.join(WEBINIZER_HOME, "dist"); +export const WEBINIZER_TEST_HOME = path.join(WEBINIZER_HOME, "tests"); + +const builderPath = path.join(WEBINIZER_DIST_HOME, "builders"); +const advisorPath = path.join(WEBINIZER_DIST_HOME, "advisors"); +const actionPath = path.join(WEBINIZER_DIST_HOME, "actions"); +const adviseRequestPath = path.join(WEBINIZER_DIST_HOME, "advise_requests"); +export const moduleDirectories = [builderPath, advisorPath, actionPath, adviseRequestPath]; + +export const EXTENSION_SRC_HOME = path.join(WEBINIZER_HOME, "extensions"); diff --git a/src/create_project.ts b/src/create_project.ts new file mode 100644 index 0000000..7166c7c --- /dev/null +++ b/src/create_project.ts @@ -0,0 +1,406 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ +import fs from "graceful-fs"; +import * as H from "./helper"; +import * as C from "./constants"; +import * as _ from "lodash"; +import Path from "path"; +import multiparty from "multiparty"; +import AdmZip from "adm-zip"; +import errorCode from "./error_code"; +import { Project } from "./project"; +import { getPackageFetcher } from "./package_manager/fetcher"; + +const log = H.getLogger("create_project"); +const enum UploadStatus { + processing = "processing", + done = "done", +} + +export async function handleUploadProject(req: any, res: any) { + const multiParty = new multiparty.Form(req); + + multiParty.parse(req, async (err, fields, files) => { + try { + if (err) throw err; + /* parse form data successfully, get fields valve from `fields`*/ + const index = Number(fields.index); + const uploadedSize = Number(fields.uploadedSize); + const totalSize = Number(fields.totalSize); + const chunkSize = Number(fields.chunkSize); + const type = String(fields.type); + const startTime = String(fields.startTime); + + /* get project details from fields */ + const projectName = String(fields.projectName); + const projectVersion = String(fields.projectVersion); + const projectDesc = String(fields.projectDesc); + const projectIsLib = String(fields.projectIsLib) === "true" ? true : false; + const projectDependencies = JSON.parse(String(fields.projectDependencies)); + const projImg = String(fields.img); + + /* get files details from `files`*/ + const fileFullName = String(files.file[0].originalFilename); + const fileBaseName = Path.parse(fileFullName).name; + const fileSize = Number(files.file[0].size); + const temFilePath = String(files.file[0].path); + let projRoot = Path.resolve(C.projectPool, fileBaseName); + + /**NOTE - should check if uploaded file's type meets requirement + * - should check if this project exists in + * projects pool path(/projects) + */ + checkUploadedFileType(type); + + const targetName = generateValidProjFolderName(projRoot); + /* reassign the project root since the target name may change */ + projRoot = Path.resolve(C.projectPool, targetName); + + /* construct the uploaded directory tree */ + const chunkDirPath = constructUploadedProjFolder(fileBaseName, startTime); + + /**NOTE - each chunk file is saved temporarily under /tmp + * directory, so we could just move it into constructed + * chunk directory + * */ + fs.renameSync(temFilePath, Path.resolve(chunkDirPath, String(index))); + + /**NOTE - merge chunks if the all chunks arrived, read each + * chunk then write into target. + * target file will be created and saved under current + * set up UPLOAD_PROJECT_REPO_PATH. + */ + if (uploadedSize + fileSize === totalSize) { + try { + await mergeChunksIntoTarget( + chunkDirPath, + Path.resolve(C.UPLOAD_PROJECT_REPO_PATH, fileBaseName), + chunkSize + ); + extractTargetZipFile( + Path.resolve(C.UPLOAD_PROJECT_REPO_PATH, fileBaseName), + fileBaseName, + targetName + ); + + /* git init the project for tracking */ + const gitInitResults = await H.runCommand( + "git init && git add . && git commit -m 'first commit'", + { cwd: projRoot, silent: true } + ); + + if (gitInitResults.code !== 0) { + /**NOTE - should clear the project if error occurs + * cause the project folder has been extracted + */ + throw new H.WError( + `Initialize the project with git failed.`, + errorCode.WEBINIZER_PROJ_INIT_FAIL + ); + } + + /* update project config when creating project finish */ + const proj = new Project(projRoot); + await proj.config.updateRawJson({ + name: projectName, + version: projectVersion, + desc: projectDesc, + isLibrary: projectIsLib, + dependencies: projectDependencies, + img: projImg, + }); + + //TODO. do we need to check the existence of `package.json` and convert it to config.json? + + /* return Status.done when all actions finish */ + res + .status(200) + .json({ status: `${UploadStatus.done}`, path: encodeURIComponent(proj.root) }); + return; + } catch (error) { + /* remove the project folder */ + fs.rmSync(projRoot, { recursive: true, force: true }); + throw error as Error; + } finally { + fs.rmSync(C.UPLOAD_PROJECT_REPO_PATH, { recursive: true, force: true }); + } + } + + /* if the response has been sent, then the headersSent will be true */ + if (!res.headersSent) { + /* send back Status.process */ + res.status(200).json({ status: `${UploadStatus.processing}` }); + } + } catch (error) { + fs.rmSync(C.UPLOAD_PROJECT_REPO_PATH, { recursive: true, force: true }); + log.error("project initialization error\n", H.normalizeErrorOutput(error as Error)); + res.status(400).json(H.serializeError(error as Error)); + return; + } + }); +} + +/** + * ALLOWED_UPLOADED_FILE_TYPE is defined in constant.ts + * @param type The type of the uploaded file + */ +function checkUploadedFileType(type: string) { + if (!C.ALLOWED_UPLOADED_FILE_TYPE.includes(type)) { + throw new H.WError( + `Uploaded file's type is not allowed.`, + errorCode.WEBINIZER_FILE_UNSUPPORTED_ENCODING + ); + } +} + +/** + * same named projects under project pool directory is + * not allowed + * + * @param projectFolderPath The file's name without the extension + */ +function checkIfProjectExists(projectFolderPath: string): boolean { + return fs.existsSync(projectFolderPath); +} + +function checkIfProjectDeleted(projectPath: string): boolean { + const proj = new Project(projectPath); + return proj.config.deleted as boolean; +} + +function generateValidProjFolderName(origProjectPath: string): string { + /**NOTE - 2 situations allowed: + * 1) project dose not exist + * 2) project exists but has been deleted + */ + const folderName = Path.basename(origProjectPath); + if (!checkIfProjectExists(origProjectPath)) return folderName; + else { + if (!checkIfProjectDeleted(origProjectPath)) { + // validate if the existing project is deleted or not + throw new H.WError(`Project already exists.`, errorCode.WEBINIZER_ROOT_EXT); + } + const newFolderName = renameNewlyAddedProject(folderName); + const newFolderPath = Path.resolve(C.projectPool, newFolderName); + return generateValidProjFolderName(newFolderPath); + } +} + +/** + * construct the chunk directory for each uploaded project file + * to save each chunk + * E.g: UPLOAD_PROJECT_REPO_PATH/fileName/2023-01-09_00:00:00/0|1|2... + * + * @param fileName file's name without extension + * @param uploadStartTime used in naming chunks directory + */ +function constructUploadedProjFolder(fileName: string, uploadStartTime: string): string { + const chunkDirPath = Path.resolve(C.UPLOAD_PROJECT_REPO_PATH, `${fileName}_${uploadStartTime}`); + + if (!fs.existsSync(chunkDirPath)) { + fs.mkdirSync(chunkDirPath, { recursive: true }); + } + return chunkDirPath; +} + +/** + * + * @param chunkDirPath the path that saves chunks + * @param targetFilePath the path the chunks will be merged into + * @param setupChunkSize the setup size of each chunk, may not equal + * to the uploaded chunk size + */ +async function mergeChunksIntoTarget( + chunkDirPath: string, + targetFilePath: string, + setupChunkSize: number +): Promise { + const chunksArr = fs.readdirSync(chunkDirPath); + /* sort the chunks order by index to ensure successfully merge */ + chunksArr.sort((a, b) => { + return Number(a) - Number(b); + }); + + const allPromise = Promise.all( + chunksArr.map((chunk, index) => { + return new Promise((resolve) => { + const chunkPath = Path.resolve(chunkDirPath, String(chunk)); + const readStream = fs.createReadStream(chunkPath); + const writeStream = fs.createWriteStream(targetFilePath, { start: index * setupChunkSize }); + readStream.pipe(writeStream); + readStream.on("end", () => { + fs.unlinkSync(chunkPath); + resolve(); + }); + }); + }) + ); + + await allPromise; + /* remove the chunk directory after merging */ + fs.rmdirSync(chunkDirPath); +} + +/** + * extract zip file to dest, note that if the project folder exists + * and has been set `deleted` flag as true, should change top + * folder name to new target name + * @param path the path of the project zip file + */ +function extractTargetZipFile(path: string, sourceFolderName?: string, targetName?: string): void { + /**NOTE - the uploaded file has no access yet, access right + * before extracting + */ + fs.chmodSync(path, 0o755); + const unZipper = new AdmZip(path); + /**NOTE - be aware that the compress action maybe not the same + * such as, user may select to compress the project folder + * directly, or he may compress the whole files under the + * project folder, we should check the files in the archive + * before extracting + */ + if (sourceFolderName !== targetName) { + unZipper.getEntries().forEach((entry) => { + /**NOTE - check if the zip file name equals to the top layer + * folder, we strictly set limitation here + */ + const regX = new RegExp("^" + sourceFolderName + ""); + if (entry.entryName.match(regX) === null) { + throw new H.WError( + `Upload project package does not meet requirement.`, + errorCode.WEBINIZER_PROJ_PACKAGE_INVALID + ); + } + entry.entryName = entry.entryName.replace(sourceFolderName as string, targetName as string); + }); + } + unZipper.extractAllTo(C.projectPool, true, true); +} + +export async function cloneProject(repoPath: string, configPart: H.Dict): Promise { + /*NOTE - should check if the project has existed under project + * pool directory + */ + const extractNameCmd = `basename ${repoPath} .git`; + const extractResult = await H.runCommand(extractNameCmd, { silent: true }); + if (extractResult.code !== 0) { + throw new H.WError( + `The repo's path is invalid.`, + errorCode.WEBINIZER_PROJ_GIT_REPO_PATH_INVALID + ); + } + + const repoName = extractResult.output.replace(/\n/gi, ""); + let projRoot = Path.resolve(C.projectPool, repoName); + const targetName = generateValidProjFolderName(projRoot); + /* reassign the project root since the target name may change */ + projRoot = Path.resolve(C.projectPool, targetName); + try { + const cmd = `git clone ${repoPath} ${projRoot}`; + const cloneResult = await H.runCommand(cmd, { cwd: C.projectPool }); + if (cloneResult.code !== 0) { + throw new H.WError( + `Clone the project with git failed.`, + errorCode.WEBINIZER_PROJ_GIT_CLONE_FAIL + ); + } + + if (fs.existsSync(Path.join(projRoot, ".gitmodules"))) { + // initialize submodules + const initSubmodules = await H.runCommand("git submodule update --init --recursive", { + cwd: projRoot, + }); + if (initSubmodules.code !== 0) { + throw new H.WError( + `Initialize the project with git submodules failed.`, + errorCode.WEBINIZER_PROJ_GIT_CLONE_FAIL + ); + } + } + + /* save the project config when project is cloned successfully */ + const proj = new Project(projRoot); + await proj.config.updateRawJson(configPart); + + //TODO. do we need to check the existence of `package.json` and convert it to config.json? + return projRoot; + } catch (error) { + /* remove the project folder if any error occurs */ + fs.rmSync(projRoot, { recursive: true, force: true }); + throw error as Error; + } +} + +export async function fetchProjectFromRegistry( + spec: H.Dict, + config: H.Dict +): Promise { + const packageFetcher = getPackageFetcher( + { name: spec.name.trim(), reference: spec.version.trim() }, + { + fullMetadata: true, + } + ); + const manifest = await packageFetcher.getManifest(); + // using name-version as the default name for this project + let projRoot = Path.join(C.projectPool, `${manifest.name}-${manifest.version}`); + const targetName = generateValidProjFolderName(projRoot); + /* reassign the project root since the target name may change */ + projRoot = Path.resolve(C.projectPool, targetName); + + try { + // fetch project and extract to local + await packageFetcher.fetchPackage(projRoot); + + // git init project + // FIXME. should we include config.json into git tree or not? + const gitInitResults = await H.runCommand( + "git init && git add . && git commit -m 'first commit'", + { cwd: projRoot, silent: true } + ); + if (gitInitResults.code !== 0) { + throw new H.WError( + `Initialize the project with git failed.`, + errorCode.WEBINIZER_PROJ_INIT_FAIL + ); + } + const proj = new Project(projRoot); + // convert package.json to config.json + if (fs.existsSync(proj.meta.path)) { + proj.meta.validateMetaSchema(_.cloneDeep(proj.meta.data)); + await proj.config.convertFromRegMeta(); + } + // update other config part such as `img`, `isLibrary`, etc + await proj.config.updateRawJson(config); + return projRoot; + } catch (error) { + /* remove the project folder if any error occurs */ + fs.rmSync(projRoot, { recursive: true, force: true }); + throw error as Error; + } +} + +/** + * @param projectName the name of project + * @returns true if the project exist in recycle_bin + * + * if there are projects which have same name in + * directory, should rename the new added(including upload & clone) + * follow the format. ProjName__1 | 2 | 3 + */ +function renameNewlyAddedProject(projectName: string): string { + let newName = ""; + const suffix = "__1"; + const results = projectName.match(/((.+)__)(\d+)/); + if (results) { + const baseFolderName = results[1]; + const version = Number(results[3]) + 1; + newName = baseFolderName + version; + } + return newName || projectName + suffix; +} diff --git a/src/delete_project.ts b/src/delete_project.ts new file mode 100644 index 0000000..1cc563a --- /dev/null +++ b/src/delete_project.ts @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import Path from "path"; +import errorCode from "./error_code"; +import { Project } from "./project"; +import { buildStatus } from "./status"; +import * as C from "./constants"; +import * as H from "./helper"; + +/** + * Delete projects softly, which means the projects will not be + * removed from disk, set the `project.config.deleted` flag as true + * instead + * if users upload or clone the project which has the same name + * again, will rename new project folder with {project__1 | 2 ...} + * to avoid multiple folders with the same name + */ + +/** + * This function is to resolve unexpected action like users + * input the system file path + * + * @param projectPath: the path of the project, generally start with + * "/native_projects/" + * @returns true if the project path is valid + */ +function checkIfProjectPathValid(projectPath: string) { + const projParsedPath = Path.parse(Path.normalize(projectPath)).dir; + if (projParsedPath !== C.projectPool) { + throw new H.WError(`Project path is invalid.`, errorCode.WEBINIZER_PROJ_PATH_INVALID); + } +} + +export function deleteProjectSoftly(projectPath: string) { + checkIfProjectPathValid(projectPath); + const proj = new Project(projectPath); + proj.config.updateRawJson({ deleted: true }); + buildStatus.setBuildStatus(projectPath, "idle_default"); +} diff --git a/src/disk_cache.ts b/src/disk_cache.ts new file mode 100644 index 0000000..2b9beb7 --- /dev/null +++ b/src/disk_cache.ts @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import fs from "graceful-fs"; +import writeFileAtomic from "write-file-atomic"; +import dotProp from "dot-prop"; +import * as H from "./helper"; + +const log = H.getLogger("disk-cache"); + +export default class DiskCache { + private _path: string; + private _data: H.Dict = {}; + constructor(filePath: string) { + this._path = filePath; + this._load(); + } + + private _load() { + try { + this._data = JSON.parse(fs.readFileSync(this._path, "utf8")); + //eslint-disable-next-line + } catch (err: any) { + if (err.code === "ENOENT") { + this._data = {}; + return; + } + log.error( + "Failed to load cache from file", + this._path, + "with error:\n", + H.normalizeErrorOutput(err as Error) + ); + throw err; + } + } + + private _save() { + try { + // this doesn't report error if already exists because recursive is set to true + fs.mkdirSync(path.dirname(this._path), { mode: 0o0700, recursive: true }); + writeFileAtomic.sync(this._path, JSON.stringify(this._data, undefined, 2) + "\n", { + mode: 0o0600, + }); + //eslint-disable-next-line + } catch (err: any) { + log.error( + "Failed to save cache to file", + this._path, + "with error:\n", + H.normalizeErrorOutput(err as Error) + ); + throw err; + } + } + + get path(): string { + return this._path; + } + + get data(): H.Dict { + return this._data; + } + + set data(v: H.Dict) { + Object.assign(this._data, v); + this._save(); + } + + get(k: string, defaultValue?: unknown): unknown { + return dotProp.get(this._data, k, defaultValue); + } + + set(k: string, v: unknown) { + dotProp.set(this._data, k, v); + this._save(); + } + + has(k: string): boolean { + return dotProp.has(this._data, k); + } + + delete(k: string): boolean { + const r = dotProp.delete(this._data, k); + this._save(); + return r; + } + + clear() { + this._data = {}; + this._save(); + } +} diff --git a/src/dtree.ts b/src/dtree.ts new file mode 100644 index 0000000..c1328e6 --- /dev/null +++ b/src/dtree.ts @@ -0,0 +1,91 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Directory Tree Utility + * + * @module + */ + +import directoryTree from "directory-tree"; +import path from "path"; +import fs from "graceful-fs"; +import { WError } from "./helper"; +import errorCode from "./error_code"; + +export interface IDtreeNode { + path: string; + name: string; + type: string; + children?: IDtreeNode[]; +} +export interface IDtreeOptions { + exclude?: RegExp | RegExp[]; + depth?: number; + attributes?: (keyof fs.Stats | "type" | "extension")[]; +} +export interface IDtreeJson { + tree: IDtreeNode; +} + +const defaultOptions = { + exclude: [/\/\.webinizer/, /\.webinizer_.*\.(json|log)$/, /\/\.vscode/, /\/\.git/], + depth: 1, + attributes: ["type"] /* show entry type */, +} as IDtreeOptions; + +export function updateDirTree(dirPath: string, dirTree: IDtreeNode, total: IDtreeNode) { + if ( + !total.path || + (total.path === dirPath && total.type === "directory" && total.type === dirTree.type) + ) { + Object.assign(total, dirTree); + return; + } + if (total.children) { + const children = total.children; + for (let i = 0; i < children.length; i++) { + // eslint-disable-next-line + updateDirTree(dirPath, dirTree, children[i]); + } + } +} + +export function hasPath(dirPath: string, total: IDtreeNode): boolean { + if (total.path === dirPath && total.type === "directory" && total.children) return true; + if (total.children) { + const children = total.children; + for (const c of children) { + // eslint-disable-next-line + if (hasPath(dirPath, c)) return true; + } + } + return false; +} + +export function normalizePath(dirPath: string): string { + const dir = path.normalize(dirPath.trim()); + if (dir.endsWith("/")) { + return dir.slice(0, -1); + } + return dir; +} + +export function buildDirTree(dirPath: string, options = defaultOptions): IDtreeNode { + if (fs.existsSync(dirPath)) { + const dir = normalizePath(fs.statSync(dirPath).isFile() ? path.dirname(dirPath) : dirPath); + // we generate it once per level instead of recursively + const tree = directoryTree(dir, options); + return { + path: tree.path, + name: tree.name, + type: tree.type as string, + children: tree.children as IDtreeNode[], + }; + } else { + throw new WError(`Directory ${dirPath} doesn't exist.`, errorCode.WEBINIZER_DIR_NOEXT); + } +} diff --git a/src/error_code.ts b/src/error_code.ts new file mode 100644 index 0000000..d4dc634 --- /dev/null +++ b/src/error_code.ts @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Webinizer Specific Error Code + * @module + */ +const enum errorCode { + /* Webinizer init */ + WEBINIZER_INIT_MODULE_DIR_LOAD_FAIL = "WEBINIZER_INIT_MODULE_DIR_LOAD_FAIL", //Module directory loading failed while webinizer initialization. + WEBINIZER_INIT_MODULE_LOAD_FAIL = "WEBINIZER_INIT_MODULE_LOAD_FAIL", // Module file loading failed while webinizer initialization. + WEBINIZER_INIT_MODULE_DIR_NOEXT = "WEBINIZER_INIT_MODULE_DIR_NOEXT", // Module dirctory does not exist while webinizer initialization. + WEBINIZER_INIT_TOOLCHAIN_CHECK_FAIL = "WEBINIZER_INIT_TOOLCHAIN_CHECK_FAIL", // Required toolchain is not properly configured. + + /* Extension */ + WEBINIZER_EXT_HOME_DIR_LOAD_FAIL = "WEBINIZER_EXT_HOME_DIR_LOAD_FAIL", // Load extension home directory failed. + WEBINIZER_EXT_DIR_LOAD_FAIL = "WEBINIZER_EXT_DIR_LOAD_FAIL", // Load extension directory failed. + WEBINIZER_EXT_META_LOAD_FAIL = "WEBINIZER_EXT_META_LOAD_FAIL", // Load extension meta file failed. + WEBINIZER_EXT_HOME_DIR_NOEXT = "WEBINIZER_EXT_HOME_DIR_NOEXT", // Extesion home directory does not exist. + WEBINIZER_EXT_DIR_NOEXT = "WEBINIZER_EXT_DIR_NOEXT", // Extesion directory does not exist. + WEBINIZER_EXT_META_NOEXT = "WEBINIZER_EXT_META_NOEXT", // Extension meta file does not exist. + WEBINIZER_EXT_UNKNOWN = "WEBINIZER_EXT_UNKNOWN", // Unknown extension. + + /* Project Root */ + WEBINIZER_ROOT_EMPTY = "WEBINIZER_ROOT_EMPTY", // Project root is empty. + WEBINIZER_ROOT_NOEXT = "WEBINIZER_ROOT_NOEXT", // Project root doesn't exist. + WEBINIZER_ROOT_EXT = "WEBINIZER_ROOT_EXT", // Project root exists. + /* File */ + WEBINIZER_FILE_UNSUPPORTED_ENCODING = "WEBINIZER_FILE_UNSUPPORTED_ENCODING", // The file is either binary or uses an unsupported text encoding. + WEBINIZER_FILE_OUTSIDE_ROOT = "WEBINIZER_FILE_OUTSIDE_ROOT", // The file is outside the project root and cannot be accessed. + WEBINIZER_FILE_READONLY = "WEBINIZER_FILE_READONLY", // The file is readonly. + WEBINIZER_FILE_UNKNOWN_SYMBOLIC = "WEBINIZER_FILE_UNKNOWN_SYMBOLIC", // The file is symbolic link to an unknown file. + WEBINIZER_FILE_EXT = "WEBINIZER_FILE_EXT", // The file already exists. + WEBINIZER_FILE_NOEXT = "WEBINIZER_FILE_NOEXT", // The file doesn't exist. + /* Directory */ + WEBINIZER_DIR_OUTSIDE_ROOT = "WEBINIZER_DIR_OUTSIDE_ROOT", // The directory is outside the project root and cannot be accessed. + WEBINIZER_DIR_EXT = "WEBINIZER_DIR_EXT", // The directory already exists. + WEBINIZER_DIR_NOEXT = "WEBINIZER_DIR_NOEXT", // The directory doesn't exist. + WEBINIZER_DIR_COPY_FAIL = "WEBINIZER_DIR_COPY_FAIL", // Failed to copy a directory. + WEBINIZER_DIR_DEL_FAIL = "WEBINIZER_DIR_DEL_FAIL", // Failed to delete a directory. + WEBINIZER_DIR_MV_FAIL = "WEBINIZER_DIR_MV_FAIL", // Failed to rename a directory. + /* Builder */ + WEBINIZER_BUILDER_UNDEFINED = "WEBINIZER_BUILDER_UNDEFINED", // No builders are defined yet for building. + /* Advisor */ + WEBINIZER_ADVISOR_UNKNOWN = "WEBINIZER_ADVISOR_UNKNOWN", // Unknown advisor type. + /* Advisor Pipeline */ + WEBINIZER_ADVISOR_PIPELINE_FILE_NOEXT = "WEBINIZER_ADVISOR_PIPELINE_FILE_NOEXT", // "advisor_pipelines.json" file does not exist. + WEBINIZER_ADVISOR_PIPELINE_FILE_LOAD_FAIL = "WEBINIZER_ADVISOR_PIPELINE_FILE_LOAD_FAIL", // "advisor_pipelines.json" file loading failed. + /* Actions */ + WEBINIZER_ACTION_FILE_INTERSECT = "WEBINIZER_ACTION_FILE_INTERSECT", // Lines are intersected in file change actions. + WEBINIZER_ACTION_BUILDSTEP_INTERSECT = "WEBINIZER_ACTION_BUILDSTEP_INTERSECT", // Build step indexes are intersected in build step change actions. + /* Json Factory */ + WEBINIZER_JSONFACTORY_DUP_REG = "WEBINIZER_JSONFACTORY_DUP_REG", // Factory type has already registered. + WEBINIZER_JSONFACTORY_DESERIALIZE_FAIL = "WEBINIZER_JSONFACTORY_DESERIALIZE_FAIL", // Fail to deserialize from Json object. + /* Build Process */ + WEBINIZER_PROCESS_MULTI_BUILD = "WEBINIZER_PROCESS_MULTI_BUILD", // Multiple build at the same time is not allowed for the same project. + WEBINIZER_PROCESS_UPDATE_UNDER_BUILD = "WEBINIZER_PROCESS_UPDATE_UNDER_BUILD", // Can't update configs and files when the project is under build. + WEBINIZER_PROJ_INIT_FAIL = "WEBINIZER_PROJ_INIT_FAIL", //Initialize the project with git failed + WEBINIZER_PROJ_GIT_CLONE_FAIL = "WEBINIZER_PROJ_GIT_CLONE_FAIL", //Clone the project with git failed + WEBINIZER_PROJ_GIT_REPO_PATH_INVALID = "WEBINIZER_PROJ_GIT_REPO_PATH_INVALID", //The repo's path is invalid + WEBINIZER_PROJ_PATH_INVALID = "WEBINIZER_PROJ_PATH_INVALID", //The path is invalid + WEBINIZER_PROJ_PACKAGE_INVALID = " WEBINIZER_PROJ_PACKAGE_INVALID", // The upload project package does not meet requirement + WEBINIZER_PROJ_TARGET_NOEXT = "WEBINIZER_PROJ_TARGET_NOEXT", // The project build target doesn't exist + /* Metadata */ + WEBINIZER_META_UNDEFINED = "WEBINIZER_META_UNDEFINED", // Metadata file package.json is not defined + WEBINIZER_META_PARSE_FAILED = "WEBINIZER_META_PARSE_FAILED", // Failed to parse the metadata json file + WEBINIZER_META_FIELD_UNDEFINED = "WEBINIZER_META_FIELD_UNDEFINED", // Required metadata field is undefined + WEBINIZER_META_SCHEMA_VALIDATION_FAILED = "WEBINIZER_META_SCHEMA_VALIDATION_FAILED", // Metadata failed to pass the schema validation + /* Registry */ + WEBINIZER_REG_PKG_INVALID = "WEBINIZER_REG_PKG_INVALID", // The requested package is not found + WEBINIZER_REG_VER_INVALID = "WEBINIZER_REG_VER_INVALID", // The requested package version is invalid + WEBINIZER_REG_PUBLISH_FAIL = "WEBINIZER_REG_PUBLISH_FAIL", // Publish package failed + WEBINIZER_REG_PACK_FAIL = "WEBINIZER_REG_PACK_FAIL", // Pack package failed + WEBINIZER_REG_UNDEFINED = "WEBINIZER_REG_UNDEFINED", // Registry is not defined + WEBINIZER_REG_ADDR_INVALID = "WEBINIZER_REG_ADDR_INVALID", // Registry address is invalid + /* Package Manager */ + WEBINIZER_PM_VER_INVALID = "WEBINIZER_PM_VER_INVALID", // No valid version found for a package + WEBINIZER_PM_VER_CONFLICT = "WEBINIZER_PM_VER_CONFLICT", // Resolving dependencie fail due to package version conflict + WEBINIZER_PM_CIRCULAR_DEP = "WEBINIZER_PM_CIRCULAR_DEP", // Circular dependency is not allowed + WEBINIZER_PM_PORT_CONFLICT = "WEBINIZER_PM_PORT_CONFLICT", // Different ports of the same native library is not allowed + /* Default */ + WEBINIZER_DEFAULT = "WEBINIZER_DEFAULT", // Default error code. +} + +export default errorCode; diff --git a/src/extension.ts b/src/extension.ts new file mode 100644 index 0000000..bc1f6cf --- /dev/null +++ b/src/extension.ts @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import fs from "graceful-fs"; +import * as H from "./helper"; +import path from "path"; +import writeFileAtomic from "write-file-atomic"; +import { EXTENSION_SRC_HOME } from "./constants"; +import errorCode from "./error_code"; +import { Settings } from "./settings"; +import * as prettier from "prettier"; + +export interface IExtensionAction { + __type__: string; + desc: string; +} + +export interface IExtensionAdvisor { + __type__: string; + desc: string; + tags: string[]; +} + +export interface IExtensionAnalyzer { + __type__: string; + desc: string; +} + +export interface IExtensionBuilder { + __type__: string; + desc: string; +} +export interface IExtMetaInPkgJson { + status: "enable" | "disable"; + actions?: IExtensionAction[]; + advisors?: IExtensionAdvisor[]; + analyzers?: IExtensionAnalyzer[]; + builders?: IExtensionBuilder[]; +} +export interface IExtensionMeta { + name: string; + version: string; + description: string; + webinizerExtMeta: IExtMetaInPkgJson; +} + +export interface IExtensionSettingsJson { + desc: string; + status: "enable" | "disable"; +} + +export interface IExtensionSettings extends IExtensionSettingsJson { + updateStatus(status: "enable" | "disable"): void; +} + +const log = H.getLogger("extension"); + +function loadExtMeta(name: string): IExtensionMeta | null { + const extPath = path.join(EXTENSION_SRC_HOME, name, "package.json"); + try { + const pkgJson = JSON.parse(fs.readFileSync(extPath, "utf8")); + return pkgJson as IExtensionMeta; + //eslint-disable-next-line + } catch (err: any) { + let errMsg; + if (err.code === "ENOENT") { + errMsg = `Extension metadata file ${extPath} does not exist.`; + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_EXT_META_NOEXT); + } + errMsg = + `Failed to load extension metadata from file ${extPath} due to error:\n` + + H.normalizeErrorOutput(err as Error); + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_EXT_META_LOAD_FAIL); + } +} + +async function loadExtensionByName(name: string) { + /** + * Skip the load for node_modules folder. This is a workaround for exntensions to load + * the webinizer module from a global import. + */ + if (name === "node_modules") return; + + const extMeta = loadExtMeta(name); + if (extMeta !== null && extMeta.webinizerExtMeta !== null) { + if (extMeta.webinizerExtMeta.status === "enable") { + let extension; + const extIndexPath = + process.env.npm_lifecycle_event === "test" + ? path.join(EXTENSION_SRC_HOME, name, "src", "index.ts") + : path.join(EXTENSION_SRC_HOME, name, "dist", "index.js"); + if (fs.existsSync(extIndexPath)) { + extension = await import(extIndexPath); + } + if (extension && "default" in extension) { + await extension.default(); + } + } + Settings.registerFromExtensions(extMeta.name, { + desc: extMeta.description, + status: extMeta.webinizerExtMeta.status, + updateStatus: (status: "enable" | "disable") => { + log.info(`... update status for extension ${extMeta.name} as ${status}`); + const updatedExtMeta = Object.assign({}, extMeta.webinizerExtMeta, { status }); + const updatedPkgJson = Object.assign({}, extMeta, { webinizerExtMeta: updatedExtMeta }); + const formatted = prettier.format(JSON.stringify(updatedPkgJson), { + parser: "json", + }); + writeFileAtomic.sync(path.join(EXTENSION_SRC_HOME, name, "package.json"), formatted, { + mode: 0o0600, + }); + }, + }); + } +} + +export async function loadAllExtensions() { + try { + const extensions = fs.readdirSync(EXTENSION_SRC_HOME); + for (const ext of extensions) { + const extPath = path.join(EXTENSION_SRC_HOME, ext); + try { + if (fs.statSync(extPath).isDirectory()) { + await loadExtensionByName(ext); + } + //eslint-disable-next-line + } catch (error: any) { + if ( + error.code === errorCode.WEBINIZER_EXT_META_NOEXT || + error.code === errorCode.WEBINIZER_EXT_META_LOAD_FAIL + ) { + throw error as H.WError; + } else { + const errorMsg = + `Failed to load extension from directory ${extPath} due to error:\n` + + H.normalizeErrorOutput(error as Error); + log.error(errorMsg); + throw new H.WError(errorMsg, errorCode.WEBINIZER_EXT_DIR_LOAD_FAIL); + } + } + } + //eslint-disable-next-line + } catch (err: any) { + if ( + err.code === errorCode.WEBINIZER_EXT_META_NOEXT || + err.code === errorCode.WEBINIZER_EXT_META_LOAD_FAIL || + err.code === errorCode.WEBINIZER_EXT_DIR_LOAD_FAIL + ) { + throw err as H.WError; + } else { + let errMsg; + if (err.code === "ENOENT") { + errMsg = `Extension Home Directory "${EXTENSION_SRC_HOME}" does not exist.`; + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_EXT_HOME_DIR_NOEXT); + } else { + errMsg = + `Failed to read extension home directory ${EXTENSION_SRC_HOME} due to error:\n` + + H.normalizeErrorOutput(err as Error); + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_EXT_HOME_DIR_LOAD_FAIL); + } + } + } +} diff --git a/src/helper.ts b/src/helper.ts new file mode 100644 index 0000000..ea8db91 --- /dev/null +++ b/src/helper.ts @@ -0,0 +1,493 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Commonly shared functions, types etc. + * + * @module + * @example + * ```typescript + * import * as H from "./helper"; + * const log = H.getLogger("test"); + * ``` + */ +import { ChildProcess } from "child_process"; + +import glob from "glob"; +import * as shell from "shelljs"; +import * as _ from "lodash"; +import fs from "graceful-fs"; + +import { format as _prettyFormat } from "pretty-format"; + +import logger from "./logger"; +import errorCode from "./error_code"; + +export const prettyFormat = _prettyFormat; +// re-export logger functions as part of helper +export const getLogger = logger.get; +export const getGlobalLogWriter = logger.getGlobalLogWriter; +export const setDefaultLogLevel = logger.setDefaultLevel; +export const onlyLogCategories = logger.onlyAllowCategories; +export const forbidLogCategories = logger.forbidCategories; +export interface Dict { + [k: string]: T; +} + +const _log = logger.get("helper"); +export function assert(check: boolean, ...msgs: any[]) { + if (!check) { + _log.customOutput(4 /* fatal */, 2, ...msgs); + } +} + +export function messageBlock(title: string, msg: string, char = "-", width = 80): string { + const titleBar = char.repeat( + Math.max(0, Math.floor((width - title.length - 2) / 2 / char.length)) + ); + const bottomBar = char.repeat(Math.floor(width / char.length)); + + return `\n${titleBar} ${title} ${titleBar}\n${msg}\n${bottomBar}`; +} + +export class XError extends Error { + type = "unknown"; + constructor(type: string, message: string) { + super(message); + this.type = type; + } +} + +// WebinizerError: errors with webinizer specific code +export class WError extends Error { + constructor(message: string, code: errorCode) { + super(message); + this.name = code; + } +} + +/** + * Serialize `Error` + * @param err `Error` to be serialized + * @returns Stringified Error with below struct + * ```ts + * { + * name: string; // webinizer error code or default name of `Error` class + * message: string; // error message + * } + * ``` + */ +export function serializeError(err: Error): { name: string; message: string } { + return { name: err.name, message: err.message }; +} + +/** + * Normalize `Error` output + * @param err `Error` to be normalized + * @returns `error stack` or `error name: error message` + */ +export function normalizeErrorOutput(err: Error): string { + return err.stack || `${err.name}: ${err.message}`; +} + +/** + * Check whether ctor (usually a class) implements T. Compiler throws error if not + * @param ctor The class to check + * @example + * ```typescript + * interface XConstructor { + * staticMethod(): number; + * } + * class BadX { + * staticMethod() { return "123"; } + * } + * // compiler ERROR: it fails to convert BadX to XConstructor + * staticImplements(BadX); + * ``` + */ +export function staticImplements(ctor: T) {} //eslint-disable-line + +export function isObjectEmpty(o: object): boolean { + return Object.keys(o).length === 0; +} + +export const voidFunc = () => { + return; +}; + +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +/* eslint-disable @typescript-eslint/no-explicit-any */ +interface IDeferred { + resolve: (value: T | PromiseLike) => void; + reject: (reason?: any) => void; + promise: () => Promise; +} + +/** + * Mimic jQuery defer or Angual $q.defer. + * + * @example + * ```typescript + * function numberPromise(): Promise { + * const d = defer(); + * setTimeout(() => { + * d.resolve(100); + * }, 100); + * return d.promise(); + * } + * + * async function test() { + * console.log(await numberPromise()); // should print 5 + * } + * ``` + * @returns A deferred object + */ +export function defer(): IDeferred { + let res: (value: T | PromiseLike) => void = voidFunc, + rej: (reason?: any) => void = voidFunc; + const promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + return { + resolve: res, + reject: rej, + promise: () => promise, + }; +} +/* eslint-enable @typescript-eslint/no-explicit-any */ + +export interface ICommandResult { + code: number; // returned code + output: string; // output in stdout + error: string; // output in stderr + all: string; // all output (stdout + stderr) +} +/** + * A promise wrapper for async version of `shelljs.exec`. By default even if we captured all of the + * outputs, they are shown in the console as well, unless `{ silent: true }` is set into options. + * @param cmd Command to run. + * @param options Same options as `child_process.exec()`, e.g., cwd, env, silent, timeout, etc. + * @param onOut Callback function when there is any output in stdout. + * @param onErr Callback function when there is any output in stderr. + * @returns Promise resolved with {code, output, error, all}. + */ +export function runCommand( + cmd: string, + options = {}, + onOut?: (data: string) => void, + onErr?: (data: string) => void +): Promise { + return new Promise((resolve) => { + const logWriter = getGlobalLogWriter(); + const outStrings: string[] = []; + const errStrings: string[] = []; + const allStrings: string[] = []; + // force to be async so always returns a ChildProcess + const p = shell.exec( + cmd, + Object.assign(Object.assign({}, options), { async: true }) + ) as ChildProcess; + + if (p.stdout) { + p.stdout.on("data", (data: Buffer) => { + const strData = data.toString(); // Buffer -> String + outStrings.push(strData); + allStrings.push(strData); + if (logWriter) { + logWriter.updateLog(strData); + } + if (onOut) { + onOut(strData); + } + }); + } + if (p.stderr) { + p.stderr.on("data", (data: Buffer) => { + const strData = data.toString(); + errStrings.push(strData); + allStrings.push(strData); + if (logWriter) { + logWriter.updateLog(strData); + } + if (onErr) { + onErr(strData); + } + }); + } + + p.on("close", (code: number) => { + resolve({ + code: code, + output: outStrings.join(""), + error: errStrings.join(""), + all: allStrings.join(""), + }); + }); + }); +} + +//////////////////////////////////////////////////////////// +// Common Interfaces Here +//////////////////////////////////////////////////////////// +/** + * Find files/dir matching a pattern in a directory + * @param pattern The pattern to find, follows [`glob()`](@link https://www.npmjs.com/package/glob) + * @param rootDir Find patterns in this directory + * @param excludeDirs Array of directories to exclude from match + * @param fileOnly Exclude directories or not + * @param ignoreCase Case sensitive or not + * @param sortMatches Sort the matches alphabetically or not + */ +export function matchFilePath( + pattern: string, + rootDir: string, + excludeDirs: string[] = [], + fileOnly = true, + ignoreCase = false, + sortMatches = false +): string[] { + return glob.sync(pattern, { + cwd: rootDir, + ignore: excludeDirs.map((d) => `${d}/**`), // convert dir to ignore pattern + nodir: fileOnly, + nocase: ignoreCase, + nosort: !sortMatches, + }); +} + +export interface IPattern { + pattern: string; // Pattern for search + rootDir: string; // Find patterns in this directory + file: string; // File path relative to baseDir + line: number; // Line number with pattern match + content: string; // Content for matched line +} + +/** + * Find specific petterns in files using `grep` + * @param s Pattern for search + * @param dir Base directory for search + * @param excludeDirs Excluded directories for search + * @returns Array of matched files + */ +export async function findPatternInFiles( + s: string, + dir: string, + excludeDirs?: string[] +): Promise { + const patterns: IPattern[] = []; + const cmd = + excludeDirs && excludeDirs.length + ? `grep -rn ${excludeDirs.map((d) => `--exclude-dir=${d}`).join(" ")} "${s}"` + : `grep -rn "${s}"`; + const responses = await runCommand(cmd, { cwd: dir, silent: true }); + + for (const res of responses.output.split("\n")) { + if (res && !res.startsWith("Binary file")) { + const resBody = res.split(":"); + patterns.push({ + pattern: s, + rootDir: dir, + file: resBody[0], + line: Number(resBody[1]), + content: resBody[2], + }); + } + } + return patterns; +} + +/** + * Find differences from newObj to origObj + * @param origObj Original object + * @param newObj New object with potential changes + * @returns Differences from newObj to origObj,deleted entries are not shown + */ +export function getObjDifferenceInternal( + origObj: Dict, + newObj: Dict +): Dict { + function changes(newObj: Dict, origObj: Dict): Dict { + if (!_.isObject(origObj) || isObjectEmpty(origObj)) return _.cloneDeep(newObj); + if (!_.isObject(newObj) || isObjectEmpty(newObj)) return {}; + let arrayIndexCounter = 0; + return _.transform(newObj, (result: Dict, value: unknown, key: string) => { + if (!_.isEqual(value, origObj[key])) { + const resultKey = Array.isArray(origObj) ? String(arrayIndexCounter++) : key; + result[resultKey] = + _.isObject(value) && _.isObject(origObj[key]) + ? changes(value as Dict, origObj[key] as Dict) + : value; + } + }); + } + return changes(newObj, origObj); +} + +/** + * Merge differences from bi-directional diffs + * @param newToOld new to old diffs + * @param oldToNew old to new diffs + * @returns Merged diffs from newToOld and oldToNew, deleted entries will be set as `null` + */ +export function mergeDiffs(newToOld: Dict, oldToNew: Dict): Dict { + function changes(oldToNew: Dict, newToOld: Dict): Dict { + if (!_.isObject(oldToNew) || isObjectEmpty(oldToNew)) return _.cloneDeep(newToOld); + let arrayIndexCounter = 0; + return _.transform( + oldToNew, + (result: Dict, value: unknown, key: string) => { + // newToOld and oldToNew should not have equal key-value pair + const resultKey = Array.isArray(newToOld) ? String(arrayIndexCounter++) : key; + if (Object.keys(newToOld).includes(key)) { + result[resultKey] = + _.isObject(value) && _.isObject(newToOld[key]) + ? changes(value as Dict, newToOld[key] as Dict) + : newToOld[key]; + } else { + // set value to the resultKey as null as this is deleted in the newObj (not a key in newToOld) + result[resultKey] = null; + } + }, + // set the initial value of accumulator as the same of newToOld + _.cloneDeep(newToOld) + ); + } + return changes(oldToNew, newToOld); +} + +/** + * Find complete differences (add, update, delete) between two objects + * @param origObj Original object + * @param newObj New object with potential changes + * @returns Differences from newObj to origObj, deleted entries will be set as `null` + */ +export function getObjDifference(origObj: Dict, newObj: Dict): Dict { + const newToOld = getObjDifferenceInternal(origObj, newObj); + const oldToNew = getObjDifferenceInternal(newObj, origObj); + return mergeDiffs(newToOld, oldToNew); +} + +/** + * Table text align type + */ +type TableAlignStyle = "middle" | "left" | "right"; + +/** + * Convert to a Markdown format table + * @param header Array of header string (first row) + * @param content Array of each content row with order + * @param style Array of the the text align style of each column, `middle` by default + * @returns The table string in Markdown format + */ +export function constructMarkdownTable( + header: string[], + content: string[][], + style?: TableAlignStyle[] +): string { + const styleMap = { + middle: `| :--------------: `, + left: `| :-------------- `, + right: `| --------------: `, + } as { [k in TableAlignStyle]: string }; + const tableWidth = header.length; + /* table border */ + let tableBorder = ""; + if (!style) { + // if no style defined for each column, use `middle` as default + tableBorder = styleMap["middle"].repeat(tableWidth) + "|"; + } else { + if (style.length === tableWidth) { + // apply each style to each column accordingly + style.forEach((s) => { + tableBorder += styleMap[s]; + }); + tableBorder += "|"; + } else { + // use the last style for the rest columns + style.forEach((s) => { + tableBorder += styleMap[s]; + }); + tableBorder += styleMap[style[style.length - 1]].repeat(tableWidth - style.length) + "|"; + } + } + /* table header */ + let headerRow = ""; + header.forEach((h) => { + headerRow += `| **${h}** `; + }); + headerRow += "|"; + /* table content */ + let tableContent = ""; + content.forEach((line) => { + if (line.length === tableWidth) { + tableContent += + line + .map((words) => { + return `| ${words} `; + }) + .join("") + "|\n"; + } + }); + return `${headerRow}\n${tableBorder}\n${tableContent}\n`; +} + +/** + * Backup a folder + * @param srcDir The folder directory to be backuped + * @param destDir The destination directory + */ +export function backupFolderSync(srcDir: string, destDir: string) { + try { + fs.cpSync(srcDir, destDir, { recursive: true }); + _log.info(`Copy folder from ${srcDir} to ${destDir} successfully.`); + } catch (error) { + _log.error(`An error occurred while copying folder '${srcDir}':`, error); + throw new WError( + `An error occurred while copying folder '${srcDir}':\n${error}`, + errorCode.WEBINIZER_DIR_COPY_FAIL + ); + } +} + +/** + * Delete a folder + * @param dir The folder directory to be deleted + */ +export function deleteFolder(dir: string) { + try { + fs.rmSync(dir, { recursive: true }); + _log.info(`Delete folder '${dir}' successfully.`); + } catch (error) { + _log.error(`An error occurred while deleting folder '${dir}':`, error); + throw new WError( + `An error occurred while deleting folder '${dir}:\n${error}'`, + errorCode.WEBINIZER_DIR_DEL_FAIL + ); + } +} + +/** + * Rename a folder + * @param oldPath The old path of the folder + * @param newPath The new path of the folder + */ +export function renameFolder(oldPath: string, newPath: string) { + try { + fs.renameSync(oldPath, newPath); + _log.info(`Folder '${oldPath}' is renamed as '${newPath}' successfully.`); + } catch (error) { + _log.error(`An error occurred while renaming folder '${oldPath}':`, error); + throw new WError( + `An error occurred while moving folder '${oldPath}':\n${error}`, + errorCode.WEBINIZER_DIR_MV_FAIL + ); + } +} diff --git a/src/init.ts b/src/init.ts new file mode 100644 index 0000000..19842a3 --- /dev/null +++ b/src/init.ts @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import fs from "graceful-fs"; +import * as H from "./helper"; +import { loadAllExtensions } from "./extension"; +import errorCode from "./error_code"; +import { moduleDirectories } from "./constants"; + +const log = H.getLogger("initialization"); + +async function loadAndExecuteModule(p: string) { + const m = await import(p); + if (m && "default" in m) { + await m.default(); + } +} + +async function checkToolchainReadiness() { + // check whether emscripten is configured in path or not + const emccVer = await H.runCommand("emcc --version", { silent: true }); + if (emccVer.code !== 0) { + log.error( + "Emscripten is not configured in PATH. Please run the 'source ./emsdk_env.sh' command from the emsdk folder before initializing Webinizer." + ); + throw new H.WError( + "Emscripten is not configured in PATH.", + errorCode.WEBINIZER_INIT_TOOLCHAIN_CHECK_FAIL + ); + } +} + +export async function loadAllModulesInDirctory(dir: string) { + try { + const modules = fs.readdirSync(dir); + + for (const m of modules) { + if (m.endsWith(".js") || m.endsWith(".ts")) { + const modulePath = path.join(dir, m); + try { + if (fs.statSync(modulePath).isFile()) { + await loadAndExecuteModule(modulePath); + } + //eslint-disable-next-line + } catch (error: any) { + const errorMsg = + `Failed to load module from path ${modulePath} due to error:\n` + + H.normalizeErrorOutput(error as Error); + log.error(errorMsg); + throw new H.WError(errorMsg, errorCode.WEBINIZER_INIT_MODULE_LOAD_FAIL); + } + } + } + //eslint-disable-next-line + } catch (err: any) { + let errMsg; + if (err.code === "ENOENT") { + errMsg = `Module Directory "${dir}" does not exist.`; + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_INIT_MODULE_DIR_NOEXT); + } else { + if (err.code === errorCode.WEBINIZER_INIT_MODULE_LOAD_FAIL) { + throw err as H.WError; + } else { + errMsg = + `Failed to load modules from directory ${dir} due to error:\n` + + H.normalizeErrorOutput(err as Error); + log.error(errMsg); + throw new H.WError(errMsg, errorCode.WEBINIZER_INIT_MODULE_DIR_LOAD_FAIL); + } + } + } + + return; +} + +export async function init() { + await checkToolchainReadiness(); + for (const md of moduleDirectories) { + await loadAllModulesInDirctory(md); + } + + await loadAllExtensions(); +} diff --git a/src/json_factory.ts b/src/json_factory.ts new file mode 100644 index 0000000..bdda0dd --- /dev/null +++ b/src/json_factory.ts @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import chalk from "chalk"; +import * as H from "./helper"; +import errorCode from "./error_code"; +import { IJsonObject, IFromJson, FromJsonMethod, Project as IProject } from "webinizer"; + +const log = H.getLogger("factory"); + +export function checkJsonType(type: string, o: IJsonObject) { + H.assert(type === o.__type__, `Json expects ${type} but got ${o.__type__}`); +} + +// By default, the Factory only contains fromJson(), but if one need to add more +// items into it, you could explictly pass in X as well. +export class JsonFactories< + T, + X extends IFromJson | FromJsonMethod = IFromJson | FromJsonMethod +> implements IFromJson +{ + name: string; + private _map = new Map(); + constructor(name: string) { + this.name = name; + } + fromJson(proj: IProject, o: IJsonObject, index: number): T | null { + const f = this._map.get(o.__type__); + if (f) { + // eslint-disable-next-line + if (typeof (f as any).fromJson === "function") { + return (f as IFromJson).fromJson(proj, o, index); + } else { + return (f as FromJsonMethod)(proj, o, index); + } + } + return null; + } + register(type: string, method_or_factory: X) { + if (this._map.has(type)) { + throw new H.WError( + `Factory for type ${type} has already been registered.`, + errorCode.WEBINIZER_JSONFACTORY_DUP_REG + ); + } + this._map.set(type, method_or_factory); + const head = `<< ${this.name} >>`; + log.info(`* ${chalk.yellowBright(head)} - registered ${chalk.cyanBright(type)}`); + } + factoriesMap(): Map { + return this._map; + } + + // build an array of objects. Throw Error if any of the json failed to deserialize + fromJsonArray(proj: IProject, arr: IJsonObject[]): T[] { + return arr.map((json, index) => { + const o = this.fromJson(proj, json, index); + if (o) { + return o; + } + throw new H.WError( + `fromJson() returns null for ${JSON.stringify(o, null, 1)}.`, + errorCode.WEBINIZER_JSONFACTORY_DESERIALIZE_FAIL + ); + }); + } +} diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..b543053 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,331 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Log utility + * + * @module + * + * @example + * ```typescript + * import logger from "./logger"; + * log = logger.get("mycategory"); + * log.debug("debug message", x); + * log.info("default", x); + * log.warn("warn", x, y, z); + * log.error("error", x, y); + * log.fatal("fatal", x, y); + * ``` + */ + +import chalk from "chalk"; +import Moment from "moment"; +import process from "process"; +import fs from "graceful-fs"; +import path from "path"; +import writeFileAtomic from "write-file-atomic"; +import { homedir } from "os"; + +// Dict and isObjectEmpty(...) are also defined and exported in helper.ts +// However, helper.ts will import logger.ts so we copied them here. +interface Dict { + [k: string]: T; +} +function isObjectEmpty(o: object): boolean { + return Object.keys(o).length === 0; +} + +// levels +const levelNames = ["debug", "info", "warn", "error", "fatal"] as const; +type logLevelType = (typeof levelNames)[number]; + +// The default level which controls the output. Each Logger could specify its own to replace this +// default is "info" +let defaultLevelValue = 1; +// Globally we could config the categories to show. It's the allowed categories substract all +// categories forbidden. Note empty categoriesAllowed below actaully means all are allowed + +let categoriesAllowed: Dict = {}; // empty actaully means all are allowed +let categoriesForbidden: Dict = {}; // empty means none is forbidden + +const formatters = { + debug: { + time: chalk.gray, + level: (x: string) => chalk.bgGray(chalk.white(x)), + category: chalk.greenBright, + }, + info: { + time: chalk.gray, + level: (x: string) => chalk.bgBlue(chalk.white(x)), + category: chalk.greenBright, + }, + warn: { + time: chalk.gray, + level: (x: string) => chalk.bgMagenta(chalk.white(x)), + category: chalk.greenBright, + }, + error: { + time: chalk.gray, + level: (x: string) => chalk.bgRed(chalk.white(x)), + category: chalk.greenBright, + }, + fatal: { + time: chalk.gray, + level: (x: string) => chalk.bgRedBright(chalk.whiteBright(x)), + category: chalk.greenBright, + }, +}; + +/** + * Log Writer + */ +class GlobalLogWriter { + private _file: string; + private _content: string; + private static _instance: GlobalLogWriter; + + private constructor() { + const date = Moment().format(); + this._file = path.join(homedir(), ".webinizer", "logs", `webinizer-debug-log-${date}.log`); + this._content = `Webinizer debug log at ${date}\n`; + this.save(); + } + + static getInstance(): GlobalLogWriter { + if (!GlobalLogWriter._instance) { + GlobalLogWriter._instance = new GlobalLogWriter(); + } + return GlobalLogWriter._instance; + } + + updateLog(data: string) { + this._content += data; + this.save(); + } + + save() { + try { + // this doesn't report error if already exists because recursive is set to true + fs.mkdirSync(path.dirname(this._file), { mode: 0o0700, recursive: true }); + writeFileAtomic.sync(this._file, this._content, { + mode: 0o0600, + }); + // eslint-disable-next-line + } catch (err: any) { + // webinizer logger is not initialized yet, using console instead. + console.log( + `Failed to save ${this._content} to file`, + this._file, + "due to error:", + err.message + ); + throw err; + } + } +} + +// the unique global log writer instance +const logWriter = GlobalLogWriter.getInstance(); + +/** + * Logger + */ +class Logger { + private _category: string; + private _enabled: boolean; + + /** If this is -1, it uses defaultLevelValue, otherwise use this one to control output or not */ + private _levelValue = -1; + + /** + * Actual class for outputting logs. + * @param category Category name + * @param enabled false to turn it off + */ + constructor(category: string, enabled: boolean) { + this._category = category; + this._enabled = enabled; + } + + private _willOutput(levelValue: number): boolean { + // always show >= error + if (levelValue >= 3) { + return true; + } + const level = this._levelValue < 0 ? defaultLevelValue : this._levelValue; + if (!this._enabled || levelValue < level || this._category in categoriesForbidden) { + return false; + } + return isObjectEmpty(categoriesAllowed) || this._category in categoriesAllowed; + } + + // if nSliceStack >= 0, print the stack as well - but slice the first nSliceStack lines + customOutput(levelValue: number, nSliceStack: number, ...args: any[]): void { + if (!this._willOutput(levelValue)) { + return; + } + const level = levelNames[levelValue]; + const formatter = formatters[level]; + + let customLogger = console.log; + // check if global log writer is defined + if (logWriter) { + customLogger = function (...d) { + const output = + d + .map((o) => { + return typeof o === "object" ? JSON.stringify(o, null, 1) : o; + }) + .join(" ") + "\n"; + process.stdout.write(output); + logWriter.updateLog(output); + }; + } + // check if callback function is appended in the last + if (args.length && typeof args[args.length - 1] === "function") { + type cb = (data: string) => void; + const dumpOutput = args.pop() as cb; + customLogger = function (...d) { + const output = + d + .map((o) => { + return typeof o === "object" ? JSON.stringify(o, null, 1) : o; + }) + .join(" ") + "\n"; + process.stdout.write(output); + dumpOutput(output); + if (logWriter) { + logWriter.updateLog(output); + } + }; + } + customLogger( + formatter.time(Moment().format("hh:mm:ss")), + formatter.level(level.padEnd(5)), + formatter.category(this._category), + ...args + ); + if (nSliceStack >= 0) { + const stacks = (new Error().stack || "") + .split("\n") + .slice(nSliceStack) + .map((x: string) => { + return " " + x.trim(); + }); + if (stacks) { + stacks[0] = stacks[0].trim(); + } + customLogger(formatter.level(" >>>"), stacks.join("\n")); + } + } + + debug(...args: any[]): void { + this.customOutput(0, -1, ...args); + } + + info(...args: any[]): void { + this.customOutput(1, -1, ...args); + } + + warn(...args: any[]): void { + this.customOutput(2, -1, ...args); + } + + error(...args: any[]): void { + this.customOutput(3, 2, ...args); + } + + fatal(...args: any[]): void { + this.customOutput(4, 2, ...args); + process.exit(1); + } + + /** + * Set the level to control the output. For example, if it is set to "info", then debug(...) will + * not output anything. + * + * If we invoked setLevel() without any value, it will reset the level of this specific logger, + * and will use the one at system level, which is controlled by `setDefaultLevel()` of + * {@link logger} to decide whether to output or not. + * + * @param level The new level. If it is omitted, this Logger will use system level control. + * @returns The old level + */ + setLevel(level?: logLevelType): logLevelType { + const oldLevel = levelNames[this._levelValue]; + if (level === undefined) { + this._levelValue = -1; + } else { + this._levelValue = levelNames.indexOf(level); + } + return oldLevel; + } +} + +/** + * logger interface + */ +const logger = { + /** + * Default level to control output a log or not. Each Logger could use setLevel() to specifically + * control the level by itself. + * @param level New default level + * @returns Old default level + */ + setDefaultLevel(level: logLevelType): logLevelType { + const oldLevel = levelNames[defaultLevelValue]; + defaultLevelValue = levelNames.indexOf(level); + return oldLevel; + }, + + /** + * Get the global log writer + * @returns The global log writer + */ + getGlobalLogWriter(): GlobalLogWriter { + return logWriter; + }, + + /** + * Create a Logger. It's called get() for convention, but it's actaully mean create(). That means, + * if you call it with the same category twice, it create two separated Logger for you, instead of + * a shared one. + * @param category this classifies the log and itself will show and highlight in console + * @param enabled set it false will disable it at all + * @returns A Logger that you could info(), ... + */ + get(category: string, enabled = true): Logger { + return new Logger(category, enabled); + }, + + /** + * Only allow some categories to show. Set it to [] means to clear this, i.e. allowing all to show + * @param cats Categories allowed to show, like a filter. [] means allowing all. + * @returns Old cateogories + */ + onlyAllowCategories(cats: string[]): string[] { + const old = Array.from(Object.keys(categoriesAllowed)); + categoriesAllowed = cats.reduce((acc, v) => { + return { ...acc, [v]: true }; + }, {}); + return old; + }, + + /** + * Categories in this list aren't allowed to show + * @param cats Categories not allowed to show + * @returns Old categories + */ + forbidCategories(cats: string[]): string[] { + const old = Array.from(Object.keys(categoriesForbidden)); + categoriesForbidden = cats.reduce((acc, v) => { + return { ...acc, [v]: true }; + }, {}); + return old; + }, +}; + +export default logger; diff --git a/src/package_manager/fetcher.ts b/src/package_manager/fetcher.ts new file mode 100644 index 0000000..3998eaa --- /dev/null +++ b/src/package_manager/fetcher.ts @@ -0,0 +1,255 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Package Fetcher + * @module + */ + +import pacote from "pacote"; +import * as _ from "lodash"; +import fs from "graceful-fs"; +import writeFileAtomic from "write-file-atomic"; +import path from "path"; +import * as H from "../helper"; +import errorCode from "../error_code"; +import { Project } from "../project"; +import { IPackageSpec } from "./resolver"; +import { Settings } from "../settings"; +import npa from "npm-package-arg"; + +const log = H.getLogger("package_fetcher"); + +// A wrapper over pacote implementation +export type IRegistryOptions = pacote.Options; +export type IPackageManifest = pacote.AbbreviatedManifest & pacote.ManifestResult; +export type IPackagePackument = pacote.AbbreviatedPackument & pacote.PackumentResult; + +class BaseFetcher { + spec: string; + options: IRegistryOptions | undefined; + registryValidity = true; + constructor(spec: string, options?: IRegistryOptions) { + this.spec = spec; + if (options) this.options = { ...options }; + // registry validation for fetcher for registry + const result = npa(this.spec); + switch (result.type) { + case "version": + case "range": + case "tag": + case "alias": + if (!Settings.registry) this.registryValidity = false; + break; + default: // no registry check required + } + } + + async getManifest(): Promise { + this.checkRegistryValidity(); + try { + const fetchOpts = this.getRegistryBaseOptions(); + if (this.options) { + _.extend(fetchOpts, this.options); + } + log.info(`getManifest with spec:`, this.spec); + const manifest = await pacote.manifest(this.spec, fetchOpts); + return manifest; + //eslint-disable-next-line + } catch (error: any) { + if (error.code === "E404") { + log.error(`No package found for ${this.spec}`); + throw new H.WError( + `No package found for ${this.spec}`, + errorCode.WEBINIZER_REG_PKG_INVALID + ); + } + if (error.code === "ETARGET" && error.type === "version") { + log.error(`No matching version ${error.wanted} found for ${this.spec}`); + throw new H.WError( + `No matching version ${error.wanted} found for ${this.spec}`, + errorCode.WEBINIZER_REG_VER_INVALID + ); + } + throw error; + } + } + + async getPackument(): Promise { + this.checkRegistryValidity(); + try { + const fetchOpts = this.getRegistryBaseOptions(); + if (this.options) { + _.extend(fetchOpts, this.options); + } + log.info(`getPackument with spec:`, this.spec); + const packument = await pacote.packument(this.spec, fetchOpts); + return packument; + //eslint-disable-next-line + } catch (error: any) { + if (error.code === "E404") { + log.error(`No package found for ${this.spec}`); + throw new H.WError( + `No package found for ${this.spec}`, + errorCode.WEBINIZER_REG_PKG_INVALID + ); + } + throw error; + } + } + + async fetchPackage(dest: string) { + this.checkRegistryValidity(); + try { + const fetchOpts = this.getRegistryBaseOptions(); + if (this.options) { + _.extend(fetchOpts, this.options); + } + const fetched = await pacote.extract(this.spec, dest, fetchOpts); + log.info(`Fetch package ${this.spec} from ${fetched.resolved} successfully at ${dest}`); + //eslint-disable-next-line + } catch (error: any) { + log.error(`Fetch package ${this.spec} fail due to error`, error as Error); + throw error; + } + } + + getRegistryBaseOptions(): IRegistryOptions { + if (this.registryValidity) + return { + registry: Settings.registry, + }; + return {}; + } + + checkRegistryValidity() { + if (!this.registryValidity) { + log.warn(`No registry is set in Webinizer settings!`); + throw new H.WError( + "No registry is set in Webinizer settings.", + errorCode.WEBINIZER_REG_UNDEFINED + ); + } + } +} + +// subclass DirFetcher - handle local dependency +class DirFetcher extends BaseFetcher { + constructor(spec: string, options?: IRegistryOptions) { + super(spec, options); + } + + // ensure package.json and config.json are always synced up-to-date + async preparePackageJson() { + // `spec` is path to a local directory + const proj = new Project(this.spec, false); + if (fs.existsSync(proj.config.path)) { + await proj.config.convertToRegMetaForPublish(); + } + if (fs.existsSync(proj.meta.path)) { + // validate metadata schema + proj.meta.validateMetaSchema(_.cloneDeep(proj.meta.data)); + await H.runCommand(`git add package.json && git add -u`, { + cwd: proj.root, + silent: true, + }); + } else { + throw new H.WError("No metadata defined for package.", errorCode.WEBINIZER_META_UNDEFINED); + } + } + + async getManifest(): Promise { + await this.preparePackageJson(); + return super.getManifest(); + } + + async getPackument(): Promise { + await this.preparePackageJson(); + return super.getPackument(); + } + + async fetchPackage(dest: string) { + try { + await this.preparePackageJson(); + + // prepare .npmignore to exclude files for packing (based on git untracked files list) + const untracked = await H.runCommand("git ls-files --others --exclude-standard", { + cwd: this.spec, + silent: true, + }); + if (untracked.code === 0) { + const untrackedList = untracked.all + .split("\n") + .filter((line) => line.trim()) + .map((line) => "/" + line.trim()); // add "/" to the beginning to specify files/dirs relative to .npmignore + // add .webinizer/config.json to ignore list + if (!untrackedList.includes("/.webinizer/config.json")) { + untrackedList.push("/.webinizer/config.json"); + } + // create .npmignore file + writeFileAtomic.sync(path.join(this.spec, ".npmignore"), untrackedList.join("\n") + "\n", { + mode: 0o0600, + }); + } + + // pack the package + const pack = await H.runCommand("npm pack --json", { cwd: this.spec, silent: true }); + if (pack.code !== 0) { + log.warn(`Failed to pack package ${this.spec} due to error`, pack.error); + throw new H.WError( + `Failed to pack package ${this.spec} due to error ${pack.error}`, + errorCode.WEBINIZER_REG_PACK_FAIL + ); + } + + const packageFilename = JSON.parse(pack.output)[0].filename; + try { + const fetched = await pacote.extract(path.join(this.spec, packageFilename), dest); + log.info(`Fetch package ${this.spec} from ${fetched.resolved} successfully at ${dest}`); + // remove package.tgz file after extract successfully + fs.rmSync(path.join(this.spec, packageFilename)); + } catch (error) { + log.error(`Errors happend when extracting ${packageFilename} to ${dest}`, error as Error); + // if errors happened, remove both package.tgz and possibly the package folder. + fs.rmSync(path.join(this.spec, packageFilename), { force: true }); + fs.rmSync(dest, { recursive: true, force: true }); + throw error as Error; + } + //eslint-disable-next-line + } catch (error: any) { + log.error(`Fetch package ${this.spec} fail due to error`, error as Error); + throw error; + } + } +} + +export function getPackageFetcher( + { name, reference, version }: IPackageSpec, + options?: IRegistryOptions +): BaseFetcher | DirFetcher { + if (reference.startsWith("file:")) { + const filePath = reference.replace("file:", ""); + if (fs.existsSync(filePath)) { + const fileStat = fs.statSync(filePath); + if (fileStat.isDirectory()) { + return new DirFetcher(filePath, options); + } + if (fileStat.isFile()) { + const isFileName = /[.](?:tgz|tar.gz|tar)$/i; + if (isFileName.test(filePath)) return new BaseFetcher(filePath, options); + } + } + throw new H.WError( + `Invalid local package path ${reference}`, + errorCode.WEBINIZER_REG_PKG_INVALID + ); + } + if (version) { + return new BaseFetcher(`${name}@${version}`, options); + } else { + return new BaseFetcher(`${name}@${reference}`, options); + } +} diff --git a/src/package_manager/publish.ts b/src/package_manager/publish.ts new file mode 100644 index 0000000..d2a7b61 --- /dev/null +++ b/src/package_manager/publish.ts @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { Project } from "../project"; +import * as H from "../helper"; +import errorCode from "../error_code"; +import writeFileAtomic from "write-file-atomic"; +import * as _ from "lodash"; +import path from "path"; +import { Settings } from "../settings"; + +const log = H.getLogger("package_publish"); + +// publish project to registry +export default async function publish(proj: Project) { + if (!Settings.registry) { + log.warn(`No registry is set in Webinizer settings!`); + throw new H.WError( + "No registry is set in Webinizer settings.", + errorCode.WEBINIZER_REG_UNDEFINED + ); + } + // 1. convert config.json and save to package.json + await proj.config.convertToRegMetaForPublish(); + + // 2. validate package.json format before publish to ensure required fields exist + proj.meta.validateMetaSchema(_.cloneDeep(proj.meta.data)); + + // 3. git add all changes and commit + // Add `package.json` into commit tree by default + // Use `git add -u` to handle updated and deleted files only + const commit = await H.runCommand( + `git add package.json && git add -u && git commit -m '${proj.config.version}'`, + { + cwd: proj.root, + silent: true, + } + ); + if (commit.code !== 0) { + log.warn(`Commit changes for version ${proj.config.version} failed.\n`, commit.error); + throw new H.WError( + `Commit changes for version ${proj.config.version} failed due to error ${commit.error}`, + errorCode.WEBINIZER_REG_PUBLISH_FAIL + ); + } else log.info(`Committed changes for version ${proj.config.version}.`); + + // 4. prepare .npmignore to exclude files for publishing (based on git untracked files list) + const untracked = await H.runCommand("git ls-files --others --exclude-standard", { + cwd: proj.root, + silent: true, + }); + if (untracked.code === 0) { + const untrackedList = untracked.all + .split("\n") + .filter((line) => line.trim()) + .map((line) => "/" + line.trim()); // add "/" to the begining to specify files/dirs relative to .npmignore + // add .webinizer/config.json to ignore list + if (!untrackedList.includes("/.webinizer/config.json")) { + untrackedList.push("/.webinizer/config.json"); + } + // create .npmignore file + writeFileAtomic.sync(path.join(proj.root, ".npmignore"), untrackedList.join("\n") + "\n", { + mode: 0o0600, + }); + } + + // 5. publish + const publish = await H.runCommand(`npm publish --registry ${Settings.registry}`, { + cwd: proj.root, + }); + if (publish.code !== 0) { + log.warn(`Publish ${proj.config.name?.toLowerCase()} failed.\n`, publish.error); + // reset last commit if publish failed + await H.runCommand("git reset HEAD^", { cwd: proj.root, silent: true }); + throw new H.WError( + `Publish ${proj.config.name?.toLowerCase()} failed due to error ${publish.error}`, + errorCode.WEBINIZER_REG_PUBLISH_FAIL + ); + } +} diff --git a/src/package_manager/resolver.ts b/src/package_manager/resolver.ts new file mode 100644 index 0000000..7347a62 --- /dev/null +++ b/src/package_manager/resolver.ts @@ -0,0 +1,607 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Package dependency resolver + * @module + */ + +import { Project } from "../project"; +import fs from "graceful-fs"; +import path from "path"; +import semver from "semver"; +import * as _ from "lodash"; +import * as H from "../helper"; +import * as C from "../constants"; +import errorCode from "../error_code"; +import { getPackageFetcher, IPackageManifest } from "./fetcher"; +import { buildStatus } from "../status"; +import dotProp from "dot-prop"; + +const log = H.getLogger("package_resolver"); + +/** + * Define a package specifier. + */ +export interface IPackageSpec { + /** + * The package name. + */ + name: string; + /** + * The package version reference, this could be a version, a version range, a directory, a file path etc. + */ + reference: string; + /** + * The resolved fixed package version. + */ + version?: string; +} + +/** + * Define a raw package. + */ +export interface IRawPackage extends IPackageSpec { + /** + * The raw package dependencies. + */ + dependencies: IPackageSpec[]; + /** + * The packages that depend on this. + */ + requiredBy?: H.Dict; +} + +/** + * Define a resolved package. + */ +export interface IPackage extends Omit { + /** + * The package dependencies. + */ + dependencies: IPackage[]; + /** + * The destination of this package resolved on local disk. + */ + destination?: string; +} + +export class DependencyResolver { + root: string; + name: string; + version: string; + isRootProject: boolean; + rawDependencies: H.Dict; + resolutions: IPackage[]; + + constructor(proj: Project) { + this.root = proj.root; + this.name = proj.config.name?.toLocaleLowerCase() || ""; + this.version = proj.config.version || ""; + this.isRootProject = proj.isRootProject; + this.rawDependencies = _.cloneDeep(proj.config.rawDependencies) || {}; + this.resolutions = _.cloneDeep(proj.config.resolutions) || []; + } + + /** + * Get fixed version for a package + * @param package a raw package + * @param package.name package name + * @param package.reference package version reference + * @param resolutions the resolutions from last resolver, used for package version lock + */ + async getFixedVersion( + { name, reference }: IPackageSpec, + resolutions?: IPackage[] + ): Promise { + let version = ""; + // if `reference` is not a semver or semver range (i.e., a directory/file path), convert it to a + // version number at first + if (reference.startsWith("file:")) { + const packageManifest = await getPackageFetcher({ name, reference }).getManifest(); + version = packageManifest.version; + } + if (resolutions) { + // verify if the package is fixed in resolutions field + const filteredRes = resolutions.filter((res) => { + if (res.name === name) return true; + }); + if (filteredRes.length) { + // there should be only one version of package in the resolutions field in current implementation + const filteredResVer = filteredRes[0].version; + if ( + filteredResVer && + ((semver.valid(reference) && reference === filteredResVer) || + (semver.validRange(reference) && semver.satisfies(filteredResVer, reference)) || + (reference.startsWith("file:") && + version && + semver.valid(version) && + version === filteredResVer)) + ) { + log.info(`... get fixed version for package ${name}: ${filteredResVer}`); + return { name, reference, version: filteredResVer }; + } + // if the fixed version in resolutions field can't meet the requirement of the package reference version, raise error + throw new H.WError( + `Package ${name} version ${reference} is conflict with locked version ${filteredResVer} defind in resolutions field.`, + errorCode.WEBINIZER_PM_VER_CONFLICT + ); + } + } + + if (semver.validRange(reference)) { + if (semver.valid(reference)) { + // works for a fixed reference (1.0.0) + version = reference; + } else { + // works for a range (^1.0.0) + const packument = await getPackageFetcher({ name, reference }).getPackument(); + // currently, we always get the latest version of a package that fits the semver range + const maxSatisfied = semver.maxSatisfying(Object.keys(packument.versions), reference); + + if (maxSatisfied === null) + throw new H.WError( + `Couldn't find a version matching "${reference}" for package "${name}"`, + errorCode.WEBINIZER_PM_VER_INVALID + ); + + version = maxSatisfied; + } + log.info(`... get fixed version for package ${name}: ${version}`); + } + + return { name, reference, version }; + } + + /** + * Convert the raw dependencies of a package using PackageSpec interface + * @param package a raw package + * @param package.name package name + * @param package.reference package version reference + * @param package.version package fixed version + * @returns the package dependencies + * + */ + async getPackageDependencies({ + name, + reference, + version, + }: IPackageSpec): Promise { + const packageManifest = await getPackageFetcher({ name, reference, version }).getManifest(); + const dependencies = packageManifest.dependencies || {}; + return Object.keys(dependencies).map((name) => { + return { name, reference: dependencies[name] }; + }); + } + + /** + * Calculate the basic dependency tree and detect possible circular dependency + * @param package a raw package + * @param package.name package name + * @param package.reference package version reference + * @param package.version package fixed version + * @param package.dependencies raw dependencies from package.json, in the form of PackageSpec[] + * @param package.requiredBy the packages that depends on the current one + * @param ancenstors ancenstor packages map + * @returns the basic dependency tree + */ + async getPackageDependencyTree( + { name, reference, version, dependencies, requiredBy }: IRawPackage, + ancenstors = new Map(), + resolutions?: IPackage[] + ): Promise { + return { + name, + reference, + version, + dependencies: await Promise.all( + dependencies.map(async (dep) => { + // `ancenstors` is a Map of [name, reference] pair, used to record the ancenstors of a package to help get rid + // of possible circular dependency + if (ancenstors.get(dep.name)) { + // circular dependency pattern detected, throw exception + throw new H.WError( + `Circular dependency is detected for package ${dep.name}`, + errorCode.WEBINIZER_PM_CIRCULAR_DEP + ); + } + // the package is not found in ancenstors, add it to the dependency tree + const fixedDependency = await this.getFixedVersion(dep, resolutions); + const subDependencies = await this.getPackageDependencies(fixedDependency); + // create a new map subAncenstors from ancenstors, instead of overriding it + const subAncenstors = new Map(ancenstors); + if (fixedDependency.version) { + subAncenstors.set(fixedDependency.name, fixedDependency.version); + } + // get the dependency tree recursively + return this.getPackageDependencyTree( + Object.assign({}, fixedDependency, { + dependencies: subDependencies, + requiredBy: { [name]: reference }, + }), + subAncenstors, + resolutions + ); + }) + ), + requiredBy, + }; + } + + /** + * Convert the dependency tree from nested to flat, and eliminate any possible version conflicts + * across different sub-trees + * @param package a resolved package + * @param package.name package name + * @param package.reference package version reference + * @param package.version fixed package version + * @param package.dependencies the basic dependency tree from `getPackageDependencyTree` + * @param package.requiredBy the packages that depends on the current one + * @returns the optimized dependency tree + * */ + optimizeDependencyTree({ + name, + reference, + version, + dependencies, + requiredBy, + }: IPackage): IPackage { + // transverse the tree from bottom to top recursively, and merge the optimized results together + dependencies = dependencies.map((dep) => this.optimizeDependencyTree(dep)); + + for (const dep of dependencies.slice()) { + for (const subDep of dep.dependencies.slice()) { + /** + * A + * / \ + * B C <-- dependencies + * / \ / \ + * D E F G <-- dep.dependencies + */ + + // to find if `D` is in [B, C] + const availableDep = dependencies.find((dependency) => subDep.name === dependency.name); + + if (!availableDep) { + // if no availableDep found for subDep (means `D` is not in [B, C]), level it up and remove + // it from dep.dependencies + dependencies.push(subDep); + dep.dependencies.splice( + dep.dependencies.findIndex((dependency) => dependency.name === subDep.name), + 1 + ); + } else { + if (availableDep.version === subDep.version) { + // if availableDep found and it's the same reference version as subDep, merge requiredBy of both deps + availableDep.requiredBy = Object.assign({}, availableDep.requiredBy, subDep.requiredBy); + // remove the node from dep.dependencies and only keep the one in dependencies + dep.dependencies.splice( + dep.dependencies.findIndex((dependency) => dependency.name === availableDep.name), + 1 + ); + } else { + // version conflict, throw exception, this will catch version conflicts in different sub-trees + throw new H.WError( + `Version conflict! ${subDep.name}: ${subDep.version} vs. ${availableDep.version}`, + errorCode.WEBINIZER_PM_VER_CONFLICT + ); + } + } + } + } + + return { name, reference, version, dependencies, requiredBy }; + } + + /** + * Compare native libraries info of different dependencies to eliminate different ports for the same native library + * @param deps an optimized dependency tree + */ + async validateNativeLibraryInDependencyTree(deps: Readonly): Promise { + const nativeLibs = new Map(); + for (const dep of deps) { + const packageManifest = await getPackageFetcher( + { + name: dep.name, + reference: dep.reference, + version: dep.version, + }, + { fullMetadata: true } // fetch full metadata file + ).getManifest(); + if ( + dotProp.get(packageManifest, "webinizer.nativeLibrary.name") && + dotProp.get(packageManifest, "webinizer.nativeLibrary.version") + ) { + // get the native library name and ignore letter case + const nativeLibName = ( + dotProp.get(packageManifest, "webinizer.nativeLibrary.name") as string + ).toLocaleLowerCase(); + if (nativeLibs.get(nativeLibName)) { + throw new H.WError( + `Different ports (${dep.name} vs. ${dotProp.get( + nativeLibs.get(nativeLibName), + "name" + )}) of the same native library ${nativeLibName} is detected in the dependency graph and is NOT allowed.`, + errorCode.WEBINIZER_PM_PORT_CONFLICT + ); + } else { + nativeLibs.set(nativeLibName, packageManifest); + } + } else { + throw new H.WError( + `No valid field nativeLibrary is defined in the package manifest of ${dep.name}`, + errorCode.WEBINIZER_META_FIELD_UNDEFINED + ); + } + } + } + + /** + * Save the dependency packages on local disk according to the optimized tree + * @param package a resolved and optimized package + * @param package.name package name + * @param package.reference package version reference + * @param package.version fixed package version + * @param package.dependencies the optimized dependency tree from `optimizedDependencyTree` + * @param package.destination the destination to store the dependencies, default is ${projectRoot}/webinizer_deps + * @param package.requiredBy the packages that depend on the current one + * @param rootPath the root path of main project + * @param isRoot is the project a main/root project or not + * @returns updated dependencies with destination info + * */ + private async _localizeDependencies( + { name, reference, version, dependencies, destination, requiredBy }: IPackage, + rootPath: string, + isRoot: boolean + ): Promise { + if (destination) { + if (!isRoot) { + if (!fs.existsSync(destination)) { + log.info(`... fetching package ${name}@${reference}@${version} to local disk.`); + // we don't need to fetch the root project, but all the other dependencies. + try { + await getPackageFetcher({ name, reference, version }).fetchPackage(destination); + // git init for each dependency + // FIXME. should we include config.json into git tree or not? + const gitInitResults = await H.runCommand( + "git init && git add . && git commit -m 'first commit'", + { cwd: destination, silent: true } + ); + if (gitInitResults.code !== 0) { + throw new H.WError( + `Initialize the project with git failed.`, + errorCode.WEBINIZER_PROJ_INIT_FAIL + ); + } + } catch (err) { + // if errors happend in fetching the package to local disk, remove the package repo before throw the error. + fs.rmSync(destination, { recursive: true, force: true }); + throw err as Error; + } + // convert package.json to config.json if config.json doesn't exist after all + // dependencies are localized successfully + } + + return { + name, + reference, + version, + dependencies, + destination: path.relative(rootPath, destination), + requiredBy, + }; + } + + return { + name, + reference, + version, + dependencies: await Promise.all( + dependencies + .slice() + .map(async ({ name, reference, version, dependencies, requiredBy }) => { + const destTarget = path.join( + destination, + C.dependencyDir, + `${name.toLocaleLowerCase()}` + ); + return this._localizeDependencies( + { name, reference, version, dependencies, destination: destTarget, requiredBy }, + rootPath, + false + ); + }) + ), + }; + } + return { name, reference, version, dependencies, requiredBy }; + } + + /** + * Remove packages from local disk + * @param deleted deleted package list + * @param root project root + */ + private _cleanupDependencies(deleted: IPackage[], root: string) { + deleted.forEach((pkg) => { + log.info(`... removing package ${pkg.name} from local disk.`); + const pkgRoot = pkg.destination + ? path.join(root, pkg.destination) + : path.join(root, C.dependencyDir, pkg.name); + fs.rmSync(pkgRoot, { + recursive: true, + force: true, + }); + // reset the build status of the dependency to `idle_default` + buildStatus.setBuildStatus(pkgRoot, "idle_default"); + }); + } + + /** + * Compare resolutions and get outdated packages + * @param oldResolutions old resolutions + * @param newResolutions new resolutions + * @returns resolutions of outdated packages + */ + private _generateOutdatedResolutions( + oldResolutions: IPackage[] | undefined, + newResolutions: IPackage[] | undefined + ): IPackage[] { + const outdated: IPackage[] = []; + if (!oldResolutions || !oldResolutions.length) { + return []; + } else if (!newResolutions || !newResolutions.length) { + outdated.push(...(oldResolutions || [])); + } else { + const isSameResolution = (a: IPackage, b: IPackage) => + a.name === b.name && a.version === b.version && a.reference === b.reference; + const compareRes = ( + oldRes: IPackage[], + newRes: IPackage[], + compareFn: (a: IPackage, b: IPackage) => boolean + ) => { + return oldRes.filter( + (oldResVal) => !newRes.some((newResVal) => compareFn(oldResVal, newResVal)) + ); + }; + outdated.push(...compareRes(oldResolutions, newResolutions, isSameResolution)); + } + return outdated; + } + + /** + * Update (delete and add) dependency packages + * @param newResolutions new resolutions + * @param proj the root project + * @returns new resolutions field with dependencies' dest info + */ + async finalizeDependencies( + newResolutions: IPackage[] | undefined + ): Promise { + if (this.isRootProject) { + const outdated = this._generateOutdatedResolutions(this.resolutions, newResolutions); + // delete outdated packages + this._cleanupDependencies(outdated, this.root); + // add newly added packages + const updatedNewResolutions = ( + await this._localizeDependencies( + { + name: this.name, + reference: this.version, + dependencies: newResolutions || [], + destination: this.root, + }, + this.root, + this.isRootProject + ) + ).dependencies; + return updatedNewResolutions; + } + // resolutions are generated for main project only + return undefined; + } + + /** + * Update the resolutions based on the top-level dependencies at first to ensure + * the direct installed dependencies meet user's requirement + * @returns the package resolutions adjusted based on top-level dependencies + */ + async adjustToplevelDepResolutions(): Promise { + const oldResolutions = _.cloneDeep(this.resolutions); + if (this.rawDependencies && !H.isObjectEmpty(this.rawDependencies)) { + for (const dep in this.rawDependencies) { + for (const idx in oldResolutions) { + if (oldResolutions[idx].name === dep) { + // package `dep` has locked version + if (this.rawDependencies[dep].startsWith("file:")) { + const packageManifest = await getPackageFetcher({ + name: dep, + reference: this.rawDependencies[dep], + }).getManifest(); + const depVer = packageManifest.version; + if (depVer && semver.valid(depVer) && oldResolutions[idx].version !== depVer) { + oldResolutions[idx].reference = this.rawDependencies[dep]; + oldResolutions[idx].version = depVer; + } + } else if ( + (semver.valid(this.rawDependencies[dep]) && + oldResolutions[idx].version !== this.rawDependencies[dep]) || + (semver.validRange(this.rawDependencies[dep]) && + oldResolutions[idx].version && + !semver.satisfies(oldResolutions[idx].version || "", this.rawDependencies[dep])) + ) { + const newRes = await this.getFixedVersion({ + name: dep, + reference: this.rawDependencies[dep], + }); + oldResolutions[idx].name = newRes.name; + oldResolutions[idx].reference = newRes.reference; + oldResolutions[idx].version = newRes.version; + } + } + } + } + } + return oldResolutions; + } + + /** + * Generate the final optimized dependency tree + * @returns An optimized (flatten) dependency tree. + */ + async getDependencyResolutions(): Promise { + if (this.rawDependencies && !H.isObjectEmpty(this.rawDependencies)) { + // adjust resolutions for first-level dependencies + let adjustedResolutions: IPackage[] = []; + if (this.resolutions && this.resolutions.length) { + adjustedResolutions = await this.adjustToplevelDepResolutions(); + } + log.info( + `... original resolutions is:\n${this.resolutions?.map((n) => JSON.stringify(n, null, 2))}` + ); + log.info( + `... resolutions adjusted for top-level dependencies is:\n${adjustedResolutions.map((n) => + JSON.stringify(n, null, 2) + )}` + ); + // construct the base tree + const baseTree = await this.getPackageDependencyTree( + { + name: this.name, + reference: this.version, + dependencies: Object.keys(this.rawDependencies).map((name) => { + return { name, reference: this.rawDependencies?.[name] || "" }; + }), + requiredBy: {}, // root project has empty requiredBy property + }, + new Map([[this.name, this.version]]), + adjustedResolutions + ); + // generate the optimized/flatten tree + if (baseTree.dependencies && baseTree.dependencies.length) { + const optTree = this.optimizeDependencyTree({ + name: this.name, + reference: this.version, + dependencies: _.cloneDeep(baseTree.dependencies), + }); + await this.validateNativeLibraryInDependencyTree(optTree.dependencies); + return optTree.dependencies; + } + } + return []; + } + + /** + * Resolve project dependencies and finalize the project on local disk + * @returns the resolved project dependency tree + */ + async resolveDependencies(): Promise { + const newResolutions = await this.getDependencyResolutions(); + log.info(`... new resolutions is:\n${newResolutions?.map((n) => JSON.stringify(n, null, 2))}`); + // delete and add dependency packages + return this.finalizeDependencies(newResolutions); + } +} diff --git a/src/package_manager/search.ts b/src/package_manager/search.ts new file mode 100644 index 0000000..d1df480 --- /dev/null +++ b/src/package_manager/search.ts @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "../helper"; +import * as npmSearch from "libnpmsearch"; +import * as _ from "lodash"; +import { Settings } from "../settings"; +import errorCode from "../error_code"; + +const log = H.getLogger("package_search"); + +/** + * The direct search result from the registry, for compatible with + * Verdaccio search. + */ +interface IRegistrySearchResult extends npmSearch.Result { + "dist-tags"?: { latest: string }; +} + +/** + * The simplified search result passed to UI. + */ +export interface IPackageSearchResult { + name: string; + version?: string; + description?: string; +} + +/** + * Search with keywords in registry + * @param text keywords to search + * @param options search options + * @returns search result array + */ +export async function search( + text: string, + options?: npmSearch.Options +): Promise { + if (!Settings.registry) { + log.warn(`No registry is set in webinizer settings!`); + throw new H.WError( + "No registry is set in webinizer settings.", + errorCode.WEBINIZER_REG_UNDEFINED + ); + } + const searchOpts = getRegistryBaseOptions(); + if (options) { + _.extend(searchOpts, options); + } + const searchResults = (await npmSearch.default(text, searchOpts)) as IRegistrySearchResult[]; + return searchResults.map((item) => { + return { + name: item.name, + version: item.version + ? item.version + : item["dist-tags"]?.latest /* a workaround for Verdaccio */, + description: item.description, + }; + }); +} + +function getRegistryBaseOptions(): npmSearch.Options { + return { + registry: Settings.registry, + }; +} diff --git a/src/package_metadata.ts b/src/package_metadata.ts new file mode 100644 index 0000000..82d4684 --- /dev/null +++ b/src/package_metadata.ts @@ -0,0 +1,100 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Package Metadata - represent package.json + * @module + */ + +import Ajv, { ValidateFunction } from "ajv"; +import fs from "graceful-fs"; +import DiskCache from "./disk_cache"; +import * as H from "./helper"; +import { Project } from "./project"; +import { + buildTargetMetaSchema, + webinizerFieldMetaSchema, + metaSchema, +} from "./schemas/metadata_schema"; +import errorCode from "./error_code"; + +const log = H.getLogger("package_metadata"); + +// major difference with class ProjectCacheFile is that it doesn't have __type__ +export default class PackageMeta extends DiskCache { + private _proj: Project; + constructor(proj: Project, filePath: string) { + super(filePath); + this._proj = proj; + } + + get proj(): Project { + return this._proj; + } + + validateMetaSchema(metaData: H.Dict) { + const ajv = new Ajv(); + + let validate: ValidateFunction<{ [x: string]: unknown }> | undefined = undefined; + + if (this.proj.config && fs.existsSync(this.proj.config.path) && this.proj.config.isLibrary) { + // use schema defined for library + validate = ajv + .addSchema(Object.assign({}, buildTargetMetaSchema, { $ref: "#/definitions/library" })) + .addSchema(Object.assign({}, webinizerFieldMetaSchema, { $ref: "#/definitions/library" })) + .compile(metaSchema); + } else { + // use standard schema + validate = ajv + .addSchema(buildTargetMetaSchema) + .addSchema(webinizerFieldMetaSchema) + .compile(metaSchema); + } + + const valid = validate(metaData); + if (!valid) { + log.info( + `Errors happened in metadata validation for project ${this.proj.config.name}@${this.proj.config.version}:\n`, + validate.errors + ); + throw new H.WError( + `Errors happened in metadata validation for project ${this.proj.config.name}@${ + this.proj.config.version + }:\n${ajv.errorsText(validate.errors)}`, + errorCode.WEBINIZER_META_SCHEMA_VALIDATION_FAILED + ); + } else log.info("Metadata validation passed!"); + } + + async updateMetaAndConfig(metaData: H.Dict) { + const diffContent = H.getObjDifference(this.data, metaData); + // update metadata + this.clear(); + this.data = metaData; + // update config based on metadata update + await this.proj.config.convertFromRegMeta(diffContent); + } + + backup() { + if (fs.existsSync(this.path) && !fs.existsSync(`${this.path}.bak`)) { + fs.copyFileSync(this.path, `${this.path}.bak`); + // chmod for the temp file to be read-only + fs.chmodSync(`${this.path}.bak`, 0o0400); + } + } + + restoreFromBackupFile() { + if (fs.existsSync(`${this.path}.bak`)) { + this.clear(); + this.data = JSON.parse(fs.readFileSync(`${this.path}.bak`, "utf8")); + this.cleanBackupFile(); + } + } + + cleanBackupFile() { + fs.rmSync(`${this.path}.bak`, { force: true }); + } +} diff --git a/src/project.ts b/src/project.ts new file mode 100644 index 0000000..ccc076e --- /dev/null +++ b/src/project.ts @@ -0,0 +1,380 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Project Details - hold the entire session + * + * @module + */ +import path from "path"; +import fs from "graceful-fs"; +import { AdviseManager } from "./advisor"; +import { ALL_BUILDER_FACTORIES } from "./builder"; +import * as H from "./helper"; +import * as C from "./constants"; +import { Recipe } from "./recipe"; +import { FileChangeManager } from "./actions/file_change"; +import { PlainAdviseRequest } from "./advise_requests/common_requests"; +import { BuildStepChangeManager } from "./actions/build_step_change"; +import { buildStatus } from "./status"; +import errorCode from "./error_code"; +import PackageMeta from "./package_metadata"; +import { ProjectConfig } from "./project_caches/project_config"; +import ProjectResult from "./project_caches/project_result"; +import ProjectLog from "./project_caches/project_log"; +import ProjectRecipe from "./project_caches/project_recipe"; +import publish from "./package_manager/publish"; +import { Project as IProject, ProjectConstType, IBuilder } from "webinizer"; + +const log = H.getLogger("project"); +export class Project implements IProject { + root = ""; // root of project + config: ProjectConfig; + log: ProjectLog; + result: ProjectResult; + recipe: ProjectRecipe; + meta: PackageMeta; + fileChangeManager = new FileChangeManager(); + buildStepChangeManager = new BuildStepChangeManager(); + isRootProject: boolean; + constant: Record; + + constructor(root: string, isRoot?: boolean) { + this.root = root; + this.config = new ProjectConfig(this, path.join(this.root, ".webinizer", "config.json")); + this.log = new ProjectLog(this, path.join(this.root, ".webinizer", "log.json")); + this.result = new ProjectResult(this, path.join(this.root, ".webinizer", "result.json")); + this.recipe = new ProjectRecipe(this, path.join(this.root, ".webinizer", "recipe.json")); + this.meta = new PackageMeta(this, path.join(this.root, "package.json")); + /** + * This is to determine if the project is a dependency or root based on path + * If the project is nested inside a `webinizer_deps` folder -> a dependency + * If the project is nested inside projectPool -> root project + */ + this.isRootProject = + isRoot !== undefined ? isRoot : path.dirname(this.root) === C.projectPool ? true : false; + this.constant = { + projectDist: path.join(this.root, C.buildDir), //default build path + projectRoot: this.root, // project root path + projectPool: C.projectPool, // project pool directory for all native projects + }; + if (H.isObjectEmpty(this.meta.data) && Object.keys(this.config.data).length > 1) { + this.config.convertToRegMetaFromConfig(); + } + } + + // Detect all possible builders and provide to user for their reference + // And return a possible build steps to use + recommendBuildersToUse(): IBuilder[] { + const builders: IBuilder[] = []; + log.info("... trying to detect the Builder to use"); + for (const f of ALL_BUILDER_FACTORIES.factoriesMap().values()) { + const builder = f.detect(this); + if (builder) { + builders.push(builder); + if (builder.type === "CMakeBuilder" || builder.type === "ConfigureBuilder") { + // add MakeBuilder with a clean step ahead + const m = ALL_BUILDER_FACTORIES.factoriesMap().get("MakeBuilder"); + if (m) builders.push(...[m.createDefault(this, "clean"), m.createDefault(this)]); + } + if (builder.type === "MakeBuilder") { + // add MakeBuilder with a clean step ahead at the same build path + const m = builder.toJson(); + m.args = "clean"; + const mBuilder = ALL_BUILDER_FACTORIES.fromJsonArray(this, [m]); + builders.splice(0, 0, ...mBuilder); + } + break; + } + } + // if no builders detected, recommend to use emcc directly + if (!builders.length) { + const b = ALL_BUILDER_FACTORIES.factoriesMap().get("EmccBuilder"); + if (b) builders.push(b.createDefault(this)); + } + return builders; + } + + getTemplateLiterals(withMarkdown = false): string[] { + const templates: string[] = []; + for (const c in this.constant) { + if (withMarkdown) templates.push(`\`$\{${c}}\` = ${this.constant[c as ProjectConstType]}`); + else templates.push(`$\{${c}} = ${this.constant[c as ProjectConstType]}`); + } + return templates; + } + + evalTemplateLiterals(s: string): string { + let val = s; + if (s) { + for (const c in this.constant) { + val = val.replaceAll("${" + c + "}", this.constant[c as ProjectConstType]); + } + } + return val; + } + + validateTemplateLiterals(s: string): string[] { + // TODO. validate if the string is defined with proper template literal format? + // i.e., ${xyz} - correct, {xyz} - wrong + const invalidTemplates: string[] = []; + const templateReg = /\$\{(?[^${]*)\}/g; + const matches = s.matchAll(templateReg); + for (const m of matches) { + if (m && m.groups && !Object.keys(this.constant).includes(m.groups.dir)) { + invalidTemplates.push(m[0]); + } + } + return invalidTemplates; + } + + backupConfigFiles() { + log.info("... backup meta and config files before updating configs"); + this.config.backup(); + this.meta.backup(); + } + + restoreConfigsFromBackupFiles() { + log.info("... errors happened, restore config and meta files"); + this.config.restoreFromBackupFile(); + this.meta.restoreFromBackupFile(); + } + + cleanBackupFiles() { + log.info("... cleanup backup files"); + this.config.cleanBackupFile(); + this.meta.cleanBackupFile(); + } + + // dependency folder backup and restore for root project only + backupDependencyDir() { + if (this.isRootProject) { + const depsDir = path.join(this.root, C.dependencyDir); + const depsBackupDir = path.join(this.root, `.${C.dependencyDir}`); + if (fs.existsSync(depsDir) && !fs.existsSync(depsBackupDir)) { + H.backupFolderSync(depsDir, depsBackupDir); + } + } + } + + restoreDependencyDir() { + if (this.isRootProject) { + const depsDir = path.join(this.root, C.dependencyDir); + const depsBackupDir = path.join(this.root, `.${C.dependencyDir}`); + if (fs.existsSync(depsDir)) { + H.deleteFolder(depsDir); + } + if (fs.existsSync(depsBackupDir)) { + H.renameFolder(depsBackupDir, depsDir); + } + } + } + + cleanDependencyDirBackup() { + if (this.isRootProject) { + const depsBackupDir = path.join(this.root, `.${C.dependencyDir}`); + if (fs.existsSync(depsBackupDir)) { + H.deleteFolder(depsBackupDir); + } + } + } + + /** + * Reset build status of project to `idle_default` if it requires hard reset or there is any API requests fired + * from UI to change project configs / source codes. This will be propagated to all requiredBy parent projects. + * @param hardReset reset the status to `idle_default` regardless of the current build status + */ + async resetBuildStatus(hardReset = false) { + if (hardReset) buildStatus.setBuildStatus(this.root, "idle_default"); + else { + const currentStatus = await buildStatus.getBuildStatus(this.root); + if (currentStatus !== "building" && currentStatus !== "building_with_recipes") { + buildStatus.setBuildStatus(this.root, "idle_default"); + } else { + // if the project is under building, any actions to update configs are not allowed + throw new H.WError( + "The project is under building and update the configs and files is not allowed.", + errorCode.WEBINIZER_PROCESS_UPDATE_UNDER_BUILD + ); + } + } + // propagate the status reset to all parent projects + if (this.config.requiredBy && !H.isObjectEmpty(this.config.requiredBy)) { + await Promise.all( + Object.keys(this.config.requiredBy).map(async (name) => { + const requiredProjRoot = await this.config.detectProjectRoot( + name, + this.config.requiredBy?.[name] || "", + false /* detect for parent project */ + ); + if (requiredProjRoot) { + const requiredProj = new Project(requiredProjRoot); + await requiredProj.resetBuildStatus(hardReset); + } else { + throw new H.WError( + `Can't find required project ${name} on local disk`, + errorCode.WEBINIZER_ROOT_NOEXT + ); + } + }) + ); + } + return; + } + + async build(res: Recipe[] | null): Promise { + const currentStatus = await buildStatus.getBuildStatus(this.root); + if (currentStatus === "building" || currentStatus === "building_with_recipes") { + throw new H.WError( + `Project ${this.root} is under building now, multiple builds for the same project is not allowed.`, + errorCode.WEBINIZER_PROCESS_MULTI_BUILD + ); + } + + if (res && res.length) { + buildStatus.setBuildStatus(this.root, "building_with_recipes"); + } else buildStatus.setBuildStatus(this.root, "building"); + + const projName = this.config.name ? this.config.name : path.basename(this.root); + const tStart = new Date(); + + // clear the log, result and recipe files when build + this.log.clear(); + this.result.clear(); + this.recipe.clear(); + const dumpLog = (data: string) => { + this.log.update(data); + }; + + // apply recipes before build if any + if (res && res.length) { + log.info(`... apply recipes for project ${projName}`, dumpLog); + for (const r of res) await r.apply(); + } + + const buildConfig = this.config.getBuildConfigForTarget(this.config.target); + + if (!buildConfig.builders) { + // one must have configured related builders in UI before trigger build + buildStatus.setBuildStatus(this.root, "idle_fail"); + buildStatus.setChangeHash(this.root); + throw new H.WError( + "No builders defined yet for building.", + errorCode.WEBINIZER_BUILDER_UNDEFINED + ); + } + + const recipes: Recipe[] = []; + const adviseManager = new AdviseManager(this); + + /** + * dependencies' build + */ + if (this.isRootProject) { + // if there is any shared build enabled in the dependency tree, append `-sRELOCATABLE` to all + // (main and dependent) projects' build. Otherwise, remove it. + const isSharedBuild = await this.config.isSharedBuild(); + if (isSharedBuild) await buildConfig.setRelocatable("replace"); + else await buildConfig.setRelocatable("deleteAll"); + } + + if (!this.config.dependencies) { + await this.config.getDependencies(); + } + if (this.config.dependencies && !H.isObjectEmpty(this.config.dependencies)) { + const depRecipes: string[] = []; + for (const k in this.config.dependencies) { + const depRoot = this.config.dependencies[k].root; + const depBuildStatus = await buildStatus.getBuildStatus(depRoot); + // don't rebuild dep project if it's a successful build previously + if ( + depBuildStatus !== "idle_success" && + depBuildStatus !== "building" && + depBuildStatus !== "building_with_recipes" + ) { + log.info(`... build dependency: ${k}@${depRoot}`, dumpLog); + const r = await this.config.dependencies[k].build(null); + if (r.length) { + this.config.dependencies[k].recipe.saveRecipes(r); + // depRecipes.push(k.replace(C.projectPool, "${projectPool}")); + depRecipes.push(depRoot); + } + } + } + + if (depRecipes.length) { + // recipes in dep projects generated + adviseManager.queueRequest(new PlainAdviseRequest("dep-build", depRecipes)); + recipes.push(...(await adviseManager.advise())); + } + + if (recipes.length > 0) { + this.recipe.saveRecipes(recipes); + buildStatus.setBuildStatus(this.root, "idle_fail"); + buildStatus.setChangeHash(this.root); + return recipes; + } + } + + /** + * pre-build checks + */ + log.info(`... running pre-build checks for project ${projName}`, dumpLog); + adviseManager.queueRequest(new PlainAdviseRequest("pre-build", {})); + recipes.push(...(await adviseManager.advise())); + + // recipes generated during pre-build, stop building the project + if (recipes.length > 0) { + this.recipe.saveRecipes(recipes); + buildStatus.setBuildStatus(this.root, "idle_fail"); + buildStatus.setChangeHash(this.root); + return recipes; + } + + // force to update overallEnvs from dependencies before build to ensure latest configs are used + await this.config.updateOverallEnvsFromDeps(); + + /** + * root project build + */ + log.info(`... building project ${projName}`, dumpLog); + // run build steps + for (const builder of buildConfig.builders) { + log.info(`... will use Builder ${builder.type}`); + if (!(await builder.build(adviseManager))) { + recipes.push(...(await adviseManager.advise())); + break; + } + } + + if (recipes.length > 0) { + this.recipe.saveRecipes(recipes); + buildStatus.setBuildStatus(this.root, "idle_fail"); + buildStatus.setChangeHash(this.root); + return recipes; + } else { + // no recipe means successful build - generate build summary + log.info(`... project ${projName} build successfully!`, dumpLog); + const tEnd = new Date(); + this.result.timestamps = { + tStart: tStart, + tEnd: tEnd, + tDur: tEnd.getTime() - tStart.getTime(), + }; + await this.result.genBuildResults(); + buildStatus.setBuildStatus(this.root, "idle_success"); + buildStatus.setChangeHash(this.root); + return []; + } + } + + async publishToRegistry() { + await publish(this); + } +} + +// re-export related project cache files classes here +export { ProjectConfig, ProjectLog, ProjectRecipe, ProjectResult }; diff --git a/src/project_caches/project_cache_file.ts b/src/project_caches/project_cache_file.ts new file mode 100644 index 0000000..8cdd66e --- /dev/null +++ b/src/project_caches/project_cache_file.ts @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import fs from "graceful-fs"; +import writeFileAtomic from "write-file-atomic"; +import * as H from "../helper"; +import { Project } from "../project"; +import { IJsonObject, IToJson } from "webinizer"; + +const log = H.getLogger("project_cache_file"); + +export default abstract class ProjectCacheFile implements IToJson { + private _proj: Project; + private _path: string; + private _data: IJsonObject; + private _type: string; + + constructor(proj: Project, filePath: string, type: string) { + this._proj = proj; + this._path = filePath; + this._type = type; + this._data = { __type__: type }; + if (fs.existsSync(this._path)) { + this.load(); + } + } + + get proj(): Project { + return this._proj; + } + + get path(): string { + return this._path; + } + + get data(): IJsonObject { + return this._data; + } + + set data(v: H.Dict) { + Object.assign(this._data, v); + this.save(); + } + + reset() { + this._data = { __type__: this._type }; + this.save(); + } + + toJson(): IJsonObject { + return this._data; + } + + load() { + try { + const data = JSON.parse(fs.readFileSync(this._path, "utf8")) as IJsonObject; + H.assert(data.__type__ === this.data.__type__); + this._data = data; + //eslint-disable-next-line + } catch (err: any) { + if (err.code === "ENOENT") { + log.error(`Tried to load ${this.data.__type__} from an nonexist file:`, this._path); + return; + } + log.error( + `Failed to load ${this.data.__type__} from file`, + this._path, + "due to error:\n", + H.normalizeErrorOutput(err as Error) + ); + throw err; + } + } + + save() { + try { + // this doesn't report error if already exists because recursive is set to true + fs.mkdirSync(path.dirname(this._path), { mode: 0o0700, recursive: true }); + writeFileAtomic.sync(this._path, JSON.stringify(this._data, undefined, 2) + "\n", { + mode: 0o0600, + }); + //eslint-disable-next-line + } catch (err: any) { + log.error( + `Failed to save ${this.data.__type__} to file`, + this._path, + "due to error:\n", + H.normalizeErrorOutput(err as Error) + ); + throw err; + } + } +} diff --git a/src/project_caches/project_config.ts b/src/project_caches/project_config.ts new file mode 100644 index 0000000..04ae601 --- /dev/null +++ b/src/project_caches/project_config.ts @@ -0,0 +1,1618 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import shlex from "shlex"; +import * as _ from "lodash"; +import path from "path"; +import fs from "graceful-fs"; +import semver from "semver"; +import dotProp from "dot-prop"; +import Ajv from "ajv"; +import * as H from "../helper"; +import * as C from "../constants"; +import { ALL_BUILDER_FACTORIES } from "../builder"; +import { updateArgs } from "../actions/args_change"; +import errorCode from "../error_code"; +import { IPackage, DependencyResolver } from "../package_manager/resolver"; +import { getPackageFetcher } from "../package_manager/fetcher"; +import ProjectCacheFile from "./project_cache_file"; +import { Project } from "../project"; +import { IProjectProfile } from "../project_profiles"; +import { + EnvType, + ProjectEnv, + PkgConfigType, + ProjectPkgConfig, + BuildOptionType, + IProjectBuildOptions, + IBuildConfigUpdateOptions, + IArg, + ActionType, + IProjectConfig, + IProjectBuildConfig, + IJsonObject, + IBuilder, +} from "webinizer"; +import { configSchema, buildTargetConfigSchema } from "../schemas/config_schema"; + +const log = H.getLogger("project_config"); + +// introduce ProjectBuildConfig class to handle build configs per target +class ProjectBuildConfig implements IProjectBuildConfig { + private _proj: Project; + private _data: H.Dict; + private _target: string; + private _builders: IBuilder[] | null = null; // lazy created builders + constructor(proj: Project, config: H.Dict, target: string) { + this._proj = proj; + this._data = config; + this._target = target; + if (this._proj.config.useDefaultConfig !== false) { + // initialize BuildConfig with default settings for webinizer + if (!this.options || H.isObjectEmpty(this.options)) { + this.resetOptions(); + if (!this.envs || H.isObjectEmpty(this.envs)) { + this.resetEnvs(); + } else { + this.updateEnvsFromOptions(); + } + } + } + } + + // read-only, target of this ProjectBuildConfig + get target(): string { + return this._target; + } + + get rawBuilders(): IJsonObject[] | undefined { + return this._data.builders as IJsonObject[]; + } + + set rawBuilders(v: IJsonObject[] | undefined) { + // using setter will reset this._builders + this._builders = null; + Object.assign(this._data, { builders: v }); + this.save(); + this.convertBuildersToMeta(); + } + + get builders(): IBuilder[] | null { + if (!this._builders) { + if (this.rawBuilders) { + this._builders = ALL_BUILDER_FACTORIES.fromJsonArray(this._proj, this.rawBuilders); + // save the builders with index info as builderID added from backend + this.builders = this._builders; + } + } + return this._builders; + } + + set builders(newBuilders: IBuilder[] | null) { + this._builders = newBuilders; + const newBuildersJson = newBuilders?.map((b) => b.toJson()); + if (JSON.stringify(this.rawBuilders) !== JSON.stringify(newBuildersJson)) { + this.updateBuildConfig({ builders: newBuildersJson }, { refresh: false }); + } + } + + get preloadFiles(): string[] | undefined { + return this._data.preloadFiles as string[]; + } + + set preloadFiles(v: string[] | undefined) { + Object.assign(this._data, { preloadFiles: v }); + this.save(); + } + + get exportedFuncs(): string | undefined { + return this._data.exportedFuncs as string; + } + + set exportedFuncs(v: string | undefined) { + Object.assign(this._data, { exportedFuncs: v }); + this.save(); + } + + get exportedRuntimeMethods(): string | undefined { + return this._data.exportedRuntimeMethods as string; + } + + set exportedRuntimeMethods(v: string | undefined) { + Object.assign(this._data, { exportedRuntimeMethods: v }); + this.save(); + } + + getEnv(key: EnvType): string { + const envs = (this.envs || {}) as ProjectEnv; + return envs[key] as string; + } + + setEnv(key: EnvType, value: string) { + if (!this.envs) { + this.envs = {} as ProjectEnv; + } + Object.assign(this.envs as ProjectEnv, { [key]: value }); + this._proj.config.updateOverallEnvsFromSelf(this.envs); + this.save(); + this.convertEnvsToMeta(); + } + + get envs(): ProjectEnv | undefined { + return this._data.envs as ProjectEnv; + } + + set envs(v: ProjectEnv | undefined) { + Object.assign(this._data, { envs: v }); + this._proj.config.updateOverallEnvsFromSelf(this.envs); + this.save(); + this.convertEnvsToMeta(); + } + + resetEnvs() { + this.envs = { + cflags: "-msimd128", + ldflags: "-msimd128 -sMODULARIZE=1", + } as ProjectEnv; + } + + getOption(key: BuildOptionType): T | undefined { + const options = (this.options || {}) as IProjectBuildOptions; + return options[key] as T; + } + + setOption(key: BuildOptionType, value: T) { + if (!this.options) { + this.options = {} as IProjectBuildOptions; + } + Object.assign(this.options, { [key]: value }); + this.save(); + } + + get options(): IProjectBuildOptions | null { + return this._data.options as IProjectBuildOptions; + } + set options(v: IProjectBuildOptions | null) { + Object.assign(this._data, { options: v }); + this.save(); + } + + resetOptions() { + this.options = { + needMainLoop: true, + needPthread: false, + needCppException: false, + needSimd: true, + needModularize: true, + }; + } + + getDisabledAdvisorFlag(key: string): T | undefined { + const flags = (this.disabledAdvisors || {}) as H.Dict; + return flags[key] as T; + } + + setDisabledAdvisorFlag(key: string, value: T) { + if (!this.disabledAdvisors) { + this.disabledAdvisors = {}; + } + Object.assign(this.disabledAdvisors as H.Dict, { [key]: value }); + this.save(); + } + + get disabledAdvisors(): H.Dict | null { + return this._data.disabledAdvisors as H.Dict; + } + + set disabledAdvisors(v: H.Dict | null) { + Object.assign(this._data, { disabledAdvisors: v }); + this.save(); + } + + resetAdvisors() { + this.disabledAdvisors = {}; + } + + // pkgConfig: exported package configs to be used by other libraries + get pkgConfig(): ProjectPkgConfig | undefined { + return this._data.pkgConfig as ProjectPkgConfig; + } + + set pkgConfig(v: ProjectPkgConfig | undefined) { + Object.assign(this._data, { pkgConfig: v }); + this.save(); + this.convertPkgConfigToMeta(); + } + + getPkgConfigEnv(key: PkgConfigType): string { + const pkgConfig = (this.pkgConfig || {}) as H.Dict; + return pkgConfig[key] as string; + } + + setPkgConfigEnv(key: PkgConfigType, value: string) { + if (!this.pkgConfig) { + this.pkgConfig = {} as ProjectPkgConfig; + } + Object.assign(this.pkgConfig, { [key]: value }); + this.save(); + this.convertPkgConfigToMeta(); + } + + updateEnvsFromPreloadFiles() { + if (this.preloadFiles && this.preloadFiles.length) { + // remove all previous preload files ("deleteAll") and then add the new ones + this.updateEnv("ldflags", [ + { option: "--preload-file", value: null, type: "deleteAll" }, + ...this.preloadFiles.map((f) => { + // preload file is mapped to root of virtual FS (@/) if mapping directory is not defined + const opt = f.includes("@/") ? `--preload-file ${f}` : `--preload-file ${f}@/`; + return { option: opt, value: null, type: "replace" }; + }), + ] as IArg[]); + } else { + // if preloadFiles is [], remove all --preload-file args + this.updateEnv("ldflags", { + option: "--preload-file", + value: null, + type: "deleteAll", + } as IArg); + } + } + + updateEnvsFromExportedFuncs() { + if (this.exportedFuncs && this.exportedFuncs.trim()) { + const uniqFns = [ + ...new Set( + this.exportedFuncs + .split(",") + .map((f) => f.trim()) + .filter((f) => f) + ), + ]; + const fns = uniqFns.map((f) => "_" + f); + this.exportedFuncs = uniqFns.join(","); + + this.updateEnv("ldflags", [ + { + option: "-sEXPORTED_FUNCTIONS", + value: `${fns.join(",")}`, + type: "replace", + } as IArg, + ]); + } else { + // if exportedFuncs is "", remove -sEXPORTED_FUNCTIONS arg + this.updateEnv("ldflags", [ + { option: "-sEXPORTED_FUNCTIONS", value: null, type: "deleteAll" } as IArg, + ]); + } + } + + updateEnvsFromExportedRuntimeMethods() { + if (this.exportedRuntimeMethods && this.exportedRuntimeMethods.trim()) { + const uniqFns = [ + ...new Set( + this.exportedRuntimeMethods + .split(",") + .map((f) => f.trim()) + .filter((f) => f) + ), + ]; + this.exportedRuntimeMethods = uniqFns.join(","); + + this.updateEnv("ldflags", [ + { + option: "-sEXPORTED_RUNTIME_METHODS", + value: `${this.exportedRuntimeMethods}`, + type: "replace", + } as IArg, + ]); + } else { + // if exportedRuntimeMethods is "", remove -sEXPORTED_RUNTIME_METHODS arg + this.updateEnv("ldflags", [ + { option: "-sEXPORTED_RUNTIME_METHODS", value: null, type: "deleteAll" } as IArg, + ]); + } + } + + updateEnvsFromOptions(updateParts?: BuildOptionType | BuildOptionType[]) { + let toUpdate: BuildOptionType[] = []; + if (updateParts) { + // update envs from specified options + toUpdate = Array.isArray(updateParts) ? updateParts : [updateParts]; + } else { + // update envs from all options + if (this.options) toUpdate = Object.keys(this.options) as BuildOptionType[]; + } + if (toUpdate.length) { + if (toUpdate.includes("needPthread")) { + // pthread option update + if (this.getOption("needPthread")) { + this.updateEnvs({ option: "-sUSE_PTHREADS", value: "1", type: "replace" } as IArg); + this.updateEnv("ldflags", { + option: "-sPROXY_TO_PTHREAD", + value: "1", + type: "replace", + } as IArg); + } else { + this.updateEnvs({ + option: "-sUSE_PTHREADS", + value: null, + type: "deleteAll", + } as IArg); + this.updateEnv("ldflags", { + option: "-sPROXY_TO_PTHREAD", + value: null, + type: "deleteAll", + } as IArg); + } + } + if (toUpdate.includes("needCppException")) { + // C++ exception update + if (this.getOption("needCppException")) { + this.updateEnvs({ + option: "-fwasm-exceptions", + value: null, + type: "replace", + } as IArg); + } else { + this.updateEnvs({ + option: "-fwasm-exceptions", + value: null, + type: "delete", + } as IArg); + } + } + if (toUpdate.includes("needSimd")) { + // simd option update + if (this.getOption("needSimd")) { + this.updateEnvs({ option: "-msimd128", value: null, type: "replace" } as IArg); + } else { + this.updateEnvs({ option: "-msimd128", value: null, type: "delete" } as IArg); + } + } + if (toUpdate.includes("needModularize")) { + // modularize option update + if (this.getOption("needModularize")) { + this.updateEnv("ldflags", { + option: "-sMODULARIZE", + value: "1", + type: "replace", + } as IArg); + } else { + this.updateEnv("ldflags", { + option: "-sMODULARIZE", + value: null, + type: "deleteAll", + } as IArg); + } + } + } + } + + /** + * Update the value of a environment variable with argument(s). + * @param k The to be updated environment variable name. + * @param val The to be updated arguments. + */ + updateEnv(k: EnvType, args: IArg | IArg[]) { + log.info(`... update ${k} with args to change are \n`, args); + // update envs and save + if (this.envs) { + const updatedArgs = updateArgs(this.getEnv(k), args); + if (updatedArgs !== this.getEnv(k)) { + this.setEnv(k, updatedArgs); + } + } + } + + /** + * Update all the environment variables with argument(s). + * @param args The to be updated arguments. + */ + updateEnvs(args: IArg | IArg[]) { + for (const env in this.envs) { + this.updateEnv(env as EnvType, args); + } + } + + updateOptionsFromEnvs(currentEnv: EnvType) { + const otherEnv = currentEnv === "cflags" ? "ldflags" : "cflags"; + const envFlags = this.getEnv(currentEnv).trim(); + + if (currentEnv === "cflags") { + // pthread option related update + if (envFlags.includes("-sUSE_PTHREADS=1") && !this.getOption("needPthread")) { + this.setOption("needPthread", true); + this.updateEnv(otherEnv, [ + { + option: "-sUSE_PTHREADS", + value: "1", + type: "replace", + }, + { + option: "-sPROXY_TO_PTHREAD", + value: "1", + type: "replace", + }, + ]); + } else if ( + (!envFlags.includes("-sUSE_PTHREADS=1") || envFlags.includes("-sUSE_PTHREADS=0")) && + this.getOption("needPthread") + ) { + this.setOption("needPthread", false); + this.updateEnv(currentEnv, { + option: "-sUSE_PTHREADS", + value: null, + type: "deleteAll", + }); + this.updateEnv(otherEnv, [ + { + option: "-sUSE_PTHREADS", + value: null, + type: "deleteAll", + }, + { + option: "-sPROXY_TO_PTHREAD", + value: null, + type: "deleteAll", + }, + ]); + } + } else { + /* currentEnv === "ldflags" */ + // pthread option related update + if ( + (envFlags.includes("-sUSE_PTHREADS=1") || envFlags.includes("-sPROXY_TO_PTHREAD=1")) && + !this.getOption("needPthread") + ) { + this.setOption("needPthread", true); + this.updateEnv(currentEnv, [ + { + option: "-sUSE_PTHREADS", + value: "1", + type: "replace", + }, + { + option: "-sPROXY_TO_PTHREAD", + value: "1", + type: "replace", + }, + ]); + this.updateEnv(otherEnv, [ + { + option: "-sUSE_PTHREADS", + value: "1", + type: "replace", + }, + ]); + } else if ( + (!envFlags.includes("-sUSE_PTHREADS=1") || + !envFlags.includes("-sPROXY_TO_PTHREAD=1") || + envFlags.includes("-sUSE_PTHREADS=0") || + envFlags.includes("-sPROXY_TO_PTHREAD=0")) && + this.getOption("needPthread") + ) { + this.setOption("needPthread", false); + this.updateEnv(currentEnv, [ + { + option: "-sUSE_PTHREADS", + value: null, + type: "deleteAll", + }, + { + option: "-sPROXY_TO_PTHREAD", + value: null, + type: "deleteAll", + }, + ]); + this.updateEnv(otherEnv, { + option: "-sUSE_PTHREADS", + value: null, + type: "deleteAll", + }); + } + + // modularize option related update + if (envFlags.includes("-sMODULARIZE=1") && !this.getOption("needModularize")) { + this.setOption("needModularize", true); + } else if ( + (!envFlags.includes("-sMODULARIZE=1") || envFlags.includes("-sMODULARIZE=0")) && + this.getOption("needModularize") + ) { + this.setOption("needModularize", false); + this.updateEnv(currentEnv, { + option: "-sMODULARIZE", + value: null, + type: "deleteAll", + }); + } + } + + // c++ exception related update + if (envFlags.includes("-fwasm-exceptions") && !this.getOption("needCppException")) { + this.setOption("needCppException", true); + this.updateEnv(otherEnv, { + option: "-fwasm-exceptions", + value: null, + type: "replace", + }); + } else if (!envFlags.includes("-fwasm-exceptions") && this.getOption("needCppException")) { + this.setOption("needCppException", false); + this.updateEnv(otherEnv, { + option: "-fwasm-exceptions", + value: null, + type: "deleteAll", + }); + } + + // simd option related update + if (envFlags.includes("-msimd128") && !this.getOption("needSimd")) { + this.setOption("needSimd", true); + this.updateEnv(otherEnv, { + option: "-msimd128", + value: null, + type: "replace", + }); + } else if (!envFlags.includes("-msimd128") && this.getOption("needSimd")) { + this.setOption("needSimd", false); + this.updateEnv(otherEnv, { + option: "-msimd128", + value: null, + type: "deleteAll", + }); + } + } + + updateConfigsFromEnvs(currentEnv: EnvType) { + if (currentEnv === "ldflags") { + const localFiles = [] as string[]; + let setExportedFuncs = false; + let setExportedRuntimeMethods = false; + if (this.getEnv("ldflags").trim()) { + const args = shlex.split(this.getEnv("ldflags").trim()); + for (let i = 0; i < args.length; i++) { + const a = args[i]; + if (a.includes("-sEXPORTED_FUNCTIONS") && !setExportedFuncs) { + const f = a.split("=").pop()?.trim(); + if (f) { + const fns = [ + ...new Set( + f + .split(",") + .map((fn) => fn.trim()) + .filter((fn) => fn) + ), + ]; + args[i] = `-sEXPORTED_FUNCTIONS=${fns.join(",")}`; + // remove the first "_" + this.exportedFuncs = fns.map((fn) => fn.replace("_", "")).join(","); + setExportedFuncs = true; + } + continue; + } + if (a.includes("-sEXPORTED_RUNTIME_METHODS") && !setExportedRuntimeMethods) { + const f = a.split("=").pop()?.trim(); + if (f) { + const fns = [ + ...new Set( + f + .split(",") + .map((fn) => fn.trim()) + .filter((fn) => fn) + ), + ]; + args[i] = `-sEXPORTED_RUNTIME_METHODS=${fns.join(",")}`; + this.exportedRuntimeMethods = fns.join(","); + setExportedRuntimeMethods = true; + } + continue; + } + if (a.includes("--preload-file")) { + // store local file path and mapped path in virtual FS together + const f = a.split(" ").pop()?.trim(); + if (f && !localFiles.includes(f)) { + localFiles.push(f); + } else { + args[i] = ""; + } + continue; + } + } + this.setEnv("ldflags", shlex.join(args)); + } + if (!setExportedFuncs) this.exportedFuncs = ""; + if (!setExportedRuntimeMethods) this.exportedRuntimeMethods = ""; + this.preloadFiles = localFiles; + } + } + + updateConfigsAndOptsFromEnvs(updateParts?: EnvType | EnvType[]) { + let toUpdate: EnvType[] = []; + if (updateParts) { + // update envs from specified options + toUpdate = Array.isArray(updateParts) ? updateParts : [updateParts]; + } else { + // update envs from all options + if (this.envs) toUpdate = Object.keys(this.envs) as EnvType[]; + } + + if (toUpdate.length) { + if (toUpdate.includes("cflags")) { + log.info("... update from cflags change: ", this.getEnv("cflags")); + this.updateOptionsFromEnvs("cflags"); + } + if (toUpdate.includes("ldflags")) { + log.info("... update from ldflags change: ", this.getEnv("ldflags")); + this.updateConfigsFromEnvs("ldflags"); + this.updateOptionsFromEnvs("ldflags"); + } + } + } + + async setRelocatable(type: ActionType): Promise { + if ( + !this.getEnv("cflags").includes("MAIN_MODULE") && + !this.getEnv("cflags").includes("SIDE_MODULE") && + !this.getEnv("ldflags").includes("MAIN_MODULE") && + !this.getEnv("ldflags").includes("SIDE_MODULE") + ) { + // only set/reset -sRELOCATABLE if MAIN_MODULE or SIDE_MODULE options are not set + this.updateEnvs({ + option: "-sRELOCATABLE", + value: null, + type: type, + }); + } + if (!this._proj.config.dependencies) { + await this._proj.config.getDependencies(); + } + if (this._proj.config.dependencies && !H.isObjectEmpty(this._proj.config.dependencies)) { + for (const dep in this._proj.config.dependencies) { + const depProject = this._proj.config.dependencies[dep]; + const depBuildConfig = depProject.config.getBuildConfigForTarget(depProject.config.target); + await depBuildConfig.setRelocatable(type); + } + } + } + + updateBuildConfig(jsonParts: H.Dict, options: IBuildConfigUpdateOptions = {}) { + const updateOptions: IBuildConfigUpdateOptions = { refresh: true }; + if (options) { + _.extend(updateOptions, options); + } + const { updateEnvParts, updateOptParts, refresh } = updateOptions; + // perform the schema validation before actually updating the config JSON data. + this.validateBuildTargetConfigSchema(jsonParts); + // update config data + Object.assign(this._data, jsonParts); + this.save(); + log.info("updateBuildConfig", jsonParts, updateEnvParts, updateOptParts); + if (refresh) { + const jsonKeys = Object.keys(jsonParts); + if (jsonKeys.includes("builders")) { + this._builders = null; + this.convertBuildersToMeta(); + } + if (jsonKeys.includes("pkgConfig")) { + this.convertPkgConfigToMeta(); + } + let updateEnvs = false; + const setUpdateEnvsBit = () => { + if (!updateEnvs) updateEnvs = true; + }; + if (jsonKeys.includes("preloadFiles")) { + this.updateEnvsFromPreloadFiles(); + setUpdateEnvsBit(); + } + if (jsonKeys.includes("exportedFuncs")) { + this.updateEnvsFromExportedFuncs(); + setUpdateEnvsBit(); + } + if (jsonKeys.includes("exportedRuntimeMethods")) { + this.updateEnvsFromExportedRuntimeMethods(); + setUpdateEnvsBit(); + } + if (jsonKeys.includes("options")) { + this.updateEnvsFromOptions(updateOptParts); + setUpdateEnvsBit(); + } + if (jsonKeys.includes("envs")) { + this.updateConfigsAndOptsFromEnvs(updateEnvParts); + setUpdateEnvsBit(); + } + if (updateEnvs) { + this.convertEnvsToMeta(); + this._proj.config.updateOverallEnvsFromSelf(this.envs); + } + } + } + + resetBuildConfig() { + this.resetOptions(); + this.resetEnvs(); + if (this.disabledAdvisors) this.resetAdvisors(); + if (this.exportedFuncs) this.exportedFuncs = ""; + if (this.exportedRuntimeMethods) this.exportedRuntimeMethods = ""; + if (this.preloadFiles) this.preloadFiles = []; + } + + convertEnvsToMeta() { + if (this.envs && !H.isObjectEmpty(this.envs)) { + if ( + !H.isObjectEmpty( + H.getObjDifference( + this._proj.meta.get(`webinizer.buildTargets.${this.target}.envs`) as H.Dict, + this.envs as H.Dict + ) + ) + ) { + this._proj.meta.set(`webinizer.buildTargets.${this.target}.envs`, _.cloneDeep(this.envs)); + } + } + } + + convertBuildersToMeta() { + if (this.rawBuilders && this.rawBuilders.length) { + const buildStepMap = new Map([ + ["CMakeBuilder", "emcmake cmake"], + ["ConfigureBuilder", "emconfigure ./configure"], + ["MakeBuilder", "emmake make"], + ["EmccBuilder", "emcc"], + ]); + const buildSteps = this.rawBuilders.map((b) => { + if (b.__type__ === "NativeBuilder") { + // parse NativeBuilder args to command and args + const [first, ...rest] = shlex.split(b.args as string); + return { + command: first, + args: shlex.join(rest), + cwd: b.rootBuildFilePath || "${projectRoot}", + }; + } + return { + command: buildStepMap.get(b.__type__) || "", + args: b.args || "", + cwd: b.rootBuildFilePath || "${projectRoot}", + } as H.Dict; + }); + if ( + !H.isObjectEmpty( + H.getObjDifference( + { + buildSteps: this._proj.meta.get( + `webinizer.buildTargets.${this.target}.buildSteps` + ) as H.Dict, + }, + { buildSteps } as H.Dict + ) + ) + ) { + this._proj.meta.set(`webinizer.buildTargets.${this.target}.buildSteps`, buildSteps); + } + } + } + + convertPkgConfigToMeta() { + if (this._proj.config.isLibrary && this.pkgConfig && !H.isObjectEmpty(this.pkgConfig)) { + if ( + !H.isObjectEmpty( + H.getObjDifference( + this._proj.meta.get( + `webinizer.buildTargets.${this.target}.pkgConfig` + ) as H.Dict, + this.pkgConfig as H.Dict + ) + ) + ) { + this._proj.meta.set( + `webinizer.buildTargets.${this.target}.pkgConfig`, + _.cloneDeep(this.pkgConfig) + ); + } + } + } + + // convert `buildTargets` in config.json to package.json + // Fields included: envs, builders, pkgConfig + convertBuildTargetToMeta(convertParts?: ("envs" | "builders" | "pkgConfig")[]) { + let fieldsToConvert = ["envs", "builders", "pkgConfig"]; + if (convertParts && convertParts.length) { + fieldsToConvert = convertParts; + } + if (fieldsToConvert.includes("envs")) this.convertEnvsToMeta(); + if (fieldsToConvert.includes("builders")) this.convertBuildersToMeta(); + if (fieldsToConvert.includes("pkgConfig")) this.convertPkgConfigToMeta(); + } + + validateBuildTargetConfigSchema(configData: H.Dict) { + const ajv = new Ajv(); + const validate = ajv.compile(buildTargetConfigSchema); + + const valid = validate(configData); + if (!valid) { + log.info( + `Errors happened in config data validation for target ${this.target} of project ${this._proj.config.name}@${this._proj.config.version}:\n`, + validate.errors + ); + throw new H.WError( + `Errors happened in config data validation for target ${this.target} of project ${ + this._proj.config.name + }@${this._proj.config.version}:\n${ajv.errorsText(validate.errors)}`, + errorCode.WEBINIZER_META_SCHEMA_VALIDATION_FAILED + ); + } else log.info(`Config data validation for target ${this.target} passed!`); + } + + save() { + this._proj.config.save(); + } +} + +export class ProjectConfig extends ProjectCacheFile implements IProjectConfig { + static __type__ = "ProjectConfig"; + private _dependencies: H.Dict | null = null; // lazy created dependent projects + private _buildTargetConfigMap: H.Dict | null = null; // holds all build targets' config + + constructor(proj: Project, filePath: string) { + super(proj, filePath, ProjectConfig.__type__); + } + + get name(): string | undefined { + return this.data.name as string; + } + + set name(v: string | undefined) { + this.data = { name: v }; + if (this.name?.toLocaleLowerCase() !== this.proj.meta.get("name")) { + this.proj.meta.set("name", this.name?.toLocaleLowerCase()); + } + } + + get version(): string | undefined { + return this.data.version as string; + } + + set version(v: string | undefined) { + this.data = { version: v }; + if (this.version !== this.proj.meta.get("version")) { + this.proj.meta.set("version", this.version); + } + } + + get desc(): string | undefined { + return this.data.desc as string; + } + + set desc(v: string | undefined) { + this.data = { desc: v }; + if (this.desc !== this.proj.meta.get("description")) { + this.proj.meta.set("description", this.desc); + } + } + + // img: path to project image file + get img(): string | undefined { + return this.data.img as string; + } + + set img(v: string | undefined) { + this.data = { img: v }; + } + + // category: project category + get category(): string | undefined { + return this.data.category as string; + } + + set category(v: string | undefined) { + this.data = { category: v }; + } + + // id: sort projects based on id value, should only be defined for demo projects + get id(): number | undefined { + return this.data.id as number; + } + + set id(v: number | undefined) { + this.data = { id: v }; + } + + // deleted: the flag of project deleted status + get deleted(): boolean | undefined { + return this.data.deleted as boolean; + } + + set deleted(v: boolean | undefined) { + this.data = { deleted: v }; + } + + // target: the selected build target for Project + get target(): string | undefined { + // set the first target defined in `buildTargets` as default if `target` is not defined + if (!this.data.target && this.rawBuildTargets && !H.isObjectEmpty(this.rawBuildTargets)) { + this.target = Object.keys(this.rawBuildTargets)[0]; + } + return this.data.target as string; + } + + set target(v: string | undefined) { + this.data = { target: v }; + if (v) this.updateOverallEnvsFromSelf(this.getBuildConfigForTarget(this.target).envs); + } + + // isLibrary: the project is a library or not + get isLibrary(): boolean | undefined { + return this.data.isLibrary as boolean; + } + + set isLibrary(v: boolean | undefined) { + this.data = { isLibrary: v }; + } + + get useDefaultConfig(): boolean | undefined { + return this.data.useDefaultConfig as boolean; + } + + set useDefaultConfig(v: boolean | undefined) { + this.data = { useDefaultConfig: v }; + } + + // nativeLibrary: the native library info - name and version + get nativeLibrary(): H.Dict | undefined { + return this.data.nativeLibrary as H.Dict; + } + + set nativeLibrary(v: H.Dict | undefined) { + this.data = { nativeLibrary: v }; + } + + // requiredBy: the packages that depends on this project - the opposite of dependencies + get requiredBy(): H.Dict | undefined { + return this.data.requiredBy as H.Dict; + } + + set requiredBy(v: H.Dict | undefined) { + this.data = { requiredBy: v }; + } + + get rawDependencies(): H.Dict | undefined { + return this.data.dependencies as H.Dict; + } + + async setRawDependencies(v: H.Dict | undefined) { + this.data = { dependencies: v }; + this._dependencies = null; + if (this.proj.isRootProject) { + // this is for rootProject only + await this.finalizeDependencyProjects(); + } + await this.updateOverallEnvsFromDeps(); + if ( + !H.isObjectEmpty( + H.getObjDifference( + this.proj.meta.get("dependencies") as H.Dict, + this.rawDependencies as H.Dict + ) + ) + ) { + this.proj.meta.set("dependencies", _.cloneDeep(this.rawDependencies)); + } + } + + // resolved dependencies with package info + get resolutions(): IPackage[] | undefined { + return this.data.resolutions as IPackage[]; + } + + set resolutions(v: IPackage[] | undefined) { + this.data = { resolutions: v }; + } + + async finalizeDependencyProjects() { + const resolver = new DependencyResolver(this.proj); + this.resolutions = await resolver.resolveDependencies(); + // update configs for each dependency + if (this.resolutions && this.resolutions.length) { + for (const dep of this.resolutions) { + if (dep.destination) { + // create Project for dependency with `isRoot = false` + const depProject = new Project(path.join(this.proj.root, dep.destination), false); + // convert package.json to config.json if config.json doesn't exist + if (fs.existsSync(depProject.meta.path) && !fs.existsSync(depProject.config.path)) { + try { + depProject.meta.validateMetaSchema(_.cloneDeep(depProject.meta.data)); + await depProject.config.convertFromRegMeta(); + } catch (err) { + // remove the project folder before throw the error. + fs.rmSync(path.join(this.proj.root, dep.destination), { + recursive: true, + force: true, + }); + throw err as Error; + } + } + // add requiredBy field from the root project's `resolutions` field to config.json + await depProject.config.updateRawJson({ requiredBy: _.cloneDeep(dep.requiredBy) }); + } + } + } + } + + get dependencies(): H.Dict | null { + return this._dependencies; + } + + async getDependencies(): Promise { + if (!this._dependencies) { + if (this.rawDependencies && !H.isObjectEmpty(this.rawDependencies)) { + this._dependencies = {}; + for (const dep in this.rawDependencies) { + const depRoot = await this.detectProjectRoot(dep, this.rawDependencies[dep]); + log.info(`detectDependencyProjectRoot`, dep, this.rawDependencies[dep], depRoot); + if (depRoot) { + if (!this._dependencies[dep]) { + // create Project for dependency with `isRoot = false` + const depProject = new Project(depRoot, false); + // convert package.json to config.json if config.json doesn't exist + if (fs.existsSync(depProject.meta.path) && !fs.existsSync(depProject.config.path)) { + await depProject.config.convertFromRegMeta(); + } + this._dependencies[dep] = depProject; + } + } else { + throw new H.WError( + `Can't find dependent project ${dep} on local disk`, + errorCode.WEBINIZER_ROOT_NOEXT + ); + } + } + } + } + // return this._dependencies; + } + + // Detect project root for dependencies or requiredBy projects based on path + async detectProjectRoot( + name: string, + reference: string, + forDependencies = true + ): Promise { + const searchPaths: string[] = []; + if (forDependencies) { + // detect for dependencies, search paths include: + // - root project --> `webinizer_deps` sub-dir in current root + // - dependent project --> parent directory `webinizer_deps` + if (this.proj.isRootProject) + searchPaths.push(path.join(this.proj.root, C.dependencyDir, name.toLocaleLowerCase())); + else searchPaths.push(path.join(path.dirname(this.proj.root), name.toLocaleLowerCase())); + } else { + if (!this.proj.isRootProject) { + // detect for requiredBy, search paths include: + // 1. parent directory `webinizer_deps` --> another dependency of the main project + // 2. parent directory of `webinizer_deps` --> the main projet + searchPaths.push(path.join(path.dirname(this.proj.root), name.toLocaleLowerCase())); + searchPaths.push(path.join(path.dirname(path.dirname(this.proj.root)))); + } + } + // if `reference` is not a semver or semver range (i.e., a directory/file path), convert it to a + // version number at first + let depVer = ""; + if (reference.startsWith("file:")) { + const packageManifest = await getPackageFetcher({ name, reference }).getManifest(); + depVer = packageManifest.version; + } + for (const searchPath of searchPaths) { + if (fs.existsSync(searchPath)) { + if (fs.existsSync(path.join(searchPath, "package.json"))) { + const packageJson = JSON.parse( + fs.readFileSync(path.join(searchPath, "package.json"), "utf8") + ); + const depRef = depVer ? depVer : reference; + if ( + packageJson.name === name.toLocaleLowerCase() && + ((semver.valid(depRef) && depRef === packageJson.version) || + (semver.validRange(depRef) && semver.satisfies(packageJson.version, depRef))) + ) { + return searchPath; + } + } + } + } + + return null; + } + + // overallEnvs: the combination of self envs and deps' pkgConfig field, read-only for users + get overallEnvs(): ProjectEnv | undefined { + return this.data.overallEnvs as ProjectEnv; + } + + set overallEnvs(v: ProjectEnv | undefined) { + Object.assign(this.data, { overallEnvs: v }); + this.save(); + } + + getOverallEnv(key: EnvType): string { + const overallEnvs = (this.overallEnvs || {}) as ProjectEnv; + return overallEnvs[key] as string; + } + + setOverallEnv(key: EnvType, value: string) { + if (!this.overallEnvs) { + this.overallEnvs = {} as ProjectEnv; + } + Object.assign(this.overallEnvs as ProjectEnv, { [key]: value }); + this.save(); + } + + // overallEnvsMap: a map holding {dep: config} pair to store state + get overallEnvsMap(): H.Dict | undefined { + return this.data.overallEnvsMap as H.Dict; + } + + set overallEnvsMap(v: H.Dict | undefined) { + Object.assign(this.data, { overallEnvsMap: v }); + this.save(); + } + + async gatherPkgConfigsFromDeps(envsDict: H.Dict) { + if (!this.dependencies) { + await this.getDependencies(); + } + if (this.dependencies && !H.isObjectEmpty(this.dependencies)) { + for (const dep in this.dependencies) { + const depProject = this.dependencies[dep]; + const depBuildConfig = depProject.config.getBuildConfigForTarget(depProject.config.target); + await depProject.config.gatherPkgConfigsFromDeps(envsDict); + + if ( + depBuildConfig.pkgConfig && + depBuildConfig.pkgConfig.prefix && + depBuildConfig.pkgConfig.cflags && + depBuildConfig.pkgConfig.ldflags + ) { + const prefixVal = depProject + .evalTemplateLiterals(depBuildConfig.getPkgConfigEnv("prefix")) + .replace(/'/g, ""); + + const compilerFlags = depBuildConfig + .getPkgConfigEnv("cflags") + .replaceAll("${prefix}", prefixVal); + + const linkerFlags = depBuildConfig + .getPkgConfigEnv("ldflags") + .replaceAll("${prefix}", prefixVal); + + if (!Object.keys(envsDict).includes(dep)) { + envsDict[dep] = { + cflags: compilerFlags + ? compilerFlags + : `-I${path.join(depProject.root, C.buildDir, "include")}`, + ldflags: linkerFlags + ? linkerFlags + : `-L${path.join(depProject.root, C.buildDir, "lib")}`, + } as ProjectEnv; + } + } else { + log.warn( + `Package configurations of project ${depProject.config.name} are not defined properly.` + ); + // throw error and stop the process if pkgConfig field is not properly defined. + throw new H.WError( + `Package configurations of project "${depProject.config.name}" and build target "${depProject.config.target}" are not defined properly.`, + errorCode.WEBINIZER_META_FIELD_UNDEFINED + ); + } + } + } + } + + updateOverallEnvsFromSelf(envs: ProjectEnv | undefined, needUpdateRaw = true) { + if (!this.overallEnvsMap) { + this.overallEnvsMap = {}; + } + if ( + envs && + (!Object.keys(this.overallEnvsMap).includes("self") || + this.overallEnvsMap.self.cflags !== envs.cflags || + this.overallEnvsMap.self.ldflags !== envs.ldflags) + ) { + // only update self envs when it's changed + log.info(`updateOverallEnvsFromSelf, envs is ${JSON.stringify(envs, null, 2)}`); + Object.assign(this.overallEnvsMap, { self: _.cloneDeep(envs) }); + if (needUpdateRaw) this.updateRawOverallEnvs(); + } + } + + async updateOverallEnvsFromDeps(needUpdateRaw = true) { + log.info( + `updateOverallEnvsFromDeps for ${this.proj.root}`, + JSON.stringify(this.overallEnvsMap, null, 2) + ); + const newEnvsMapFromDeps: H.Dict = {}; + await this.gatherPkgConfigsFromDeps(newEnvsMapFromDeps); + const oldDeps = Object.keys(this.overallEnvsMap || {}); + const newDeps = Object.keys(newEnvsMapFromDeps); + log.info( + `updateOverallEnvsFromDeps newDeps for ${this.proj.root}`, + JSON.stringify(newEnvsMapFromDeps, null, 2) + ); + newDeps.forEach((dep) => { + if (!this.overallEnvsMap) { + this.overallEnvsMap = {}; + } + this.overallEnvsMap[dep] = newEnvsMapFromDeps[dep]; + }); + oldDeps + .filter((dep) => !newDeps.includes(dep) && dep !== "self") + .forEach((dep) => { + delete this.overallEnvsMap?.[dep]; + }); + if (needUpdateRaw) this.updateRawOverallEnvs(); + } + + updateRawOverallEnvs() { + log.info( + `updateRawOverallEnvs for project ${this.proj.root}`, + JSON.stringify(this.overallEnvsMap, null, 2), + `\nis this a root project? - ${this.proj.isRootProject}` + ); + if (this.overallEnvsMap) { + const overallCflags = Object.keys(this.overallEnvsMap) + .map((dep) => { + return this.overallEnvsMap?.[dep].cflags; + }) + .join(" "); + this.setOverallEnv( + "cflags", + shlex + .join([...new Set(shlex.split(overallCflags))]) + .replaceAll(this.proj.root, "${projectRoot}") + ); + + // update linker flags from dependent projects for root/main project only + const overallLdflags = this.proj.isRootProject + ? Object.keys(this.overallEnvsMap) + .map((dep) => { + return this.overallEnvsMap?.[dep].ldflags; + }) + .join(" ") + : this.overallEnvsMap.self.ldflags; + + this.setOverallEnv( + "ldflags", + shlex + .join([...new Set(shlex.split(overallLdflags))]) + .replaceAll(this.proj.root, "${projectRoot}") + ); + } + } + + async isSharedBuild(): Promise { + if (this.target === "shared") return true; + if (!this.dependencies) { + await this.getDependencies(); + } + if (this.dependencies && !H.isObjectEmpty(this.dependencies)) { + for (const dep in this.dependencies) { + const isShared = await this.dependencies[dep].config.isSharedBuild(); + if (isShared) return true; + } + } + return false; + } + + // rawBuildTargets: raw configs for all build targets + get rawBuildTargets(): H.Dict | undefined { + return this.data.buildTargets as H.Dict; + } + + set rawBuildTargets(v: H.Dict | undefined) { + this.data = { buildTargets: v }; + this._buildTargetConfigMap = null; + this.convertBuildTargetsToMeta(); + } + + getRawBuildConfigForTarget(key: string): H.Dict | undefined { + const buildTargets = (this.rawBuildTargets || {}) as H.Dict; + return buildTargets[key] as H.Dict; + } + + setRawBuildConfigForTarget(key: string, value: H.Dict | undefined) { + Object.assign(this.rawBuildTargets || {}, { [key]: value }); + this._buildTargetConfigMap = null; + this.save(); + if (value) this.getBuildConfigForTarget(key).convertBuildTargetToMeta(); + } + + get buildTargetConfigMap() { + if (!this._buildTargetConfigMap) { + if (this.rawBuildTargets) { + this._buildTargetConfigMap = {}; + for (const t in this.rawBuildTargets) { + if (!this._buildTargetConfigMap[t]) { + this._buildTargetConfigMap[t] = new ProjectBuildConfig( + this.proj, + this.getRawBuildConfigForTarget(t) as H.Dict, + t + ); + } + } + } + } + return this._buildTargetConfigMap; + } + + getBuildConfigForTarget(target: string | undefined): ProjectBuildConfig { + if ( + target && + this.buildTargetConfigMap && + Object.keys(this.buildTargetConfigMap).includes(target) + ) { + return this.buildTargetConfigMap[target]; + } else { + throw new H.WError("Build target doesn't exist!", errorCode.WEBINIZER_PROJ_TARGET_NOEXT); + } + } + + async updateRawJson(jsonParts: H.Dict, refresh = true) { + // perform the schema validation before actually updating the config JSON data. + this.validateConfigSchema(jsonParts); + // update config data + this.data = jsonParts; + if (refresh) { + const jsonKeys = Object.keys(jsonParts); + // refresh cache + if (jsonKeys.includes("name")) { + this.proj.meta.set("name", this.name?.toLocaleLowerCase()); + } + if (jsonKeys.includes("version")) { + this.proj.meta.set("version", this.version); + } + if (jsonKeys.includes("desc")) { + this.proj.meta.set("description", this.desc); + } + if (jsonKeys.includes("buildTargets")) { + this._buildTargetConfigMap = null; + this.convertBuildTargetsToMeta(); + } + if (jsonKeys.includes("dependencies")) { + // if dependencies are updated, set dependencyTree and dependencies to null + this._dependencies = null; + if (this.proj.isRootProject) { + // for root project only + await this.finalizeDependencyProjects(); + } + await this.updateOverallEnvsFromDeps(); + this.proj.meta.set("dependencies", _.cloneDeep(this.rawDependencies)); + } + if (jsonKeys.includes("target")) { + if (this.target) { + if (this.rawBuildTargets) { + if (!Object.keys(this.rawBuildTargets).includes(this.target)) { + // if this is to set a new target, initialize the raw build config for it as an empty object {} + this.setRawBuildConfigForTarget(this.target, {} as H.Dict); + } + } else { + // buildTargets field is not defined yet, initialize buildTargets first and then + // initialize the raw build config for target as an empty object {} + this.rawBuildTargets = {} as H.Dict; + this.setRawBuildConfigForTarget(this.target, {} as H.Dict); + } + this.updateOverallEnvsFromSelf(this.getBuildConfigForTarget(this.target).envs); + } + } + } + } + + getProjectProfile(): IProjectProfile { + const profile: IProjectProfile = {}; + if (this.name) Object.assign(profile, { name: this.name }); + if (this.desc) Object.assign(profile, { desc: this.desc }); + if (this.img) Object.assign(profile, { img: this.img }); + if (this.category) Object.assign(profile, { category: this.category }); + if (this.version) Object.assign(profile, { version: this.version }); + if (this.deleted !== undefined) Object.assign(profile, { deleted: this.deleted }); + + // this.id could be 0 so can't simply use this.id + if (this.id !== undefined && this.id !== null) Object.assign(profile, { id: this.id }); + return profile; + } + + setProjectProfile(v: IProjectProfile) { + if ("path" in v) { + // remove path entry before updating to ProjectConfig + delete v.path; + } + this.data = v as H.Dict; + } + + convertBuildTargetsToMeta() { + if (this.buildTargetConfigMap) { + Object.keys(this.buildTargetConfigMap).forEach((target) => { + this.getBuildConfigForTarget(target).convertBuildTargetToMeta(); + }); + } + } + + // convert config.json to package.json + convertToRegMetaFromConfig() { + if (this.name) { + this.proj.meta.set("name", this.name.toLocaleLowerCase()); + } else { + throw new H.WError("Package name is required.", errorCode.WEBINIZER_META_FIELD_UNDEFINED); + } + if (this.version) { + this.proj.meta.set("version", this.version); + } else { + throw new H.WError("Package version is required.", errorCode.WEBINIZER_META_FIELD_UNDEFINED); + } + if (this.desc) { + this.proj.meta.set("description", this.desc); + } + /* dependencies */ + if (this.rawDependencies) { + this.proj.meta.set("dependencies", _.cloneDeep(this.rawDependencies)); + } + + /* webinizer customized fields */ + // buildTargets + if (this.buildTargetConfigMap) { + this.convertBuildTargetsToMeta(); + } + // nativeLibrary + if (this.nativeLibrary) { + this.proj.meta.set("webinizer.nativeLibrary", _.cloneDeep(this.nativeLibrary)); + } + } + + async convertToRegMetaForPublish() { + this.convertToRegMetaFromConfig(); + // add toolchain info when publish + const toolchainVer = await H.runCommand("emcc --version", { silent: true }); + if (toolchainVer.code === 0) { + const versionReg = /emcc \([^()]*\) (?[0-9]+.[0-9]+.[0-9]+) \((?[a-z0-9]*)\)/; + for (const line of toolchainVer.all.split("\n")) { + const m = line.match(versionReg); + if (m && m.groups) { + const version = m.groups.ver.trim(); + this.proj.meta.set("webinizer.toolchain", { emscripten: version }); + break; + } + } + } + } + + convertBuildTargetFromRegMeta(target: string, diffContent: H.Dict) { + const targetJson = _.cloneDeep( + this.proj.meta.get(`webinizer.buildTargets.${target}`) + ) as H.Dict; + if (!this.rawBuildTargets) { + this.rawBuildTargets = {}; + } + if (targetJson) { + const convertedJson = this.getRawBuildConfigForTarget(target) || {}; + if (dotProp.has(diffContent, `webinizer.buildTargets.${target}.envs`)) + Object.assign(convertedJson, { envs: targetJson.envs || { cflags: "", ldflags: "" } }); + if (dotProp.has(diffContent, `webinizer.buildTargets.${target}.pkgConfig`)) { + Object.assign(convertedJson, { + pkgConfig: targetJson.pkgConfig || undefined, + }); + } + if (dotProp.has(diffContent, `webinizer.buildTargets.${target}.buildSteps`)) { + // convert buildSteps to rawBuilders + const steps = (targetJson.buildSteps || []) as H.Dict[]; + const builderTypeMap = new Map([ + ["emcmake cmake", "CMakeBuilder"], + ["emconfigure ./configure", "ConfigureBuilder"], + ["emmake make", "MakeBuilder"], + ["emcc", "EmccBuilder"], + ]); + + const rawBuilders = steps.map((step) => { + const builderType = builderTypeMap.get(step.command); + return { + __type__: builderType || "NativeBuilder", + args: builderType ? step.args : `${step.command} ${step.args}`, + rootBuildFilePath: step.cwd, + }; + }); + Object.assign(convertedJson, { builders: rawBuilders }); + } + this.setRawBuildConfigForTarget(target, convertedJson); + this.getBuildConfigForTarget(target).updateBuildConfig(convertedJson); + } else { + // delete the entire buildConfig for target + this.setRawBuildConfigForTarget(target, undefined); + } + } + + // convert package.json to config.json + async convertFromRegMeta(diffContent = _.cloneDeep(this.proj.meta.data)) { + if (dotProp.has(diffContent, "name")) { + this.name = (this.proj.meta.get("name") || "") as string; + } + if (dotProp.has(diffContent, "version")) { + this.version = (this.proj.meta.get("version") || "") as string; + } + if (dotProp.has(diffContent, "description")) { + this.desc = (this.proj.meta.get("description") || "") as string; + } + /* handle webinizer specific fields */ + if (dotProp.has(diffContent, "webinizer.nativeLibrary")) { + this.nativeLibrary = (_.cloneDeep(this.proj.meta.get("webinizer.nativeLibrary")) || + undefined) as H.Dict; + // set isLibrary to true + if (this.nativeLibrary && !this.isLibrary) this.isLibrary = true; + } + // buildTargets + this.useDefaultConfig = false; + if (dotProp.has(diffContent, "webinizer.buildTargets")) { + Object.keys(dotProp.get(diffContent, "webinizer.buildTargets") as H.Dict).forEach( + (target) => { + log.info(`update buildConfig for target ${target}`); + this.convertBuildTargetFromRegMeta(target, diffContent); + } + ); + // update the default target if the original one was deleted + const newTargetSet = Object.keys(this.rawBuildTargets || {}).filter((t) => + this.getRawBuildConfigForTarget(t) + ); + if (newTargetSet.length) { + if (this.target && !newTargetSet.includes(this.target)) this.target = newTargetSet[0]; + } else { + this.target = ""; + } + } + + /* dependencies */ + if (dotProp.has(diffContent, "dependencies")) { + await this.setRawDependencies( + (_.cloneDeep(this.proj.meta.get("dependencies")) || {}) as H.Dict + ); + } + } + + validateConfigSchema(configData: H.Dict) { + const ajv = new Ajv(); + const validate = ajv.addSchema(buildTargetConfigSchema).compile(configSchema); + + const valid = validate(configData); + if (!valid) { + log.info( + `Errors happened in config data schema validation of project ${this.name}@${this.version}:\n`, + validate.errors + ); + throw new H.WError( + `Errors happened in config data schema validation of project ${this.name}@${ + this.version + }:\n${ajv.errorsText(validate.errors)}`, + errorCode.WEBINIZER_META_SCHEMA_VALIDATION_FAILED + ); + } else log.info("Config data validation passed!"); + } + + // config.json file backup and restore + backup() { + if (fs.existsSync(this.path) && !fs.existsSync(`${this.path}.bak`)) { + fs.copyFileSync(this.path, `${this.path}.bak`); + // chmod for the temp file to be read-only + fs.chmodSync(`${this.path}.bak`, 0o0400); + } + } + + restoreFromBackupFile() { + if (fs.existsSync(`${this.path}.bak`)) { + this.reset(); + this.data = JSON.parse(fs.readFileSync(`${this.path}.bak`, "utf8")) as IJsonObject; + this.cleanBackupFile(); + } + } + + cleanBackupFile() { + fs.rmSync(`${this.path}.bak`, { force: true }); + } +} diff --git a/src/project_caches/project_log.ts b/src/project_caches/project_log.ts new file mode 100644 index 0000000..512222b --- /dev/null +++ b/src/project_caches/project_log.ts @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import ProjectCacheFile from "./project_cache_file"; +import { Project } from "../project"; +import { IProjectLog } from "webinizer"; + +export default class ProjectLog extends ProjectCacheFile implements IProjectLog { + static __type__ = "ProjectLog"; + private _content = ""; // log content + + constructor(proj: Project, filePath: string) { + super(proj, filePath, ProjectLog.__type__); + } + + getContent(): string { + return this.data.content as string; + } + + update(content: string) { + this._content += content; + this.data = { content: this._content }; + } + + clear() { + this._content = ""; + this.data = { content: "" }; + } +} diff --git a/src/project_caches/project_recipe.ts b/src/project_caches/project_recipe.ts new file mode 100644 index 0000000..8f5268f --- /dev/null +++ b/src/project_caches/project_recipe.ts @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import ProjectCacheFile from "./project_cache_file"; +import { Project } from "../project"; +import { Recipe } from "../recipe"; + +export default class ProjectRecipe extends ProjectCacheFile { + static __type__ = "ProjectRecipe"; + + constructor(proj: Project, filePath: string) { + super(proj, filePath, ProjectRecipe.__type__); + } + + saveRecipes(res: Recipe[]) { + this.data = { recipes: res.map((r) => r.toJson()) }; + } + + clear() { + this.data = { recipes: [] }; + } +} diff --git a/src/project_caches/project_result.ts b/src/project_caches/project_result.ts new file mode 100644 index 0000000..de1ba87 --- /dev/null +++ b/src/project_caches/project_result.ts @@ -0,0 +1,239 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import path from "path"; +import fs from "graceful-fs"; +import ProjectCacheFile from "./project_cache_file"; +import { Project } from "../project"; +import { buildDirTree } from "../dtree"; +import * as H from "../helper"; +import * as C from "../constants"; + +interface IResultFile { + path: string; + name: string; + type: "file" | "directory"; + size: number; + date: Date; +} + +interface ITargetResult { + target: string; + type: "executable" | "library"; + result: IResultFile[]; +} + +interface IResultTimestamp { + tStart: Date; + tEnd: Date; + tDur: number; +} + +export default class ProjectResult extends ProjectCacheFile { + static __type__ = "ProjectResult"; + + constructor(proj: Project, filePath: string) { + super(proj, filePath, ProjectResult.__type__); + } + + get files(): ITargetResult[] { + return this.data.files as ITargetResult[]; + } + + get timestamps(): IResultTimestamp { + return this.data.timestamps as IResultTimestamp; + } + + set timestamps(t: IResultTimestamp) { + this.data = { timestamps: t }; + } + + genFileStats(filePath: string): IResultFile { + const fileStat = fs.statSync(filePath); + let fileType = "file"; + if (fileStat.isDirectory()) fileType = "directory"; + return { + path: filePath, + name: path.basename(filePath), + type: fileType, + size: fileStat.size, + date: fileStat.mtime, + } as IResultFile; + } + + isWithinBuildTime(date: Date): boolean { + const start = new Date(this.timestamps.tStart); + const end = new Date(this.timestamps.tEnd); + if (start && end && start.getTime() <= date.getTime() && date.getTime() <= end.getTime()) + return true; + return false; + } + + async genBuildResults() { + // FIXME. this method will NOT work if we enforce the compiler to target JS (not WebAssembly) with option -sWASM=0 + // as .wasm file will not be generated + + // detect executables output based on generated .wasm file, but ignore matched files from dependency directory + const wasmFiles = H.matchFilePath("**/*.wasm", this.proj.root, [C.dependencyDir]); + const targetResults: ITargetResult[] = []; + if (wasmFiles.length > 0) { + // sort by file size from large to small, usually the file with largest size should be the + // main target of the project + wasmFiles.sort((a, b) => { + const sizeA = fs.statSync(path.join(this.proj.root, a)).size; + const sizeB = fs.statSync(path.join(this.proj.root, b)).size; + if (sizeA < sizeB) return 1; + else if (sizeA > sizeB) return -1; + return 0; + }); + for (const f of wasmFiles) { + const targetName = path.basename(f, ".wasm"); + // possible files generated for one target: + // taregt.js, target (JS file w/o extension), target.wasm, target.data, target.worker.js, target.html + // target.{js,html}.symbols - generate if specify option --emit-symbol-map + // target.wasm.map - generate source map file if specify option -gsource-map + const exts = [ + ".js", + "", + ".wasm", + ".data", + ".worker.js", + ".html", + ".js.symbols", + ".html.symbols", + ".wasm.map", + ]; + const buildFiles: IResultFile[] = []; + for (const ext of exts) { + let filePath = path.join(this.proj.root, f.replace(".wasm", ext)); + if (fs.existsSync(filePath)) { + // keep filePath and do nothing + } else if ( + fs.existsSync( + path.join( + this.proj.constant.projectDist, + "bin", + path.basename(f.replace(".wasm", ext)) + ) + ) + ) { + // check file in webinizer_build/bin path + filePath = path.join( + this.proj.constant.projectDist, + "bin", + path.basename(f.replace(".wasm", ext)) + ); + } else { + // file doesn't exist + filePath = ""; + } + if (filePath) { + if (ext === "") { + // ensure target file is JS file rather than native binary file + const re = await H.runCommand(`file -b ${filePath}`, { silent: true }); + if (re.code === 0 && re.all.includes("ASCII text, with very long lines")) { + // check if there is .js file exists (maybe from last build) and compare the modified date + if (buildFiles.map((b) => b.name).includes(targetName + ".js")) { + const idx = buildFiles.map((b) => b.name).indexOf(targetName + ".js"); + const stat = this.genFileStats(filePath); + if (this.isWithinBuildTime(stat.date) && stat.date > buildFiles[idx].date) { + // replace the stats of .js file + fs.renameSync(`${filePath}`, `${filePath + ".js"}`); + buildFiles[idx] = { + path: stat.path + ".js", + name: stat.name + ".js", + type: stat.type, + size: stat.size, + date: stat.date, + }; + } + } else { + // add .js extension to file + fs.renameSync(`${filePath}`, `${filePath + ".js"}`); + const stat = this.genFileStats(filePath + ".js"); + if (this.isWithinBuildTime(stat.date)) buildFiles.push(stat); + } + } + } else { + const stat = this.genFileStats(filePath); + if (this.isWithinBuildTime(stat.date)) buildFiles.push(stat); + } + } + } + // for same target name in different location (i.e., from different build), + // only save the one with latest modified .wasm file + if (targetResults.map((t) => t.target).includes(targetName)) { + const idx = targetResults.map((t) => t.target).indexOf(targetName); + for (const f of targetResults[idx].result) { + if (f.name === targetName + ".wasm") { + for (const b of buildFiles) { + if (b.name === f.name) { + if (b.date > f.date) + targetResults[idx] = { + target: targetName, + type: "executable", + result: buildFiles, + }; + break; + } + } + break; + } + } + } else { + targetResults.push({ target: targetName, type: "executable", result: buildFiles }); + } + } + } + + // detect library files + if (this.proj.config.isLibrary) { + const libFiles: IResultFile[] = []; + // detect from the default install directory + if (fs.existsSync(this.proj.constant.projectDist)) { + // typical install path for library and header files + const libDirs = ["include", "lib"]; + libDirs.forEach((d) => { + const dir = path.join(this.proj.constant.projectDist, d); + if (fs.existsSync(dir)) { + // scan first level files only + const libTree = buildDirTree(dir); + if (libTree.children && Array.isArray(libTree.children)) { + libTree.children.forEach((child) => { + const stat = this.genFileStats(child.path); + if (this.isWithinBuildTime(stat.date)) libFiles.push(stat); + }); + } + } + }); + } + if (!libFiles.length) { + // if no library files are detected in the default install path, search for .a/.so files in the project root + const libExts = [".a", ".so"]; + for (const ext of libExts) { + // ignore matched files from dependency directory + H.matchFilePath(`**/*${ext}`, this.proj.root, [C.dependencyDir]).forEach((f) => { + const stat = this.genFileStats(path.join(this.proj.root, f)); + if (this.isWithinBuildTime(stat.date)) libFiles.push(stat); + }); + } + } + if (libFiles.length) { + targetResults.push({ + target: this.proj.config.name ? this.proj.config.name : path.basename(this.proj.root), + type: "library", + result: libFiles, + }); + } + } + + this.data = { files: targetResults }; + } + + clear() { + this.data = { files: [], timestamps: {} }; + } +} diff --git a/src/project_profiles.ts b/src/project_profiles.ts new file mode 100644 index 0000000..c9189fb --- /dev/null +++ b/src/project_profiles.ts @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as C from "./constants"; +import fs from "graceful-fs"; +import path from "path"; +import { buildDirTree } from "./dtree"; +import { Project } from "./project"; + +export interface IProjectProfile { + /** + * The project name. + */ + name?: string; + /** + * The project version. + */ + version?: string; + /** + * The absolute path to the config file. + */ + path?: string; + /** + * The project description. + */ + desc?: string; + /** + * The project icon. + */ + img?: string; + /** + * The project category. + */ + category?: string; + /** + * The project id. This is for demo project only. + */ + id?: number; + /** + * Whether the project is deleted or not. + */ + deleted?: boolean; +} + +export function getProfilesFromDetection(projectPoolDir?: string): IProjectProfile[] { + const dir = projectPoolDir || C.projectPool; + const profiles = [] as IProjectProfile[]; + const projectPool = buildDirTree(dir); + if (projectPool.children && projectPool.children.length) { + for (const p of projectPool.children) { + if (p.type === "directory" && fs.existsSync(path.join(p.path, ".webinizer", "config.json"))) { + const proj = new Project(p.path); + const profile = proj.config.getProjectProfile(); + // update project path to current one + if (profile && !profile.deleted) { + Object.assign(profile, { path: p.path }); + profiles.push(profile); + } + } + } + } + + // sort the demo projects based on id + if (profiles.length) { + profiles.sort((a, b) => { + if (a.id !== undefined && b.id !== undefined) { + if (a.id > b.id) return 1; + if (a.id < b.id) return -1; + } else if (a.id !== undefined && b.id === undefined) { + return -1; + } else if (a.id === undefined && b.id !== undefined) { + return 1; + } + return 0; + }); + } + + return profiles; +} diff --git a/src/recipe.ts b/src/recipe.ts new file mode 100644 index 0000000..cfb6971 --- /dev/null +++ b/src/recipe.ts @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Recipe + * @module + */ + +import * as H from "./helper"; +import { ALL_ADVISE_REQUESTS_FACTORIES, advisorFactoryFromType } from "./advisor"; +import { ALL_ACTION_FACTORIES } from "./action"; +import { checkJsonType } from "./json_factory"; +import errorCode from "./error_code"; +import { + IAction, + IAdvisor, + IAdviseRequest, + IJsonObject, + IToJson, + Project as IProject, +} from "webinizer"; + +const log = H.getLogger("recipe"); + +export class Recipe implements IToJson { + proj: IProject; + desc: string; // recipe description + advisor: IAdvisor; // which advisor generates this + requests: IAdviseRequest[]; // the requests that generate this + actions: IAction[]; + showNoAdvisor = false; + constructor( + proj: IProject, + desc: string, + advisor: IAdvisor, + requests: IAdviseRequest | IAdviseRequest[], + actions: IAction | IAction[], + showNoAdvisor?: boolean + ) { + this.proj = proj; + this.advisor = advisor; + if (!Array.isArray(requests)) { + requests = [requests]; + } + if (!Array.isArray(actions)) { + actions = [actions]; + } + this.requests = requests; + this.actions = actions; + this.desc = desc; + if (showNoAdvisor) this.showNoAdvisor = showNoAdvisor; + } + + async apply(): Promise { + log.info("... apply actions"); + for (const action of this.actions) { + await action.apply(); + } + return true; + } + + toJson(): IJsonObject { + return { + __type__: "Recipe", + proj: this.proj.root, + desc: this.desc, + advisor: this.advisor.type, + requests: this.requests.map((r) => r.toJson()), + actions: this.actions.map((a) => a.toJson()), + showNoAdvisor: this.showNoAdvisor, + }; + } +} + +export function recipeFromJson(proj: IProject, o: IJsonObject): Recipe | null { + checkJsonType("Recipe", o); + const advisor = advisorFactoryFromType(o.advisor as string)?.createAdvisor(); + if (!advisor) { + throw new H.WError( + `Unknown advisor type ${o.advisor} is used.`, + errorCode.WEBINIZER_ADVISOR_UNKNOWN + ); + } + return new Recipe( + proj, + o.desc as string, + advisor, + ALL_ADVISE_REQUESTS_FACTORIES.fromJsonArray(proj, o.requests as IJsonObject[]), + ALL_ACTION_FACTORIES.fromJsonArray(proj, o.actions as IJsonObject[]), + o.showNoAdvisor as boolean + ); +} + +export function recipeArrayFromJson(proj: IProject, arr: IJsonObject[]): Recipe[] | null { + const r: Recipe[] = []; + arr.map((json) => { + const o = recipeFromJson(proj, json); + if (o) r.push(o); + }); + return r; +} diff --git a/src/schemas/config_schema.ts b/src/schemas/config_schema.ts new file mode 100644 index 0000000..d857f25 --- /dev/null +++ b/src/schemas/config_schema.ts @@ -0,0 +1,179 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Define schemas for config.json + */ + +export const buildTargetConfigSchema = { + $id: "webinizer://schema.server/buildTargetConfig.schema", + title: "JSON schema for build config of each build target.", + type: "object", + properties: { + options: { + description: "The build options.", + type: "object", + properties: { + needMainLoop: { + type: "boolean", + }, + needPthread: { + type: "boolean", + }, + needCppException: { + type: "boolean", + }, + needSimd: { + type: "boolean", + }, + needModularize: { + type: "boolean", + }, + }, + additionalProperties: false, + }, + envs: { + description: "The environment vairables from this project for build.", + type: "object", + properties: { + cflags: { type: "string" }, + ldflags: { type: "string" }, + }, + additionalProperties: false, + }, + builders: { + description: "The build steps for build.", + type: "array", + items: { + type: "object", + properties: { + __type__: { type: "string" }, + id: { type: "number" }, + desc: { type: "string" }, + args: { type: "string" }, + rootBuildFilePath: { type: "string" }, + }, + required: ["__type__", "args", "rootBuildFilePath"], + additionalProperties: false, + }, + }, + exportedFuncs: { + description: "The exported native functions to call from JS.", + type: "string", + }, + exportedRuntimeMethods: { + description: "The exported runtime methods exposed in JS glue code.", + type: "string", + }, + preloadFiles: { + description: "The local files to be preloaded to the virtual FS and used by the project.", + type: "array", + items: { + type: "string", + }, + }, + disabledAdvisors: { + description: "The disabled advisors.", + type: "object", + patternProperties: { + "^[a-zA-Z0-9]*Advisor$": { type: "boolean" }, + }, + additionalProperties: false, + }, + pkgConfig: { + description: "The package configurations provided to projects that depend on this one.", + type: "object", + properties: { + prefix: { type: "string" }, + cflags: { type: "string" }, + ldflags: { type: "string" }, + }, + additionalProperties: false, + }, + }, +}; + +export const configSchema = { + $id: "webinizer://schema.server/config.schema", + title: "JSON schema for config.json file", + definitions: { + dependency: { + description: + "Dependencies are specified with a simple hash of package name to version range, a tarball or git URL, or a local directory or .tgz file path.", + type: "object", + additionalProperties: { + type: "string", + }, + }, + }, + properties: { + name: { + description: "The name of the project.", + type: "string", + maxLength: 214, + minLength: 1, + pattern: "^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?/)?[a-z0-9-~][a-z0-9-._~]*$", + }, + version: { + description: "The version of the project.", + type: "string", + pattern: "^[0-9]+.[0-9]+.[0-9]+(?:-[a-z]+(?:[_\\.-]*[a-z0-9]+)*)*$", + }, + desc: { + description: "The description of the project.", + type: "string", + }, + img: { + description: "The path to the project icon image.", + type: "string", + }, + category: { + description: "The category of the project.", + type: "string", + }, + isLibrary: { + description: "Whether the project is a library or not.", + type: "boolean", + }, + target: { + description: "The build target.", + type: "string", + pattern: "^(static|shared)$", + }, + dependencies: { + $ref: "#/definitions/dependency", + }, + buildTargets: { + description: + "Define different build targets and corresponding configurations for the project.", + type: "object", + properties: { + static: { $ref: "buildTargetConfig.schema#" }, + shared: { $ref: "buildTargetConfig.schema#" }, + }, + additionalProperties: false, + }, + overallEnvs: { + description: "The overall environment variables used for build.", + type: "object", + properties: { + cflags: { type: "string" }, + ldflags: { type: "string" }, + }, + additionalProperties: false, + }, + nativeLibrary: { + description: "The native library info that the project is ported from.", + type: "object", + properties: { + name: { type: "string" }, + version: { type: "string" }, + }, + additionalProperties: false, + }, + }, + type: "object", +}; diff --git a/src/schemas/metadata_schema.ts b/src/schemas/metadata_schema.ts new file mode 100644 index 0000000..e2a8b4f --- /dev/null +++ b/src/schemas/metadata_schema.ts @@ -0,0 +1,156 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Define schemas for package.json + */ + +export const buildTargetMetaSchema = { + $id: "webinizer://schema.server/buildTargetMeta.schema", + $ref: "#/definitions/standard", + definitions: { + standard: { + allOf: [ + { + $ref: "#/definitions/structure", + }, + { + required: ["envs", "buildSteps"], + }, + ], + }, + library: { + allOf: [ + { + $ref: "#/definitions/structure", + }, + { + required: ["envs", "buildSteps", "pkgConfig"], + }, + ], + }, + structure: { + type: "object", + properties: { + envs: { + type: "object", + properties: { + cflags: { type: "string" }, + ldflags: { type: "string" }, + }, + required: ["cflags", "ldflags"], + additionalProperties: false, + }, + buildSteps: { + type: "array", + items: { + type: "object", + properties: { + command: { type: "string", minLength: 1 }, + args: { type: "string" }, + cwd: { type: "string", minLength: 1 }, + }, + required: ["command", "args", "cwd"], + additionalProperties: false, + }, + }, + pkgConfig: { + type: "object", + properties: { + prefix: { type: "string", minLength: 1 }, + cflags: { type: "string", minLength: 1 }, + ldflags: { type: "string", minLength: 1 }, + }, + required: ["prefix", "cflags", "ldflags"], + additionalProperties: false, + }, + }, + }, + }, +}; + +export const webinizerFieldMetaSchema = { + $id: "webinizer://schema.server/webinizerFieldMeta.schema", + $ref: "#/definitions/standard", + definitions: { + standard: { + allOf: [ + { + $ref: "#/definitions/structure", + }, + { + required: ["buildTargets"], + }, + ], + }, + library: { + allOf: [ + { + $ref: "#/definitions/structure", + }, + { + required: ["buildTargets", "nativeLibrary"], + }, + ], + }, + structure: { + type: "object", + properties: { + buildTargets: { + type: "object", + properties: { + static: { $ref: "buildTargetMeta.schema#" }, + shared: { $ref: "buildTargetMeta.schema#" }, + }, + anyOf: [{ required: ["static"] }, { required: ["shared"] }], + additionalProperties: false, + }, + toolchain: { + type: "object", + properties: { + emscripten: { type: "string" }, + }, + }, + nativeLibrary: { + type: "object", + properties: { + name: { type: "string", minLength: 1 }, + version: { type: "string", minLength: 1 }, + }, + required: ["name", "version"], + }, + }, + }, + }, +}; + +export const metaSchema = { + $id: "webinizer://schema.server/meta.schema", + type: "object", + properties: { + name: { + type: "string", + maxLength: 214, + minLength: 1, + pattern: "^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?/)?[a-z0-9-~][a-z0-9-._~]*$", + }, + version: { + type: "string", + pattern: "^[0-9]+.[0-9]+.[0-9]+(?:-[a-z]+(?:[_\\.-]*[a-z0-9]+)*)*$", + }, + description: { type: "string" }, + dependencies: { + type: "object", + patternProperties: { + "^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?/)?[a-z0-9-~][a-z0-9-._~]*$": { type: "string" }, + }, + }, + webinizer: { + $ref: "webinizerFieldMeta.schema#", + }, + }, + required: ["name", "version", "webinizer"], +}; diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..cd4b4b9 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,554 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import chalk from "chalk"; +import express from "express"; +import cors from "cors"; +import helmet from "helmet"; +import { param, body, matchedData } from "express-validator"; +import * as H from "./helper"; +import { init } from "./init"; +import * as API from "./api"; +import { IJsonObject } from "webinizer"; + +const log = H.getLogger("server"); +const PORT = 16666; + +async function startServer() { + log.info("... initialization ..."); + await init(); + + log.info("... start the server ..."); + const app = express(); + app.use(express.json({ limit: "50mb" })); + app.use( + express.urlencoded({ + extended: true, + limit: "50mb", + }) + ); + app.use(cors()); + app.use( + helmet({ + strictTransportSecurity: { + maxAge: 31536000, + includeSubDomains: true, + }, + }) + ); + + app.get("/api/projects/profile", async (req, res) => { + log.info("--> get projects profile", req.body); + try { + const profiles = API.getProjectProfilesFromDetection(); + res.status(200).json({ profiles }); + } catch (e) { + log.error("get projects profile error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.post("/api/projects/zip-file", async (req, res) => { + log.info("--> upload projects profile"); + try { + await API.acceptProjectProfile(req, res); + } catch (e) { + log.error("upload projects profile error", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.post("/api/projects/github", body("repoPath").trim(), async (req, res) => { + log.info("--> clone project with git"); + try { + const data = matchedData(req); + const path = await API.addProjectByGitClone(data.repoPath, req.body.config); + res.status(200).json({ path: encodeURIComponent(path) }); + } catch (e) { + log.error("git clone projects error", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.post("/api/projects/registry", async (req, res) => { + log.info("--> fetch project from registry"); + try { + const path = await API.addProjectFromRegistry(req.body.spec, req.body.config); + res.status(200).json({ path: encodeURIComponent(path) }); + } catch (e) { + log.error("fetch project from registry error", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.delete( + "/api/projects/:root", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> delete project", req.params); + try { + const data = matchedData(req); + const profiles = API.deleteProject(data.root); + res.status(200).json({ profiles }); + } catch (e) { + log.error("delete project error", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/config", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get project config", req.params?.root); + try { + const data = matchedData(req); + const config = API.getProjectConfig(data.root); + res.status(200).json(config.toJson()); + } catch (e) { + log.error("get project config error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.put( + "/api/projects/:root/config", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("config"), + async (req, res) => { + log.info("--> update project config", req.params, req.body); + try { + const data = matchedData(req); + const config = await API.updatePartOfProjectConfig(data.root, data.config); + res.status(200).json(config.toJson()); + } catch (e) { + log.error("update project config error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.patch( + "/api/projects/:root/config", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> reset project config", req.params); + try { + const data = matchedData(req); + const config = await API.resetProjectConfig(data.root); + res.status(200).json(config.toJson()); + } catch (e) { + log.error("reset project config error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.put( + "/api/projects/:root/config/build-options", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("config"), + async (req, res) => { + log.info(" --> update project build config", req.body); + try { + const data = matchedData(req); + const config = await API.updateProjectBuildConfig(data.root, data.config); + res.status(200).json(config.toJson()); + } catch (e) { + log.error("update project build config error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.put( + "/api/projects/:root/config/overall-envs-deps", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info(" --> update project overallEnvs due to dependency update", req.params); + try { + const data = matchedData(req); + const config = await API.updateOverallEnvsFromDeps(data.root); + res.status(200).json(config.toJson()); + } catch (e) { + log.error( + "update project overallEnvs due to dependency update error\n", + H.normalizeErrorOutput(e as Error) + ); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.patch( + "/api/projects/:root/advisor", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("advisor").trim(), + async (req, res) => { + log.info("--> disable advisor", req.params, req.body); + try { + const data = matchedData(req); + const config = await API.disableAdvisorToUse(data.root, data.advisor); + res.status(200).json(config.toJson()); + } catch (e) { + log.error("disable advisor error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/builders/recommended-builders", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> recommend builders to use", req.params); + try { + const data = matchedData(req); + const builders = API.recommendBuildersToUse(data.root); + res.status(200).json({ builders: builders.map((b) => b.toJson()) }); + } catch (e) { + log.error("recommend builders error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/builders", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get all builders", req.params); + try { + const data = matchedData(req); + const builders = API.getAllBuilders(data.root); + res.status(200).json({ builders: builders.map((b) => b.toJson()) }); + } catch (e) { + log.error("get all builders error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.post( + "/api/projects/:root/construction", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("recipes"), + async (req, res) => { + log.info("--> build", req.params, req.body); + try { + const data = matchedData(req); + const recipes = await API.build( + data.root, + data.recipes ? (data.recipes as IJsonObject[]) : null + ); + res.status(200).json({ recipes: recipes.map((r) => r.toJson()) }); + } catch (e) { + log.error("build error\n", H.normalizeErrorOutput(e as Error)); + if ( + (e as Error).name !== "WEBINIZER_ROOT_EMPTY" && + (e as Error).name !== "WEBINIZER_ROOT_NOEXT" + ) { + // reset build status to idle_default if exception happens during build + await API.resetBuildStatus(String(decodeURIComponent(req.params?.root)).trim(), true); + } + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.post( + "/api/projects/:root/publication", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> publish project", req.params); + try { + const data = matchedData(req); + await API.publishProject(data.root); + res.status(200).json({ status: "success" }); + } catch (e) { + log.error("publish error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/registry-packages/:words", + param("words") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> search project", req.params); + try { + const data = matchedData(req); + const result = await API.searchProject(data.words); + res.status(200).json({ result }); + } catch (e) { + log.error("search error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/recipes", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get recipes from last build", req.params); + try { + const data = matchedData(req); + const recipes = API.getRecipes(data.root); + res.status(200).json({ recipes }); + } catch (e) { + log.error("get recipes error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/files/:name", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + param("name") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get file content"); + try { + const data = matchedData(req); + const content = await API.getFileContent(data.root, data.name); + res.status(200).json({ + name: data.name, + content: content, + }); + } catch (e) { + log.error("get file content error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.put( + "/api/projects/:root/files/:name", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + param("name") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("content").trim(), + async (req, res) => { + log.info("--> update file content"); + try { + const data = matchedData(req); + log.info(`data.content is`, data.content); + const updatedContent = await API.updateFileContent(data.root, data.name, data.content); + res.status(200).json({ + name: data.name, + content: updatedContent, + }); + } catch (e) { + log.error("update file content error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.post( + "/api/projects/:root/files", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("name") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + body("content").trim(), + async (req, res) => { + log.info("--> create new file", req.params, req.body); + try { + const data = matchedData(req); + await API.createNewFile(data.root, data.name, data.content); + res.status(200).json({ + name: encodeURIComponent(data.name), + content: data.content, + }); + } catch (e) { + log.error("create new file error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/directory-tree/:dir", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + param("dir") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get directory tree"); + try { + const data = matchedData(req); + const directoryTree = API.getDirTree(data.root, data.dir); + res.status(200).json(directoryTree); + } catch (e) { + log.error("get directory tree error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/construction/logs", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get build log"); + try { + const data = matchedData(req); + const content = API.getBuildLog(data.root); + res.status(200).json({ content }); + } catch (e) { + log.error("get build log error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/construction/results", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get build results"); + try { + const data = matchedData(req); + const result = API.getBuildResult(data.root); + res.status(200).json(result.toJson()); + } catch (e) { + log.error("get build result error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/construction/status", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get build status"); + try { + const data = matchedData(req); + const status = await API.getStatus(data.root); + res.status(200).json({ status }); + } catch (e) { + log.error("get build status error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/templates", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> get available template literals"); + try { + const data = matchedData(req); + const templates = API.getTemplates(data.root); + res.status(200).json({ templates }); + } catch (e) { + log.error("get template literals error\n", H.normalizeErrorOutput(e as Error)); + // #swagger.responses[400] + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get( + "/api/projects/:root/templates/:template/evaluation-literals", + param("root") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + param("template") + .trim() + .customSanitizer((v) => decodeURIComponent(v)), + async (req, res) => { + log.info("--> evaluate template literals"); + try { + const data = matchedData(req); + const val = API.evalTemplates(data.root, data.template); + res.status(200).json({ val }); + } catch (e) { + log.error("evaluate template literals error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + } + ); + + app.get("/api/settings", async (req, res) => { + log.info("--> get webinizer settings"); + try { + const settings = API.getSettings(); + res.status(200).json(settings); + } catch (e) { + log.error("get webinizer setting error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.post("/api/settings", body("settingParts"), async (req, res) => { + log.info("--> update webinizer settings"); + try { + const data = matchedData(req); + const settings = await API.updateSettings(data.settingParts); + res.status(200).json(settings); + } catch (e) { + log.error("update webinizer setting error\n", H.normalizeErrorOutput(e as Error)); + res.status(400).json(H.serializeError(e as Error)); + } + }); + + app.listen(PORT, () => log.warn(`Server started at port ${chalk.redBright(PORT)}...`)); +} + +startServer(); diff --git a/src/settings.ts b/src/settings.ts new file mode 100644 index 0000000..191adff --- /dev/null +++ b/src/settings.ts @@ -0,0 +1,134 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Webinizer Settings + * @module + */ +import path from "path"; +import { homedir } from "os"; +import DiskCache from "./disk_cache"; +import { IToJson, IJsonObject } from "webinizer"; +import { IExtensionSettings, IExtensionSettingsJson } from "./extension"; +import * as H from "./helper"; +import * as _ from "lodash"; +import errorCode from "./error_code"; +import * as npmSearch from "libnpmsearch"; + +const log = H.getLogger("settings"); + +export async function validateRegistryAddress(reg: string | undefined): Promise { + if (reg) { + // validate only when registry is set + if (!reg.startsWith("http://") && !reg.startsWith("https://")) { + throw new H.WError( + "Registry address must be full url, starting with 'http://' or 'https://'.", + errorCode.WEBINIZER_REG_ADDR_INVALID + ); + } + + // test registry connectivity by firing a search request to it. + try { + await npmSearch.default("test-registry-address", { registry: reg }); + } catch (e) { + throw new H.WError( + `Registry service provided by ${reg} is not available. Please set a correct registry address!`, + errorCode.WEBINIZER_REG_ADDR_INVALID + ); + } + } +} + +export interface ISettings extends IToJson { + readonly registry?: string; + registerFromExtensions(extName: string, extSettings: IExtensionSettings): void; + updateSettings(jsonParts: H.Dict): Promise; +} + +class SettingsImpl implements ISettings { + static __type__ = "WebinizerSettings"; + private static _instance: SettingsImpl; + private rawJson: DiskCache; + private extensionSettings = new Map(); + + private constructor() { + this.rawJson = new DiskCache(path.join(homedir(), ".webinizer", "settings.json")); + if (!this.rawJson.has("__type__")) this.rawJson.set("__type__", SettingsImpl.__type__); + // clean up extensions settings on each initialization to avoid manual removal of the extensions. + if (this.rawJson.has("extensions")) this.rawJson.set("extensions", {}); + } + + static getInstance(): SettingsImpl { + if (!SettingsImpl._instance) { + SettingsImpl._instance = new SettingsImpl(); + } + return SettingsImpl._instance; + } + + get registry(): string | undefined { + return this.rawJson.get("registry") as string; + } + + async updateRegistry(v: string | undefined) { + await validateRegistryAddress(v); + this.rawJson.set("registry", v); + } + + toJson(): IJsonObject { + return this.rawJson.data as IJsonObject; + } + + registerFromExtensions(extName: string, extSettings: IExtensionSettings) { + log.info(`... register settings for extension ${extName}`); + this.extensionSettings.set(extName, extSettings); + this.rawJson.set(`extensions.${extName}`, this.extSettingToJson(extSettings)); + } + + async updateSettings(jsonParts: H.Dict): Promise { + const jsonKeys = Object.keys(jsonParts); + if (jsonKeys.includes("registry")) { + await this.updateRegistry(jsonParts.registry as string); + } + if (jsonKeys.includes("extensions")) { + this.updateExtSettings(jsonParts.extensions as H.Dict); + } + } + + private extSettingToJson({ desc, status }: IExtensionSettings): IExtensionSettingsJson { + return { desc, status }; + } + + private updateExtSettings(extParts: H.Dict) { + const exts = Object.keys(extParts); + for (const ext of exts) { + if (this.extensionSettings.has(ext)) { + const extSettingsToUpdate: IExtensionSettingsJson = extParts[ext]; + log.info( + `... update settings for extension ${ext} as ${JSON.stringify( + extSettingsToUpdate, + undefined, + 2 + )}` + ); + // update the settings.json + this.rawJson.set(`extensions.${ext}`, extSettingsToUpdate); + // update the extensionSettings map and run callback to update the properties + // in the actual extension metadata. + const settings = this.extensionSettings.get(ext); + _.extend(settings, extSettingsToUpdate); + settings?.updateStatus(extSettingsToUpdate.status); + } else { + // unknown extension, throw + throw new H.WError( + `Unknown extension ${ext} for Webinizer.`, + errorCode.WEBINIZER_EXT_UNKNOWN + ); + } + } + } +} + +export const Settings: ISettings = SettingsImpl.getInstance(); diff --git a/src/status.ts b/src/status.ts new file mode 100644 index 0000000..fdc24d7 --- /dev/null +++ b/src/status.ts @@ -0,0 +1,160 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import * as H from "./helper"; +import { createHmac } from "crypto"; +import fs from "graceful-fs"; +import path from "path"; + +const log = H.getLogger("build_status"); + +/** + * Build status type + * ``` + * "building" - project is under building w/o recipes + * "building_with_recipes" - project is under building w/ recipes + * "idle_success" - project is idle after successful build + * "idle_fail" - project is idle after failure build + * "idle_default" - the initial idle status without any build + * ``` + */ +export type StatusType = + | "building" + | "building_with_recipes" + | "idle_success" + | "idle_fail" + | "idle_default"; + +interface IChangeHash { + configHash: string; // The hash code of the project config file + codeChangeHash: string; // The hash code of the source code change + untrackFileHash: string; // The hash code of the git untracked files + commitHash: string; // The hash code of the latest git commit +} + +/** + * Build Status + * @summary The singleton class that manages build status of all projects. + */ +class BuildStatus { + private _buildStatus: Map; + private _changeHash: Map; + private static _instance: BuildStatus; + + private constructor() { + this._buildStatus = new Map(); + this._changeHash = new Map(); + } + + static getInstance(): BuildStatus { + if (!BuildStatus._instance) { + BuildStatus._instance = new BuildStatus(); + } + return BuildStatus._instance; + } + + clearStatus() { + this._buildStatus.clear(); + this._changeHash.clear(); + } + + private _hashcode(src: string): string { + return createHmac("sha256", src).digest("hex"); + } + + private async _calculateChangeHash(root: string): Promise { + let configHash = ""; + let codeChangeHash = ""; + let untrackFileHash = ""; + let commitHash = ""; + + //Get config file hash + const configPath = path.join(root, ".webinizer", "config.json"); + if (fs.existsSync(configPath)) { + configHash = this._hashcode(fs.readFileSync(configPath, "utf-8")); + } + + //Get source code change hash + const ret1 = await H.runCommand("git diff", { cwd: root, silent: true }); + if (ret1.code === 0) { + codeChangeHash = this._hashcode(ret1.output); + } + + //Get the untrack file hash + const ret2 = await H.runCommand("git status", { cwd: root, silent: true }); + if (ret2.code === 0) { + const regMatchArr = ret2.output.match(/Untracked files:(.|\s)*\n\n/); + if (regMatchArr !== null) { + untrackFileHash = this._hashcode(regMatchArr[0]); + } + } + + //Get the latest commit hash + const ret3 = await H.runCommand("git rev-parse HEAD", { cwd: root, silent: true }); + if (ret3.code === 0) { + commitHash = ret3.output.trim(); + } + + return { + configHash: configHash, + codeChangeHash: codeChangeHash, + untrackFileHash: untrackFileHash, + commitHash: commitHash, + }; + } + + private _isChangeHashEqual( + value1: IChangeHash | undefined, + value2: IChangeHash | undefined + ): boolean { + if (value1 === undefined && value2 === undefined) return true; + if (value1 === undefined && value2 !== undefined) return false; + if (value1 !== undefined && value2 === undefined) return false; + if ( + (value1 as IChangeHash).commitHash === (value2 as IChangeHash).commitHash && + (value1 as IChangeHash).untrackFileHash === (value2 as IChangeHash).untrackFileHash && + (value1 as IChangeHash).configHash === (value2 as IChangeHash).configHash && + (value1 as IChangeHash).codeChangeHash === (value2 as IChangeHash).codeChangeHash + ) + return true; + + return false; + } + + async getBuildStatus(k: string): Promise { + log.info(`... get status of project ${k}`); + + //When the build status is "idle_success" or "idle_fail", compare + //the current change hash with the one store in the _changeHash Map. + //If they are not equal, change the build status of the project as + //"idle_default". + if (this._buildStatus.get(k) === "idle_success" || this._buildStatus.get(k) === "idle_fail") { + const currentChangeHash = await this._calculateChangeHash(k); + if (!this._isChangeHashEqual(this.getChangeHash(k), currentChangeHash)) { + this._buildStatus.set(k, "idle_default"); + } + } + + return this._buildStatus.get(k) || "idle_default"; + } + + setBuildStatus(k: string, v: StatusType) { + log.info(`... set status of project ${k} to ${v}`); + this._buildStatus.set(k, v); + } + + getChangeHash(k: string): IChangeHash | undefined { + log.info(`... get change hash of project ${k}`); + return this._changeHash.get(k); + } + + async setChangeHash(k: string) { + log.info(`... set change hash of project ${k}`); + this._changeHash.set(k, await this._calculateChangeHash(k)); + } +} + +export const buildStatus = BuildStatus.getInstance(); diff --git a/src/tsconfig.json b/src/tsconfig.json new file mode 100644 index 0000000..7f0aa1c --- /dev/null +++ b/src/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["./**/*", "../typings/webinizer.d.ts"], + "compilerOptions": { + "outDir": "../dist", + "rootDir": "." + }, + "watchOptions": { + "excludeFiles": ["./settings.json"] + } +} diff --git a/src/webinizer.ts b/src/webinizer.ts new file mode 100644 index 0000000..a82de16 --- /dev/null +++ b/src/webinizer.ts @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +/** + * Webinizer Extension APIs + */ + +export { loadAllModulesInDirctory, init } from "./init"; + +export { getLogger } from "./helper"; + +export { checkJsonType } from "./json_factory"; + +/** + * Project + */ +export { Project } from "./project"; + +/** + * Advisors + */ +export { AdviseManager, registerAdvisorFactory, advisorFactoryFromType } from "./advisor"; + +/** + * Advise Request + */ +export { ErrorAdviseRequest, PlainAdviseRequest } from "./advise_requests/common_requests"; + +/** + * Builders + */ +export { ALL_BUILDER_FACTORIES } from "./builder"; + +/** + * Actions + */ +export { ALL_ACTION_FACTORIES } from "./action"; +export { BuildStepChangeAction, BuildStepRegion } from "./actions/build_step_change"; +export { FileChangeAction, FileLocation, FileRegion } from "./actions/file_change"; +export { BuilderArgsChangeAction } from "./actions/args_change"; +export { ConfigEnvChangeAction } from "./actions/config_env_change"; +export { ConfigOptionChangeAction } from "./actions/config_option_change"; +export { ShowSuggestionAction, SuggestionExample } from "./actions/show_suggestion"; + +/** + * Recipe + */ +export { Recipe } from "./recipe"; diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..1fcf7e3 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,26 @@ +# Webinizer unit test + +## How to run Webinizer unit test + +1. First, make sure `emscripten` is installed. Then go to `emsdk` folder and run + `source ./emsdk_env.` +2. Second, modify the `src/constant.ts`. Change constant `WEBINIZER_HOME` to your real webinizer + home directory. +3. Then in terminal, go to `WEBINIZER_HOME` directory and enter `npm test` or `npm run test` to + trigger the test running. + +## How to run Webinizer unit test by category + +1. Currently, we have 3 categories for unit tests, they are `action`, `advisor` and `builder`. +2. If you only want to run test case of one category, for example `action`, you can run command + `npm test -- --grep "action"`. +3. If you want to run multiple categories, you can use command + `npm test -- --grep "(action|advisor|builder)"` to run 3 categories. + +## How to run a single Webinizer unit test case + +1. If you only want to run one test case, for example `MainLoopAdvisorTest`, you can run command + `npm test -- --grep "MainLoopAdvisorTest"`. +2. If you want to run multiple test cases, you can use command + `npm test -- --grep "(MainLoopAdvisorTest|InlineAsmAdvisorTest)"` to run `MainLoopAdvisorTest` + and `InlineAsmAdvisorTest`. diff --git a/tests/action_tests.ts b/tests/action_tests.ts new file mode 100644 index 0000000..cc68edb --- /dev/null +++ b/tests/action_tests.ts @@ -0,0 +1,137 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { expect } from "chai"; +import { ShowSuggestionAction, SuggestionExample } from "../src/actions/show_suggestion"; +import { GetUserInputAction } from "../src/actions/get_user_input"; +import { ShowDepRecipeAction } from "../src/actions/show_dep_recipe"; +import { ConfigEnvChangeAction } from "../src/actions/config_env_change"; +import { ConfigOptionChangeAction } from "../src/actions/config_option_change"; +import { BuilderArgsChangeAction } from "../src/actions/args_change"; +import { WEBINIZER_TEST_HOME } from "../src/constants"; +import { Project } from "../src/project"; +import { BuildStepChangeAction, BuildStepRegion } from "../src/actions/build_step_change"; +import { FileChangeAction, FileChangeManager, FileRegion } from "../src/actions/file_change"; +import fs from "graceful-fs"; +import { backupFolderSync, deleteFolder, renameFolder } from "../src/helper"; +import path from "path"; +import { IAction, IBuilder } from "webinizer"; + +const TEST_ACTION_ASSETS_DIR = `${WEBINIZER_TEST_HOME}/assets/actions`; + +describe("action", () => { + before(() => { + //Backup the "assets/actions" folder + backupFolderSync(TEST_ACTION_ASSETS_DIR, `${WEBINIZER_TEST_HOME}/assets/.actions`); + }); + + after(() => { + //Delete the older "assets/actions" and restore it from backup + deleteFolder(TEST_ACTION_ASSETS_DIR); + renameFolder(`${WEBINIZER_TEST_HOME}/assets/.actions`, TEST_ACTION_ASSETS_DIR); + }); + + it("BuilderArgsChangeActionTest", async () => { + const proj = new Project(path.join(TEST_ACTION_ASSETS_DIR, "BuilderArgsChangeAction")); + const action = new BuilderArgsChangeAction( + proj, + "", + [{ option: "-msimd128", value: null, type: "merge" }], + 0, + true + ); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + expect( + (proj.config.getBuildConfigForTarget("static").builders as IBuilder[])[0].args[0] + ).to.equal("-msimd128"); + }); + + it("BuildStepChangeActionTest", async () => { + const proj = new Project(path.join(TEST_ACTION_ASSETS_DIR, "BuildStepChangeAction")); + const region = new BuildStepRegion(1); + const newBuildSteps = [ + { + __type__: "CMakeBuilder", + id: 1, + desc: "cmake", + args: "", + rootBuildFilePath: "${projectRoot}", + }, + ]; + const action = new BuildStepChangeAction(proj, "", region, newBuildSteps); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + expect((proj.config.getBuildConfigForTarget("static").builders as IBuilder[])[1].type).to.equal( + "CMakeBuilder" + ); + }); + + it("ConfigEnvChangeActionTest", async () => { + const proj = new Project(path.join(TEST_ACTION_ASSETS_DIR, "ConfigEnvChangeAction")); + const action = new ConfigEnvChangeAction(proj, "", { + cflags: [{ option: "-msimd128", value: null, type: "delete" }], + }); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + expect(proj.config.getBuildConfigForTarget("static").getEnv("cflags")).to.not.include( + "-msimd128" + ); + expect(proj.config.getOverallEnv("cflags")).to.not.include("-msimd128"); + }); + + it("ConfigOptionChangeActionTest", async () => { + const proj = new Project(path.join(TEST_ACTION_ASSETS_DIR, "ConfigOptionChangeAction")); + const action = new ConfigOptionChangeAction(proj, "", { needMainLoop: false }); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + expect(proj.config.getBuildConfigForTarget("static").getOption("needMainLoop")).to.equal(false); + }); + + it("FileChangeActionTest", async () => { + const region = new FileRegion( + path.join(TEST_ACTION_ASSETS_DIR, "FileChangeAction", "testfile"), + 0, + 0 + ); + const newContent = "Test line 1\nTest line 2"; + const action = new FileChangeAction(new FileChangeManager(), "", region, newContent); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + expect(fs.readFileSync(region.file, "utf-8")).to.include(newContent); + }); + + it("GetUserInputActionTest", async () => { + const action = new GetUserInputAction(); + const result = await (action as IAction).apply(); + + expect(result).to.equal(false); + }); + + it("ShowDepRecipeActionTest", async () => { + const action = new ShowDepRecipeAction("Unit test for ShowDepRecipeAction", ["Dep1", "Dep2"]); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + }); + + it("ShowSuggestionActionTest", async () => { + const action = new ShowSuggestionAction( + "error", + "Unit test for ShowSuggestionAction", + new SuggestionExample("ShowSuggestionAction Test", "Test ShowSuggestionAction"), + null + ); + const result = await (action as IAction).apply(); + + expect(result).to.equal(true); + }); +}); diff --git a/tests/advisor_tests.ts b/tests/advisor_tests.ts new file mode 100644 index 0000000..b6a1037 --- /dev/null +++ b/tests/advisor_tests.ts @@ -0,0 +1,406 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { expect } from "chai"; +import { advisorFactoryFromType } from "../src/advisor"; +import { Project } from "../src/project"; +import { ErrorAdviseRequest, PlainAdviseRequest } from "../src/advise_requests/common_requests"; +import { Recipe } from "../src/recipe"; +import { WEBINIZER_TEST_HOME } from "../src/constants"; +import { FileLocation } from "../src/actions/file_change"; +import { backupFolderSync, deleteFolder, renameFolder } from "../src/helper"; +import path from "path"; +import { IAdviseRequest, IAdviseResult, IAdvisor } from "webinizer"; + +const TEST_ADVISOR_ASSETS_DIR = `${WEBINIZER_TEST_HOME}/assets/advisors`; + +async function advise(type: string, root: string, req: IAdviseRequest): Promise { + const advisor = advisorFactoryFromType(type)?.createAdvisor(); + const proj = new Project(root); + expect(advisor).to.not.be.null; + return (advisor as IAdvisor).advise(proj, req, []); +} + +describe("advisor", () => { + before(() => { + //Backup the "assets/advisors" folder + backupFolderSync(TEST_ADVISOR_ASSETS_DIR, `${WEBINIZER_TEST_HOME}/assets/.advisors`); + }); + + after(() => { + //Delete the older "assets/advisors" and restore it from backup + deleteFolder(TEST_ADVISOR_ASSETS_DIR); + renameFolder(`${WEBINIZER_TEST_HOME}/assets/.advisors`, TEST_ADVISOR_ASSETS_DIR); + }); + + it("BuildNativeToolAdvisorTest", async () => { + const errMsg = `./tinfo/MKcaptab.sh: 55: ./make_hash: Permission denied \n make[1]: Leaving directory '${WEBINIZER_TEST_HOME}/assets/advisors/BuildNativeToolAdvisor/'`; + const req = new ErrorAdviseRequest("make", errMsg, null, 0); + const actionDesc = `The build process needs to build some tools to generate some intermedium files. These tools should be \`native\` binaries. You need to adopt native compiler/tool-chain (such as \`gcc\`) to build these tools. Otherwise, emscripten-built tools cannot work and will interrupt the build process.`; + const advisorType = "BuildNativeToolAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); + + it("BuildPathValidateAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = "Below are the `invalid` paths we detected in project configuration:"; + const advisorType = "BuildPathValidateAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("BuildStepValidateAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = "Add a `make clean` step before `make` to ensure a clean build environment."; + const advisorType = "BuildStepValidateAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("BuildTargetSpecifyAdvisorTest", async () => { + const req = new ErrorAdviseRequest("cfg_args", "", null, 0); + const actionDesc = + "Please specify the build target as `32-bit` architecture while configuring the build, i.e., `x86_32`, `i686`, etc."; + const advisorType = "BuildTargetSpecifyAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); + + it("CCompilerAdvisorTest", async () => { + const req = new ErrorAdviseRequest( + "cfg_args", + "C compiler test failed. gcc is unable to create an executable file", + null, + 0 + ); + const actionDesc = `You're using \`gcc\` instead of \`emcc\`, which is a drop-in replacement for a standard compiler (like gcc or clang) to compile to WebAssembly. Please check if the build system has it hardcoded (i.e., cc_default="gcc"), or requires you to pass an option to specify \`emcc\` instead.`; + const advisorType = "CCompilerAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); + + it("CppExceptionAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = + "We detected C++ exception used in codebase, but it's disabled in project configuration for building phase, which will disable exception catching. We recommend to enable `C++ exception` option if you want this feature."; + const advisorType = "CppExceptionAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("DepBuildAdvisorTest", async () => { + const req = new PlainAdviseRequest("dep-build", "DepBuildAdvisor Test"); + const actionDesc = + "Recipes are generated for below dependent projects. Please go to the corresponding page of each dependent project for more details."; + const advisorType = "DepBuildAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("DepCheckAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = "We detect that your project depends on below requiured packages:"; + const advisorType = "DepCheckAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("ErrorsNotHandledAdvisorTest", async () => { + const req = new ErrorAdviseRequest("default", "", null, 0); + const actionDesc = + "This error is `not` handled by Webinizer, please try to resolve it manually"; + const advisorType = "ErrorsNotHandledAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("ExportNameAdvisorTest1", async () => { + const req = new ErrorAdviseRequest("cfg_args", "", null, 0); + const actionDesc = + "Enable `Pthreads + MODULARIZE` currently require you to set `-sEXPORT_NAME=Something` to `Something != Module`."; + const advisorType = "ExportNameAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("ExportNameAdvisorTest2", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = + "Enable `Pthreads + MODULARIZE` currently require you to set `-sEXPORT_NAME=Something` to `Something != Module`."; + const advisorType = "ExportNameAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("FpmathAdvisorTest", async () => { + const req = new ErrorAdviseRequest("cfg_args", "", null, 0); + const actionDesc = "Please remove all related '-mfpmath' compiler flags in your project."; + const advisorType = "FpmathAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); + + it("HeaderMissingAdvisorTest", async () => { + const errMsg = "fatal error: 'a.h' file not found\n"; + const req = new ErrorAdviseRequest("make", errMsg, null, 0); + const actionDesc = "A header file is missing. There might be several reasons:"; + const advisorType = "HeaderMissingAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("InitialMemoryAdvisorTest", async () => { + const errMsg = "initial memory too small"; + const req = new ErrorAdviseRequest("cfg_args", errMsg, null, 0); + const actionDesc = "The initial amount of memory to use is too `small` for your application"; + const advisorType = "InitialMemoryAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("InlineAsmAdvisorTest", async () => { + const errMsg = "in asm"; + const req = new ErrorAdviseRequest("cfg_args", errMsg, null, 0); + const actionDesc = + "Code with architecture-specific inline assembly (like an `asm()` containing x86 code) is not portable."; + const advisorType = "InlineAsmAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("MainLoopAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = `Main loop implementation using Emscripten API is not detected. If you are using infinite loop in your application (i.e., for rendering / animation, etc.), please follow the example below to use [\`emscripten_set_main_loop()\`](https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop) API to modify. Otherwise, please click \`IGNORE\` to dismiss this recipe.`; + const advisorType = "MainLoopAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("MakeTargetAdvisorTest", async () => { + const errMsg = `make[3]: Entering directory '${WEBINIZER_TEST_HOME}/assets/advisors/MakeTargetAdvisor/docs'\nmake[3]: *** [gnuplot.gih] Error 126\n`; + const req = new ErrorAdviseRequest("make", errMsg, null, 0); + const actionDesc = `Please specify a build directory or target to avoid such unnecessary builds`; + const advisorType = "MakeTargetAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("PThreadAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = + "We detected pthread usage in codebase, but it's disabled in project configuration for building phase. We recommend to enable `Pthread` option if you want this feature."; + const advisorType = "PThreadAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("RanlibAdvisorTest", async () => { + const req = new ErrorAdviseRequest( + "cfg_args", + "wasm-ld: error: archive has no index; run ranlib to add one", + null, + 0 + ); + const actionDesc = `You're using the system \`ranlib\` instead of \`emranlib\` (which calls llvm-ranlib).Please check if the build system has it hardcoded (i.e., ranlib_default="ranlib"), or requires you to pass an option to use \`emranlib\` instead.`; + const advisorType = "RanlibAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.equal(actionDesc); + }); + + it("SDLAdvisorTest1", async () => { + const errMsg = 'not providing "FindSDL2.cmake"'; + const req = new ErrorAdviseRequest( + "cmake", + errMsg, + new FileLocation("CMakeLists.txt", 0, 0), + 0 + ); + const actionDesc0 = `Remove \`find_package()\` statement for SDL2 from \`CMakeLists.txt\` at line`; + const actionDesc1 = `Add related compiler and linker flags to use Emscripten ported \`SDL2\` library.`; + const advisorType = "SDLAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc0); + expect((result.recipe as Recipe).actions[1].desc).to.include(actionDesc1); + }); + + it("SDLAdvisorTest2", async () => { + const errMsg = "Could NOT find SDL2_ttf"; + const req = new ErrorAdviseRequest( + "cmake", + errMsg, + new FileLocation("CMakeLists.txt", 0, 0), + 0 + ); + const actionDesc0 = `Remove \`find_package()\` statement for \`SDL2_ttf\` from \`CMakeLists.txt\` at line`; + const actionDesc1 = `Add related compiler and linker flags to use Emscripten ported \`SDL2_ttf\` library and preload \`font files\` if any.`; + const advisorType = "SDLAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc0); + expect((result.recipe as Recipe).actions[1].desc).to.include(actionDesc1); + }); + + it("SDLAdvisorTest3", async () => { + const errMsg = + "error: undefined symbol: SDL_acos (referenced by top-level compiled C/C++ code)"; + const req = new ErrorAdviseRequest( + "cmake", + errMsg, + new FileLocation("CMakeLists.txt", 0, 0), + 0 + ); + const actionDesc = `Add related compiler and linker flags to use Emscripten ported \`SDL2\` library.`; + const advisorType = "SDLAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("SDLAdvisorTest4", async () => { + const errMsg = + "error: undefined symbol: FT_Done_Face (referenced by top-level compiled C/C++ code)"; + const req = new ErrorAdviseRequest( + "cmake", + errMsg, + new FileLocation("CMakeLists.txt", 0, 0), + 0 + ); + const actionDesc = `Add related compiler and linker flags to use Emscripten ported \`SDL2_ttf\` library and preload \`font files\` if any.`; + const advisorType = "SDLAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("SimdAdvisorTest", async () => { + const req = new ErrorAdviseRequest("cfg_args", "", null, 0); + const actionDesc = + "If you want to port `SIMD` code targeting WebAssembly, we should enable the `SIMD support` option."; + const advisorType = "SimdAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("StripAdvisorTest", async () => { + const errMsg = "strip: file format not recognized\n"; + const req = new ErrorAdviseRequest("cfg_args", errMsg, null, 0); + const actionDesc = + "Native tools such as `GNU strip` are not aware of the WebAssembly object format and cannot create archive indexes. Please disable strip if possible."; + const advisorType = "StripAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("TemplateLiteralValidateAdvisorTest", async () => { + const req = new PlainAdviseRequest("pre-build", ""); + const actionDesc = + "Below are the `invalid` template literals we detected in project configuration:"; + const advisorType = "TemplateLiteralValidateAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("TestTargetErrorAdvisorTest", async () => { + const errMsg = `emmake: error:\nLeaving directory: ${WEBINIZER_TEST_HOME}/assets/advisors/TestTargetErrorAdvisor/test`; + const req = new ErrorAdviseRequest("make", errMsg, null, 0); + const actionDesc = + "Most test related targets are aimed to build&execute with native compiler/environment"; + const advisorType = "TestTargetErrorAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); + + it("X86AsmAdvisorTest", async () => { + const errMsg = "nasm/yasm not found or too old."; + const req = new ErrorAdviseRequest("cfg_args", errMsg, null, 0); + const actionDesc = `Emscripten does \`not\` support \`x86 SIMD assembly\`, all code should be written to use SIMD intrinsic functions or compiler vector extensions. Otherwise it would need to be replaced with portable C or C++.\nSometimes a codebase will have both portable code and optional architectures-specific assembly as an optimization, so you might find an option to disable it (i.e., \`--disable-x86asm\`, \`--disable-asm\`).`; + const advisorType = "X86AsmAdvisor"; + const projRoot = path.join(TEST_ADVISOR_ASSETS_DIR, advisorType); + const result = await advise(advisorType, projRoot, req); + + expect(result.handled).to.equal(true); + expect((result.recipe as Recipe).actions[0].desc).to.include(actionDesc); + }); +}); diff --git a/tests/assets/actions/BuildStepChangeAction/.webinizer/config.json b/tests/assets/actions/BuildStepChangeAction/.webinizer/config.json new file mode 100644 index 0000000..511f047 --- /dev/null +++ b/tests/assets/actions/BuildStepChangeAction/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "BuildStepChangeActionTest", + "desc": "Test config file for BuildStepChangeAction", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/actions/BuilderArgsChangeAction/.webinizer/config.json b/tests/assets/actions/BuilderArgsChangeAction/.webinizer/config.json new file mode 100644 index 0000000..073271d --- /dev/null +++ b/tests/assets/actions/BuilderArgsChangeAction/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "BuilderArgsChangeActionTest", + "desc": "Test config file for BuilderArgsChangeAction", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/actions/ConfigEnvChangeAction/.webinizer/config.json b/tests/assets/actions/ConfigEnvChangeAction/.webinizer/config.json new file mode 100644 index 0000000..954134c --- /dev/null +++ b/tests/assets/actions/ConfigEnvChangeAction/.webinizer/config.json @@ -0,0 +1,44 @@ +{ + "__type__": "ProjectConfig", + "name": "ConfigEnvChangeActionTest", + "desc": "Test config file for ConfigEnvChangeAction", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-sMODULARIZE=1" + }, + "exportedFuncs": "", + "exportedRuntimeMethods": "", + "preloadFiles": [] + } + }, + "target": "static", + "overallEnvsMap": { + "self": { + "cflags": "-msimd128", + "ldflags": "-sMODULARIZE=1" + } + }, + "overallEnvs": { + "cflags": "-msimd128", + "ldflags": "-sMODULARIZE=1" + } +} diff --git a/tests/assets/actions/ConfigOptionChangeAction/.webinizer/config.json b/tests/assets/actions/ConfigOptionChangeAction/.webinizer/config.json new file mode 100644 index 0000000..50267d4 --- /dev/null +++ b/tests/assets/actions/ConfigOptionChangeAction/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "ConfigOptionChangeActionTest", + "desc": "Test config file for ConfigOptionChangeAction", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/actions/FileChangeAction/testfile b/tests/assets/actions/FileChangeAction/testfile new file mode 100644 index 0000000..9f4f7e8 --- /dev/null +++ b/tests/assets/actions/FileChangeAction/testfile @@ -0,0 +1 @@ +Test file for FileChangeAction test! \ No newline at end of file diff --git a/tests/assets/advisors/BuildNativeToolAdvisor/.webinizer/config.json b/tests/assets/advisors/BuildNativeToolAdvisor/.webinizer/config.json new file mode 100644 index 0000000..67622a5 --- /dev/null +++ b/tests/assets/advisors/BuildNativeToolAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "BuildNativeToolAdvisorTest", + "desc": "Test config file for BuildNativeToolAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/BuildNativeToolAdvisor/make_hash b/tests/assets/advisors/BuildNativeToolAdvisor/make_hash new file mode 100644 index 0000000..76e9b33 --- /dev/null +++ b/tests/assets/advisors/BuildNativeToolAdvisor/make_hash @@ -0,0 +1 @@ +Test assets for BuildNativeToolAdvisor \ No newline at end of file diff --git a/tests/assets/advisors/BuildPathValidateAdvisor/.webinizer/config.json b/tests/assets/advisors/BuildPathValidateAdvisor/.webinizer/config.json new file mode 100644 index 0000000..a3b3d21 --- /dev/null +++ b/tests/assets/advisors/BuildPathValidateAdvisor/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "BuildPathValidateAdvisorTest", + "desc": "Test config file for BuildPathValidateAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}/test" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/BuildStepValidateAdvisor/.webinizer/config.json b/tests/assets/advisors/BuildStepValidateAdvisor/.webinizer/config.json new file mode 100644 index 0000000..9be2ded --- /dev/null +++ b/tests/assets/advisors/BuildStepValidateAdvisor/.webinizer/config.json @@ -0,0 +1,32 @@ +{ + "__type__": "ProjectConfig", + "name": "BuildStepValidateAdvisorTest", + "desc": "Test config file for BuildStepValidateAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + }, + + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ] + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/BuildTargetSpecifyAdvisor/.webinizer/config.json b/tests/assets/advisors/BuildTargetSpecifyAdvisor/.webinizer/config.json new file mode 100644 index 0000000..ed18ee5 --- /dev/null +++ b/tests/assets/advisors/BuildTargetSpecifyAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "BuildTargetSpecifyAdvisorTest", + "desc": "Test config file for BuildTargetSpecifyAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/BuildTargetSpecifyAdvisor/testlog b/tests/assets/advisors/BuildTargetSpecifyAdvisor/testlog new file mode 100644 index 0000000..68701db --- /dev/null +++ b/tests/assets/advisors/BuildTargetSpecifyAdvisor/testlog @@ -0,0 +1 @@ +must specify -mwasm64 to process wasm64 object files \ No newline at end of file diff --git a/tests/assets/advisors/CCompilerAdvisor/.webinizer/config.json b/tests/assets/advisors/CCompilerAdvisor/.webinizer/config.json new file mode 100644 index 0000000..858dcf2 --- /dev/null +++ b/tests/assets/advisors/CCompilerAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "CCompilerAdvisorTest", + "desc": "Test config file for CCompilerAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/CppExceptionAdvisor/.webinizer/config.json b/tests/assets/advisors/CppExceptionAdvisor/.webinizer/config.json new file mode 100644 index 0000000..8436969 --- /dev/null +++ b/tests/assets/advisors/CppExceptionAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "CppExceptionAdvisorTest", + "desc": "Test config file for CppExceptionAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/CppExceptionAdvisor/test.cpp b/tests/assets/advisors/CppExceptionAdvisor/test.cpp new file mode 100644 index 0000000..c15a7f8 --- /dev/null +++ b/tests/assets/advisors/CppExceptionAdvisor/test.cpp @@ -0,0 +1,19 @@ +#include + +int main() { + try { + int age; + std::cout << "Enter your age: "; + std::cin >> age; + + if (age < 0) { + throw "Age cannot be negative"; + } + + std::cout << "Your age is: " << age << std::endl; + } catch (const char* errorMessage) { + std::cerr << "Error: " << errorMessage << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/tests/assets/advisors/DepBuildAdvisor/.webinizer/config.json b/tests/assets/advisors/DepBuildAdvisor/.webinizer/config.json new file mode 100644 index 0000000..ac3173e --- /dev/null +++ b/tests/assets/advisors/DepBuildAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "DepBuildAdvisorTest", + "desc": "Test config file for DepBuildAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/DepCheckAdvisor/.webinizer/config.json b/tests/assets/advisors/DepCheckAdvisor/.webinizer/config.json new file mode 100644 index 0000000..14cd23b --- /dev/null +++ b/tests/assets/advisors/DepCheckAdvisor/.webinizer/config.json @@ -0,0 +1,32 @@ +{ + "__type__": "ProjectConfig", + "name": "DepCheckAdvisorTest", + "desc": "Test config file for DepCheckAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + }, + + "builders": [ + { + "__type__": "CMakeBuilder", + "id": 0, + "desc": "CMake", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ] + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/DepCheckAdvisor/CMakeLists.txt b/tests/assets/advisors/DepCheckAdvisor/CMakeLists.txt new file mode 100644 index 0000000..a02fa21 --- /dev/null +++ b/tests/assets/advisors/DepCheckAdvisor/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.12) +project(MyProject) + + +find_package(OpenGL REQUIRED) +find_package(GLEW REQUIRED) +find_package(GLUT REQUIRED) + + +add_executable(my_program src/main.c) + + +target_link_libraries(my_program PRIVATE ${OPENGL_LIBRARIES} GLEW::GLEW ${GLUT_LIBRARY}) diff --git a/tests/assets/advisors/ErrorsNotHandledAdvisor/.webinizer/config.json b/tests/assets/advisors/ErrorsNotHandledAdvisor/.webinizer/config.json new file mode 100644 index 0000000..8719a2f --- /dev/null +++ b/tests/assets/advisors/ErrorsNotHandledAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "ErrorsNotHandledAdvisorTest", + "desc": "Test config file for ErrorsNotHandledAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/ExportNameAdvisor/.webinizer/config.json b/tests/assets/advisors/ExportNameAdvisor/.webinizer/config.json new file mode 100644 index 0000000..f3d3adb --- /dev/null +++ b/tests/assets/advisors/ExportNameAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "ExportNameAdvisorTest", + "desc": "Test config file for ExportNameAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": true, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/ExportNameAdvisor/testlog b/tests/assets/advisors/ExportNameAdvisor/testlog new file mode 100644 index 0000000..db08814 --- /dev/null +++ b/tests/assets/advisors/ExportNameAdvisor/testlog @@ -0,0 +1 @@ +emcc: error: pthreads + MODULARIZE currently require you to set -sEXPORT_NAME=Something (see settings.js) to Something != Module, so that the .worker.js file can work \ No newline at end of file diff --git a/tests/assets/advisors/FpmathAdvisor/.webinizer/config.json b/tests/assets/advisors/FpmathAdvisor/.webinizer/config.json new file mode 100644 index 0000000..38f652e --- /dev/null +++ b/tests/assets/advisors/FpmathAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "FpmathAdvisorTest", + "desc": "Test config file for FpmathAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/FpmathAdvisor/testlog b/tests/assets/advisors/FpmathAdvisor/testlog new file mode 100644 index 0000000..3de52d9 --- /dev/null +++ b/tests/assets/advisors/FpmathAdvisor/testlog @@ -0,0 +1 @@ +unknown FP unit \ No newline at end of file diff --git a/tests/assets/advisors/HeaderMissingAdvisor/.webinizer/config.json b/tests/assets/advisors/HeaderMissingAdvisor/.webinizer/config.json new file mode 100644 index 0000000..10f9f27 --- /dev/null +++ b/tests/assets/advisors/HeaderMissingAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "HeaderMissingAdvisorTest", + "desc": "Test config file for HeaderMissingAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/InitialMemoryAdvisor/.webinizer/config.json b/tests/assets/advisors/InitialMemoryAdvisor/.webinizer/config.json new file mode 100644 index 0000000..bca618e --- /dev/null +++ b/tests/assets/advisors/InitialMemoryAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "InitialMemoryAdvisorTest", + "desc": "Test config file for InitialMemoryAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/InlineAsmAdvisor/.webinizer/config.json b/tests/assets/advisors/InlineAsmAdvisor/.webinizer/config.json new file mode 100644 index 0000000..ad3732a --- /dev/null +++ b/tests/assets/advisors/InlineAsmAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "InlineAsmAdvisorTest", + "desc": "Test config file for InlineAsmAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/MainLoopAdvisor/.webinizer/config.json b/tests/assets/advisors/MainLoopAdvisor/.webinizer/config.json new file mode 100644 index 0000000..24968dd --- /dev/null +++ b/tests/assets/advisors/MainLoopAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "MainLoopAdvisorTest", + "desc": "Test config file for MainLoopAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/MakeTargetAdvisor/.webinizer/config.json b/tests/assets/advisors/MakeTargetAdvisor/.webinizer/config.json new file mode 100644 index 0000000..fffc7d3 --- /dev/null +++ b/tests/assets/advisors/MakeTargetAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "MakeTargetAdvisorTest", + "desc": "Test config file for MakeTargetAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/MakeTargetAdvisor/testlog b/tests/assets/advisors/MakeTargetAdvisor/testlog new file mode 100644 index 0000000..77f9de5 --- /dev/null +++ b/tests/assets/advisors/MakeTargetAdvisor/testlog @@ -0,0 +1 @@ +Test file for MakeTargetAdvisor \ No newline at end of file diff --git a/tests/assets/advisors/PThreadAdvisor/.webinizer/config.json b/tests/assets/advisors/PThreadAdvisor/.webinizer/config.json new file mode 100644 index 0000000..1f242a0 --- /dev/null +++ b/tests/assets/advisors/PThreadAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "PThreadAdvisorTest", + "desc": "Test config file for PthreadAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/PThreadAdvisor/test.cpp b/tests/assets/advisors/PThreadAdvisor/test.cpp new file mode 100644 index 0000000..2049e8c --- /dev/null +++ b/tests/assets/advisors/PThreadAdvisor/test.cpp @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/tests/assets/advisors/RanlibAdvisor/.webinizer/config.json b/tests/assets/advisors/RanlibAdvisor/.webinizer/config.json new file mode 100644 index 0000000..d37c374 --- /dev/null +++ b/tests/assets/advisors/RanlibAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "RanlibAdvisorTest", + "desc": "Test config file for RanlibAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/SDLAdvisor/.webinizer/config.json b/tests/assets/advisors/SDLAdvisor/.webinizer/config.json new file mode 100644 index 0000000..ac3ed8c --- /dev/null +++ b/tests/assets/advisors/SDLAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "SDLAdvisorTest", + "desc": "Test config file for SDLAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/SDLAdvisor/CMakeLists.txt b/tests/assets/advisors/SDLAdvisor/CMakeLists.txt new file mode 100644 index 0000000..c8af5ea --- /dev/null +++ b/tests/assets/advisors/SDLAdvisor/CMakeLists.txt @@ -0,0 +1 @@ +find_package() \ No newline at end of file diff --git a/tests/assets/advisors/SimdAdvisor/.webinizer/config.json b/tests/assets/advisors/SimdAdvisor/.webinizer/config.json new file mode 100644 index 0000000..9d35642 --- /dev/null +++ b/tests/assets/advisors/SimdAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "SimdAdvisorTest", + "desc": "Test config file for SimdAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/SimdAdvisor/testlog b/tests/assets/advisors/SimdAdvisor/testlog new file mode 100644 index 0000000..8f133d9 --- /dev/null +++ b/tests/assets/advisors/SimdAdvisor/testlog @@ -0,0 +1 @@ +emcc: error: Passing any of -msse, -msse2, -msse3, -mssse3, -msse4.1, -msse4.2, -msse4, -mavx, -mfpu=neon flags also requires passing -msimd128! \ No newline at end of file diff --git a/tests/assets/advisors/StripAdvisor/.webinizer/config.json b/tests/assets/advisors/StripAdvisor/.webinizer/config.json new file mode 100644 index 0000000..7b47798 --- /dev/null +++ b/tests/assets/advisors/StripAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "StripAdvisorTest", + "desc": "Test config file for StripAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/TemplateLiteralValidateAdvisor/.webinizer/config.json b/tests/assets/advisors/TemplateLiteralValidateAdvisor/.webinizer/config.json new file mode 100644 index 0000000..6012806 --- /dev/null +++ b/tests/assets/advisors/TemplateLiteralValidateAdvisor/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "TemplateLiteralValidateAdvisorTest", + "desc": "Test config file for TemplateLiteralValidateAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoo}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/TestTargetErrorAdvisor/.webinizer/config.json b/tests/assets/advisors/TestTargetErrorAdvisor/.webinizer/config.json new file mode 100644 index 0000000..e0a5596 --- /dev/null +++ b/tests/assets/advisors/TestTargetErrorAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "TestTargetErrorAdvisorTest", + "desc": "Test config file for TestTargetErrorAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/advisors/X86AsmAdvisor/.webinizer/config.json b/tests/assets/advisors/X86AsmAdvisor/.webinizer/config.json new file mode 100644 index 0000000..1782d9f --- /dev/null +++ b/tests/assets/advisors/X86AsmAdvisor/.webinizer/config.json @@ -0,0 +1,22 @@ +{ + "__type__": "ProjectConfig", + "name": "X86AsmAdvisorTest", + "desc": "Test config file for X86AsmAdvisor", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": true, + "needPthread": false, + "needCppException": false, + "needSimd": true, + "needModularize": true + }, + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/builders/CMakeBuilder/.webinizer/config.json b/tests/assets/builders/CMakeBuilder/.webinizer/config.json new file mode 100644 index 0000000..69cd04b --- /dev/null +++ b/tests/assets/builders/CMakeBuilder/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "CMakeBuilderTest", + "desc": "Test config file for CMakeBuilder", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "builders": [ + { + "__type__": "CMakeBuilder", + "id": 0, + "desc": "CMake", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/builders/CMakeBuilder/CMakeLists.txt b/tests/assets/builders/CMakeBuilder/CMakeLists.txt new file mode 100644 index 0000000..ab12c71 --- /dev/null +++ b/tests/assets/builders/CMakeBuilder/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.0) +project(CMakeBuilderTest) +set(SOURCES main.c) +add_executable(main ${SOURCES}) diff --git a/tests/assets/builders/CMakeBuilder/main.c b/tests/assets/builders/CMakeBuilder/main.c new file mode 100644 index 0000000..f26b97c --- /dev/null +++ b/tests/assets/builders/CMakeBuilder/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello, World!\n"); + return 0; +} diff --git a/tests/assets/builders/ConfigureBuilder/.webinizer/config.json b/tests/assets/builders/ConfigureBuilder/.webinizer/config.json new file mode 100644 index 0000000..4b56353 --- /dev/null +++ b/tests/assets/builders/ConfigureBuilder/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "ConfigureBuilderTest", + "desc": "Test config file for ConfigureBuilder", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "builders": [ + { + "__type__": "ConfigureBuilder", + "id": 0, + "desc": "configure", + "args": "'--prefix=${projectRoot}/webinizer_build'", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/builders/ConfigureBuilder/configure b/tests/assets/builders/ConfigureBuilder/configure new file mode 100755 index 0000000..614fa07 --- /dev/null +++ b/tests/assets/builders/ConfigureBuilder/configure @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ ! -x "$(command -v $CC)" ]; then + echo "Error: cannot find $CC" + exit 1 +fi + +# Generate Makefile +echo "Generating Makefile ..." +echo "CC=$CC" > Makefile +echo "CFLAGS=-Wall -Werror" >> Makefile +echo "LDFLAGS=" >> Makefile +echo "TARGET=main" >> Makefile +echo "" >> Makefile +echo "all: \$(TARGET)" >> Makefile +echo "" >> Makefile +echo "\$(TARGET): main.c" >> Makefile +echo "\t\$(CC) \$(CFLAGS) \$(LDFLAGS) -o \$(TARGET) main.c" >> Makefile +echo "" >> Makefile +echo "clean:" >> Makefile +echo "\trm -f \$(TARGET)" >> Makefile + +exit 0 diff --git a/tests/assets/builders/ConfigureBuilder/main.c b/tests/assets/builders/ConfigureBuilder/main.c new file mode 100644 index 0000000..f26b97c --- /dev/null +++ b/tests/assets/builders/ConfigureBuilder/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello, World!\n"); + return 0; +} diff --git a/tests/assets/builders/EmccBuilder/.webinizer/config.json b/tests/assets/builders/EmccBuilder/.webinizer/config.json new file mode 100644 index 0000000..73de8a2 --- /dev/null +++ b/tests/assets/builders/EmccBuilder/.webinizer/config.json @@ -0,0 +1,42 @@ +{ + "__type__": "ProjectConfig", + "name": "EmccBuilderTest", + "version": "1.0.0", + "desc": "Project for Unit test of EmccBuilder", + "useDefaultConfig": false, + "buildTargets": { + "static": { + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + }, + "builders": [ + { + "__type__": "EmccBuilder", + "id": 0, + "desc": "emcc", + "args": "main.c -o main.js", + "rootBuildFilePath": "${projectRoot}" + } + ], + "options": { + "needSimd": true, + "needModularize": true + }, + "exportedFuncs": "", + "exportedRuntimeMethods": "", + "preloadFiles": [] + } + }, + "overallEnvsMap": { + "self": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + }, + "overallEnvs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + }, + "target": "static" +} diff --git a/tests/assets/builders/EmccBuilder/main.c b/tests/assets/builders/EmccBuilder/main.c new file mode 100644 index 0000000..f26b97c --- /dev/null +++ b/tests/assets/builders/EmccBuilder/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello, World!\n"); + return 0; +} diff --git a/tests/assets/builders/MakeBuilder/.webinizer/config.json b/tests/assets/builders/MakeBuilder/.webinizer/config.json new file mode 100644 index 0000000..fb9c128 --- /dev/null +++ b/tests/assets/builders/MakeBuilder/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "MakeBuilderTest", + "desc": "Test config file for MakeBuilder", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "builders": [ + { + "__type__": "MakeBuilder", + "id": 0, + "desc": "make", + "args": "", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/builders/MakeBuilder/Makefile b/tests/assets/builders/MakeBuilder/Makefile new file mode 100644 index 0000000..4b7a986 --- /dev/null +++ b/tests/assets/builders/MakeBuilder/Makefile @@ -0,0 +1,9 @@ +CFLAGS=-Wall -Werror + +all: main + +main: main.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + rm -f main diff --git a/tests/assets/builders/MakeBuilder/main.c b/tests/assets/builders/MakeBuilder/main.c new file mode 100644 index 0000000..f26b97c --- /dev/null +++ b/tests/assets/builders/MakeBuilder/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello, World!\n"); + return 0; +} diff --git a/tests/assets/builders/NativeBuilder/.webinizer/config.json b/tests/assets/builders/NativeBuilder/.webinizer/config.json new file mode 100644 index 0000000..74346d2 --- /dev/null +++ b/tests/assets/builders/NativeBuilder/.webinizer/config.json @@ -0,0 +1,31 @@ +{ + "__type__": "ProjectConfig", + "name": "NativeBuilderTest", + "desc": "Test config file for NativeBuilder", + "version": "1.0.0", + "buildTargets": { + "static": { + "options": { + "needMainLoop": false, + "needPthread": false, + "needCppException": false, + "needSimd": false, + "needModularize": false + }, + "builders": [ + { + "__type__": "NativeBuilder", + "id": 0, + "desc": "Run native commands without emscripten related configs", + "args": "gcc main.c -o main", + "rootBuildFilePath": "${projectRoot}" + } + ], + "envs": { + "cflags": "-msimd128", + "ldflags": "-msimd128 -sMODULARIZE=1" + } + } + }, + "target": "static" +} diff --git a/tests/assets/builders/NativeBuilder/main.c b/tests/assets/builders/NativeBuilder/main.c new file mode 100644 index 0000000..f26b97c --- /dev/null +++ b/tests/assets/builders/NativeBuilder/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello, World!\n"); + return 0; +} diff --git a/tests/builder_tests.ts b/tests/builder_tests.ts new file mode 100644 index 0000000..a22ceff --- /dev/null +++ b/tests/builder_tests.ts @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { expect } from "chai"; +import { AdviseManager } from "../src/advisor"; +import { Project } from "../src/project"; +import { WEBINIZER_TEST_HOME } from "../src/constants"; +import fs from "graceful-fs"; +import path from "path"; +import { backupFolderSync, deleteFolder, renameFolder } from "../src/helper"; +import { IBuilder } from "webinizer"; + +const TEST_BUILDER_ASSETS_DIR = `${WEBINIZER_TEST_HOME}/assets/builders`; + +async function build(root: string, target = "static"): Promise { + const proj = new Project(root); + const builder = proj.config.getBuildConfigForTarget(target).builders?.[0]; + expect(builder).to.not.be.null; + return (builder as IBuilder).build(new AdviseManager(proj)); +} + +describe("builder", () => { + before(() => { + //Backup the "assets/builders" folder + backupFolderSync(TEST_BUILDER_ASSETS_DIR, `${WEBINIZER_TEST_HOME}/assets/.builders`); + }); + + after(() => { + //Delete the older "assets/builders" and restore it from backup + deleteFolder(TEST_BUILDER_ASSETS_DIR); + renameFolder(`${WEBINIZER_TEST_HOME}/assets/.builders`, TEST_BUILDER_ASSETS_DIR); + }); + + it("CMakeBuilderTest", async () => { + const projRoot = path.join(TEST_BUILDER_ASSETS_DIR, "CMakeBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(true); + expect(fs.existsSync(path.join(projRoot, "Makefile"))).to.equal(true); + }); + + it("ConfigureBuilderTest", async () => { + const projRoot = path.join(TEST_BUILDER_ASSETS_DIR, "ConfigureBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(true); + expect(fs.existsSync(path.join(projRoot, "Makefile"))).to.equal(true); + }); + + it("EmccBuilderTest", async () => { + const projRoot = path.join(TEST_BUILDER_ASSETS_DIR, "EmccBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(true); + expect(fs.existsSync(path.join(projRoot, "main.js"))).to.equal(true); + }); + + it("MakeBuilderTest", async () => { + const projRoot = path.join(TEST_BUILDER_ASSETS_DIR, "MakeBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(true); + expect(fs.existsSync(path.join(projRoot, "main"))).to.equal(true); + }); + + it("NativeBuilderTest", async () => { + const projRoot = path.join(TEST_BUILDER_ASSETS_DIR, "NativeBuilder"); + const result = await build(projRoot); + + expect(result).to.equal(true); + expect(fs.existsSync(path.join(projRoot, "main"))).to.equal(true); + }); +}); diff --git a/tests/index.ts b/tests/index.ts new file mode 100644 index 0000000..c49d331 --- /dev/null +++ b/tests/index.ts @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +import { init } from "../src/init"; + +async function initTests() { + try { + await init(); + } catch (e) { + // stop running tests if initialization failed. + process.exit(); + } +} + +initTests(); + +import "./action_tests"; +import "./advisor_tests"; +import "./builder_tests"; diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 0000000..8716503 --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["./**/*", "../typings/webinizer.d.ts"], + "compilerOptions": { + "types": ["../node_modules/@types/mocha"], + "paths": { "webinizer": ["../typings/webinizer.d.ts"] } + } +} diff --git a/tsconfig.all.json b/tsconfig.all.json new file mode 100644 index 0000000..b8544d4 --- /dev/null +++ b/tsconfig.all.json @@ -0,0 +1,5 @@ +{ + "files": [], + "include": [], + "references": [{ "path": "./src" }, { "path": "./extensions/webinizer-extension-demo" }] +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..8d2561f --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,102 @@ +{ + "extends": "@tsconfig/node16/tsconfig.json", + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + "resolveJsonModule": true /* Enable importing .json files */, + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..e4302bc --- /dev/null +++ b/typedoc.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "Webinizer", + "entryPoints": ["typings/webinizer.d.ts"], + "cleanOutputDir": true, + "lightHighlightTheme": "github-light", + "darkHighlightTheme": "github-dark", + "excludeExternals": true, + "excludeInternal": true, + "excludePrivate": true, + "out": "docs", + "readme": "none", + "tsconfig": "tsconfig.base.json" +} diff --git a/typings/webinizer.d.ts b/typings/webinizer.d.ts new file mode 100644 index 0000000..18399a5 --- /dev/null +++ b/typings/webinizer.d.ts @@ -0,0 +1,1468 @@ +/*------------------------------------------------------------------------------------------------- + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * Licensed under the Apache License 2.0. See LICENSE in the project root for license information. + * SPDX-License-Identifier: Apache-2.0 + *-----------------------------------------------------------------------------------------------*/ + +declare module "webinizer" { + /** + * Initialize all the modules and extensions of webinizer. + */ + export function init(): Promise; + + /** + * Initialize modules from directories. + * @param dir The directory for modules to load from. + */ + export function loadAllModulesInDirctory(dir: string): Promise; + + /** + * Create the logger object. + * + * @example + * ```ts + * const log = getLogger("demo"); + * log.info("This is a test for logger."); + * ``` + * + * @param category The name of the logger. + * @returns The logging utilities. + */ + export function getLogger(category: string): ILogger; + + /** + * The logging utilities with different logging levels, a replacement for `console`. + */ + export interface ILogger { + debug(...args: any[]): void; + /** + * Log with the info level. Use this for basic logging. + */ + info(...args: any[]): void; + warn(...args: any[]): void; + error(...args: any[]): void; + } + + /** + * An object that manages project configurations and build process. + */ + export class Project { + /** + * The absolute path to the project root. + */ + readonly root: string; + /** + * The project config object. + */ + readonly config: IProjectConfig; + /** + * The project log object. + */ + readonly log: IProjectLog; + /** + * The file change manager object to manage all {@link FileChangeAction}. + */ + readonly fileChangeManager: IFileChangeManager; + /** + * The build step change manager object to manage all {@link BuildStepChangeAction}. + */ + readonly buildStepChangeManager: IBuildStepChangeManager; + /** + * Whether the project is a root project (`true`) or a dependency (`false`). + */ + readonly isRootProject: boolean; + /** + * The available template literals constants. + */ + readonly constant: Record; + + /** + * Create the `Project` object. + * @param root The absolute path to the project root. + * @param isRoot Whether the project is a root project (`true`) or a dependency (`false`). + */ + constructor(root: string, isRoot?: boolean); + + /** + * Get available template literals and corresponding value. + * @param withMarkdown Whether format the output string in markdown format or not. The default value is false. + * @returns The array of each template literal, in the format of `${projectRoot} = /path/tp/project/root`. + */ + getTemplateLiterals(withMarkdown?: boolean): string[]; + /** + * Get the actual value of a string containing template literals. + * @param s The string that contains template literal. + * @returns The string of actual value. + */ + evalTemplateLiterals(s: string): string; + /** + * Validate the template literals in a string. + * @param s The string that contains template literal. + * @returns The array of invalid template literal. + */ + validateTemplateLiterals(s: string): string[]; + + /** + * Backup the config files. + */ + backupConfigFiles(): void; + /** + * Restore the config files. + */ + restoreConfigsFromBackupFiles(): void; + /** + * Cleanup the backup config files. + */ + cleanBackupFiles(): void; + + /** + * Build the project. + * @param res Recipes to apply to the build. + * @returns Recipes generated in the build. + */ + build(res: Recipe[] | null): Promise; + } + + /** + * The available template literals used in project configuration. + * + * - `projectDist`: represents the project distribution directory. + * - `projectRoot`: represents the absolute project root path. + * - `projectPool`: represents the project pool directory. + */ + export type ProjectConstType = "projectDist" | "projectRoot" | "projectPool"; + + /** + * An object represents the project build log. + */ + export interface IProjectLog extends IToJson { + /** + * Get the log content. + * @returns The log content. + */ + getContent(): string; + /** + * Update the log content. + * @param content The content to be updated to the log file. + */ + update(content: string): void; + } + + /** + * An object represents the project configs. + */ + export interface IProjectConfig extends IToJson { + /** + * The absolute path to the config file. + */ + readonly path: string; + /** + * A reference to the {@link Project} object. + */ + readonly proj: Project; + /** + * The project name. + */ + readonly name: string | undefined; + /** + * The project version. + */ + readonly version: string | undefined; + /** + * The project description. + */ + readonly desc: string | undefined; + /** + * The build target for the project. Currently we only support value `static` and `shared`. + * + * - `static` build target means to build your project with static linking. All dependent libraries will be built into + * Wasm archive files (.a), and then linked to the main project to get a standalone Wasm module with no external + * dependencies. + * + * - `shared` build target means to build your project with dynamic linking. All dependent libraries will be built into + * Wasm binary files (.wasm/.so) as side modules (using flag -sSIDE_MODULE), whose exports will be dynamically imported + * into the context of main project's Wasm module (using flag -sMAIN_MODULE) by JavaScript glue code. + */ + readonly target: string | undefined; + /** + * Whether the project is a library or not (an application). + */ + readonly isLibrary: boolean | undefined; + /** + * The overall environment variables (compiler flags and linker flags) aggregated from this project and its dependent project(s). + */ + readonly overallEnvs: ProjectEnv | undefined; + /** + * The project raw dependencies, in the format of `{ foo: "^1.0.0" }`, represents the + * `dependencies` field in the config. + */ + readonly rawDependencies: { [k: string]: string } | undefined; + /** + * The packages that depends on this project, in the format of `{ foo: "^1.0.0" }`, + * which denotes the opposite of `dependencies` field in the config. + */ + readonly requiredBy: { [k: string]: string } | undefined; + + /** + * Get a specific overall environment variable. + * @param key The environment variable name. + * @returns The value of this environment variable. + */ + getOverallEnv(key: EnvType): string; + /** + * Get the `ProjectBuildConfig` object for a specific build target. + * @param target The build target. + * @returns The `ProjectBuildConfig` object for the target. + */ + getBuildConfigForTarget(target: string | undefined): IProjectBuildConfig; + + /** + * Update the overall environment variables value from the environment variables update of this project. + * @param envs The environment variables of this project. + */ + updateOverallEnvsFromSelf(envs: ProjectEnv | undefined): void; + /** + * Update the overall environment variables value from the dependent project(s). + */ + updateOverallEnvsFromDeps(): Promise; + /** + * Update the config file. + * @param jsonParts The to be updated config fields and corresponding values. + */ + updateRawJson(jsonParts: { [k: string]: unknown }): Promise; + + /** + * Conver the config file to the metadata file. + */ + convertToRegMetaFromConfig(): void; + /** + * Convert the config file to the metadata file for publish. More fields are converted in this method + * compared to those of {@link convertToRegMetaFromConfig}, such as `toolchain`, etc. + */ + convertToRegMetaForPublish(): Promise; + /** + * Convert the metadata file to the config file. + * @param diffContent The metadata fields to be converted. The default value is the whole metadata fields + * in `package.json`. + */ + convertFromRegMeta(diffContent?: { [k: string]: unknown }): Promise; + } + + /** + * The environment variables type. + * + * - `cflags` - the compiler flags. + * - `ldflags` - the linker flags. + */ + export type EnvType = "cflags" | "ldflags"; + /** + * An object represents the project environment variables. + */ + export type ProjectEnv = Record; + + /** + * The package configuration properties. + */ + export type PkgConfigType = "prefix" | EnvType; + /** + * An object represents the package configurations of a library project. Explainations for each property are: + * + * - `prefix`: The install prefix of the library. + * - `cflags`: The compiler flags that will be acquired by the main project depending on this library to + * search for the header files (i.e., the `-I` options). + * - `ldflags`: The linker flags that will be acquired by the main project depending on this library to + * search for and identify the library files (i.e., the `-L`, `-l` options). + */ + export type ProjectPkgConfig = { + [k in PkgConfigType]: string; + }; + /** + * An object represents the project build options. + */ + export interface IProjectBuildOptions { + /** + * Option for support on infinite main loop. + */ + needMainLoop?: boolean; + /** + * Option for support on pthread. + */ + needPthread?: boolean; + /** + * Options for support on C++ exception catching. + */ + needCppException?: boolean; + /** + * Option for support on Wasm SIMD. + */ + needSimd?: boolean; + /** + * Option for support on generating modularized JS glue code. + */ + needModularize?: boolean; + } + /** + * The build option type. + */ + export type BuildOptionType = keyof IProjectBuildOptions; + /** + * Options for updating build config. + */ + export interface IBuildConfigUpdateOptions { + /** + * The array of updated environment variable name. The default value is the + * array contains all environment variable names `["cflags", "ldflags"]`. + */ + updateEnvParts?: EnvType[]; + /** + * The array of updated options name. The default value is the array contains + * all options names. + */ + updateOptParts?: BuildOptionType[]; + /** + * Whether to refresh the build config based on the updated data or not after + * updating the build config JSON data. The default is true to refresh. + */ + refresh?: boolean; + } + + /** + * An object represents the build config for a build {@link IProjectConfig.target}. + */ + export interface IProjectBuildConfig { + /** + * The build target that this `ProjectBuildConfig` object corresponding to. + * Details for a build target is explained in {@link IProjectConfig.target}. + */ + readonly target: string; + /** + * The `builders` field JSON data in config file. + */ + readonly rawBuilders: IJsonObject[] | undefined; + /** + * The IBuilders object array created from the {@link rawBuilders}. + */ + readonly builders: IBuilder[] | null; + /** + * A string array of file paths to preload. + */ + readonly preloadFiles: string[] | undefined; + /** + * A string of exported native function names, separated by comma. + */ + readonly exportedFuncs: string | undefined; + /** + * A string of exported runtime methods in JavaScript glue code from Emscripten, + * separated by comma. + */ + readonly exportedRuntimeMethods: string | undefined; + /** + * The environment variables object defined for build, containing keys `cflags` + * and `ldflags`. + */ + readonly envs: ProjectEnv | undefined; + /** + * The options object defined for build. + */ + readonly options: IProjectBuildOptions | null; + /** + * The disabled advisors object. The key should be a advisor type {@link IAdvisor.type}, the value `true` + * means the corresponding advisor is disabled. + */ + disabledAdvisors: { [k: string]: boolean } | null; + /** + * The package configurations of the project. This field must be defined for a library project. + */ + pkgConfig: ProjectPkgConfig | undefined; + + /** + * Get a environment variable value. + * @param key The environment variable name. + * @returns The environment variable value. + */ + getEnv(key: EnvType): string; + /** + * Get an option value + * @param key The option name. + * @returns The option value. + */ + getOption(key: BuildOptionType): T | undefined; + /** + * Get a disabled advisor value. + * @param key The advisor name. + * @returns The status of the advisor. True means `disabled` and vise versa. + */ + getDisabledAdvisorFlag(key: string): T | undefined; + /** + * Set a disabled advisor value. + * @param key The advisor name. + * @param value The status of the advisor to set. True means `disabled` and vise versa. + */ + setDisabledAdvisorFlag(key: string, value: T): void; + /** + * Reset the status of all the advisors to `enable`. + */ + resetAdvisors(): void; + /** + * Get a package configuration value. + * @param key The package configuration name. + * @returns The package configuration value. + */ + getPkgConfigEnv(key: PkgConfigType): string; + /** + * Set a package configuration value. + * @param key The package configuration name. + * @param value The package configuration value to set. + */ + setPkgConfigEnv(key: PkgConfigType, value: string): void; + /** + * Update the build config data. This is the general entry for all config related updates. + * + * @param jsonParts The to be updated config data. + * @param options The update options. + */ + updateBuildConfig( + jsonParts: { [k: string]: unknown }, + options?: IBuildConfigUpdateOptions + ): void; + /** + * Reset the build config data to default. + */ + resetBuildConfig(): void; + + /** + * Convert the build config data to metadata format. + * + * @param convertParts The array of the fields to be converted. The default value + * is `["envs", "builders", "pkgConfig"]` which converts all the related fields. + */ + convertBuildTargetToMeta(convertParts?: ("envs" | "builders" | "pkgConfig")[]): void; + } + + /** + * An object represents a recipe from Webinizer. + */ + + export class Recipe { + /** + * Create a `Recipe` object. + * @param proj The Project instance. + * @param desc The description of the recipe. + * @param advisor The advisor that generates this recipe. + * @param requests The requests that generate this recipe. + * @param actions The actions provided by this recipe. + * @param showNoAdvisor Whether we can dismiss the recipe from the advisor. The default is false. + */ + constructor( + proj: Project, + desc: string, + advisor: IAdvisor, + requests: IAdviseRequest | IAdviseRequest[], + actions: IAction | IAction[], + showNoAdvisor?: boolean + ); + /** + * The Project instance. + */ + readonly proj: Project; + /** + * The description of the recipe. + */ + readonly desc: string; + /** + * The advisor that generates this recipe. + */ + readonly advisor: IAdvisor; + /** + * The requests that generate this recipe. + */ + readonly requests: IAdviseRequest[]; + /** + * The actions provided by this recipe. + */ + readonly actions: IAction[]; + /** + * Whether we can dismiss the recipe from the advisor. The default is false. + */ + readonly showNoAdvisor: boolean; + + /** + * Apply the recipe. + * @returns Whether the recipe is applied successfully or not. + */ + apply(): Promise; + /** + * Convert the recipe to a plain JSON object. + * @returns A plain JSON object represents this recipe. + */ + toJson(): IJsonObject; + } + + /** + * An object represents the JSON object of a Builder. + */ + export interface IBuilderJson extends IJsonObject { + /** + * The builder ID. This is the same as the index of the builder in a builder array and + * is a unique identifier for builders in a single Project. + */ + id: number; + /** + * The description of the builder. + */ + desc: string; + /** + * The overall arguments string of the builder. + */ + args: string; + /** + * The working directory of the builder. + */ + rootBuildFilePath: string; + } + + /** + * An object represents a Builder. A builder contains all the information needed to run a build command. + */ + export interface IBuilder extends IToJson { + /** + * The type of the Builder. This should be the same as the class name of the builder. + */ + type: string; + /** + * The description of the builder. + */ + desc: string; + /** + * The arguments array of the builder. Each element in the array is a argument. + */ + args: string[]; + /** + * The builder ID. This is the same as the index of the builder in a builder array and + * is a unique identifier for builders in a single Project. + */ + id: number; + /** + * Run the build command defined by the builder. + * @param adviseManager The advise manager object. + * @returns Whether the build command is ran successfully. + */ + build(adviseManager: AdviseManager): Promise; + /** + * Convert the builder object to a plain JSON object. + * @returns The JSON object of the builder. + */ + toJson(): IBuilderJson; + } + + /** + * An object represent a builder factory. + */ + export interface IBuilderFactory extends IFromJson { + /** + * The name of the builder factory. + */ + name: string; + /** + * The description of the builder factory. + */ + desc: string; + /** + * Detect a builder to use for the project. + * @param proj The project instance. + * @returns The detected builder or null (no builder detected). + */ + detect(proj: Project): IBuilder | null; + /** + * Create a default builder object from the factory. + * @param proj The project instance. + * @param args The arguments of the builder. + * @returns A builder object. + */ + createDefault(proj: Project, args?: string): IBuilder; + } + + /** + * An object contains all the builder factories. + */ + export const ALL_BUILDER_FACTORIES: IJsonFactories; + + /** + * Check if all the previous builders run native build commands. + * @param proj The project instance. + * @param idx The builder idx to check. + * @returns `true` if all the previous builders run native build commands. + */ + export function isPrevBuildersAllNative(proj: Project, idx: number): boolean; + /** + * Find the first builder with type `builder` in the poject's builders array. + * @param proj The Project instance. + * @param builder The builder type ({@link IBuilder.type}) string. + * @returns The builder index if found one. `-1` means not found. + */ + export function findFirstBuilder(proj: Project, builder: string): number; + + /** + * An object represents an advise request. + */ + export interface IAdviseRequest extends IToJson { + /** + * The tags array of the request. + */ + tags: string[]; + } + + /** + * An object represents the advise request. + */ + export interface IAdviseResult { + /** + * Whether this request is handled by advisors or not. + */ + handled: boolean; + /** + * The recipe generated by advisors. + */ + recipe?: Recipe; + /** + * Whether continues to ask other advisors to handle this request or not. + */ + needPropagation?: boolean; + /** + * Whether needs to replace the current request queue with it if defined. + */ + newRequestQueue?: IAdviseRequest[]; + } + + /** + * An object represents an advisor. + */ + export interface IAdvisor { + /** + * The type of the advisor. This should be the same as the advisor class name. + */ + type: string; + /** + * The description of the advisor. + */ + desc: string; + /** + * Advise on the request. + * @param proj The project instance. + * @param req The request that needs to be advised. + * @param requestList The queued request list. + * @returns The advise result object. + */ + advise( + proj: Project, + req: IAdviseRequest, + requestList: ReadonlyArray + ): Promise; + } + + /** + * An object represents advisor factory. + */ + export interface IAdvisorFactory { + /** + * Name of the advisor factory. + */ + name: string; + /** + * The description of the advisor factory. + */ + desc: string; + /** + * Create advisor object from the factory. + * @param args The arguments used to create the advisor object. + */ + createAdvisor(args?: string): IAdvisor; + } + + /** + * An object that manages advise requests and generate recipes. + */ + export class AdviseManager { + /** + * The project instance. + */ + readonly proj: Project; + /** + * Create an `AdviseManager` object. + * @param proj the project instance. + */ + constructor(proj: Project); + /** + * Queue the request to the request list. + * @param req the request to be queued. + */ + queueRequest(req: IAdviseRequest): void; + /** + * Advise on the request. + * @returns The recipes generated for all the requests. + */ + advise(): Promise; + } + + /** + * Register an advisor factory. + * @param type The type of the advisor. + * @param factory The factory object of the advisor. + */ + export function registerAdvisorFactory(type: string, factory: IAdvisorFactory): void; + /** + * Get an advisor factory object with `type`. + * @param type The type of the advisor. + * @returns The advisor factory object. `null` if the advisor factory is not available. + */ + export function advisorFactoryFromType(type: string): IAdvisorFactory | null; + + /** + * Represents an request generated from build errors. + */ + export class ErrorAdviseRequest implements IAdviseRequest { + /** + * Create an `ErrorAdviseRequest` object. + * @param tags The tags of the request. + * @param error The error messages. + * @param location The file location for the error. + * @param builderID The ID of the builder that generates the request. + */ + constructor( + tags: string | string[], + error: string, + location: FileLocation | null, + builderID: number + ); + + /** + * The tags array of the request. + */ + readonly tags: string[]; + /** + * The error messages. + */ + readonly error: string; + /** + * The file location for the error. + */ + readonly location: FileLocation | null; + /** + * The ID of the builder that generates the request. + */ + readonly builderID: number; + + /** + * Convert the request to a plain JSON object. + */ + toJson(): IJsonObject; + /** + * Create a request object from a plain JSON object. + * @param proj The project instance. + * @param o The plain JSON object. + * @returns A created `ErrorAdviseRequest` object. + */ + static fromJson(proj: Project, o: IJsonObject): ErrorAdviseRequest; + } + + /** + * Represents other requests with plain JSON data. + */ + export class PlainAdviseRequest implements IAdviseRequest { + /** + * Create a `PlainAdviseRequest` object. + * @param tags The tags of the request. + * @param plainData The request data. + */ + constructor(tags: string | string[], plainData: unknown); + + /** + * The tags array of the request. + */ + readonly tags: string[]; + /** + * The request data itself is a kind of JSON so easy to fromJson() and toJson(). + */ + readonly plainData: unknown; + + /** + * Convert the request to a plain JSON object. + */ + toJson(): IJsonObject; + /** + * Create a request object from a JSON object. + * @param proj The project instance. + * @param o The plain JSON object. + * @returns A created `PlainAdviseRequest` object. + */ + static fromJson(proj: Project, o: IJsonObject): PlainAdviseRequest; + } + + /** + * An object represents a plain JSON object. + */ + export interface IJsonObject { + /** + * This should be the class name that this JSON object is converted from. + */ + __type__: string; + [key: string]: unknown; + } + + /** + * Check the JSON object type. + * @param type The type to be checked. + * @param o The JSON object to be checked. + */ + export function checkJsonType(type: string, o: IJsonObject): void; + + /** + * An object that can be converted to a plain JSON object (`IJsonObject`). + */ + export interface IToJson { + toJson(): IJsonObject; + } + + /** + * An object that can be converted from a plain JSON object (`IJsonObject`). + */ + export interface IFromJson { + fromJson: FromJsonMethod; + } + + /** + * Represents the function type of a `fromJson` method. + * The JSON itself only contains static informaiton, but the object to restore + * may need to contain the current content where proj is the root of all such + * context (session) informaiton, so we need it for deserialization too. + */ + export type FromJsonMethod = (proj: Project, o: IJsonObject, index: number) => T | null; + + /** + * A template class for Json Factories. + */ + export interface IJsonFactories< + T, + X extends IFromJson | FromJsonMethod = IFromJson | FromJsonMethod + > { + /** + * The name of the factories. + */ + readonly name: string; + + /** + * Create the factory from JSON object. + * @param proj The project instance. + * @param o The plain JSON object. + * @param index The index of the JSON object in an array. + * @returns The factory converted from JSON object. + */ + fromJson(proj: Project, o: IJsonObject, index: number): T | null; + /** + * Register a factory or method to the Json factories map. + * @param type The type of the factory or `fromJson` method. + * @param method_or_factory The factory object of the `fromJson` method for the `type`. + */ + register(type: string, method_or_factory: X): void; + /** + * Get the factories map. + */ + factoriesMap(): Map; + /** + * Create an array of objects from an array of JSON objects. + * @param proj The project instance. + * @param arr The array of JSON objects. + */ + fromJsonArray(proj: Project, arr: IJsonObject[]): T[]; + } + + /** + * An object represents an action. + */ + export interface IAction extends IToJson { + /** + * The type of the action. This should be the same as the actual action class name. + */ + type: string; + /** + * The description of the action. + */ + desc: string; + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + } + + /** + * An object contains all the action factories, used to create an new action object. + */ + export const ALL_ACTION_FACTORIES: IJsonFactories; + + /** + * File change action - An action to change the file content + */ + export class FileChangeAction implements IAction { + /** + * Create a `FileChangeAction`. + * @param manager The `FileChangeManager` object. This should be passed from Project object as + * {@link Project.fileChangeManager} rather than `new` one here. + * @param desc The action decription. + * @param region The file region to change. + * @param content The file content to change. + */ + constructor( + manager: IFileChangeManager, + desc: string, + region: FileRegion, + content: string | null + ); + + /** + * The type of the action. This should be the same as class name `FileChangeAction`. + */ + readonly type: string; + /** + * The `FileChangeManager` object of this project. + */ + readonly manager: IFileChangeManager; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The file region to be changed. + */ + readonly region: FileRegion; + /** + * The new content to be updated to the file `region`. + */ + readonly newContent: string | null; + /** + * The number of lines of the `newContent`. + */ + readonly nLinesNewContent: number; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of this action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): FileChangeAction; + } + + /** + * An object represents the content location in a file. + */ + export class FileLocation { + /** + * Create a `FileLocation` object. + * @param file The absolute path to the file. + * @param line The line number in the file. + * @param col The column number in the file. + */ + constructor(file: string, line: number, col: number); + + /** + * The absolute path to the file. + */ + readonly file: string; + /** + * The line number in the file. + */ + readonly line: number; + /** + * The column number in the file. + */ + readonly col: number; + + /** + * Convert the `FileLocation` object to a plain JSON object. + * @returns The plain JSON object. + */ + toJson(): IJsonObject; + /** + * Convert the plain JSON object to a `FileLocation` object. + * @param o The JSON object. + * @returns The converted `FileLocation` object. + */ + static fromJson(o: IJsonObject): FileRegion; + /** + * Convert this `FileLocation` object to a `FileRegion` object. + * @returns A `FileRegion` object. + */ + toFileRegion(): FileRegion; + } + + /** + * An object represents a region of lines in the file. + */ + export class FileRegion { + /** + * Create a `FileRegion` object, representing the line region as [LineStart, LineEnd), 0 indexed + * @param file The absolute path to the file. + * @param lineStart The start of the region, 0 indexed. + * @param lineEnd The end of the region. The default value is "{@link lineStart} + 1". + */ + constructor(file: string, lineStart: number, lineEnd?: number); + + /** + * The absolute path to the file. + */ + readonly file: string; + /** + * The start line index of the region, 0 indexed. + */ + readonly lineStart: number; + /** + * The end of the region. + */ + readonly lineEnd: number; + + /** + * Convert the `FileRegion` object to a plain JSON object. + * @returns The plain JSON object. + */ + toJson(): IJsonObject; + /** + * Convert the plain JSON object to a `FileRegion` object. + * @param o The JSON object. + * @returns The converted `FileRegion` object. + */ + // isIntersected(r: FileRegion): boolean; + /** + * Lines change change if some region in this file is changed + * @param r The region changed + * @param nNewLines Number of lines after changed that region + * @returns number of lines to change + */ + linesToAdjust(r: FileRegion, nNewLines: number): number; + } + + /** + * The FileChangeManager object that coordinates all `FileChangeAction`s applied to one file to + * ensure all histories is all tracked and managed. + */ + export interface IFileChangeManager { + /** + * Apply the action. + * @param action The action to be applied. + * @returns Whether the action is applied successfully or not. + */ + apply(action: FileChangeAction): Promise; + } + + /** + * A string represents the args change action type. For a typical argment + * `--x=y` to be changed: + * + * - `replace` - replace the existed value of `--x` option to `y`. + * - `merge` - merge the existed value of `--x` option with `y`. If no `--x` + * option existed before, `replace` and `merge` have the same meaning. + * - `delete` - delete the first `--x` option. + * - `deleteAll` - delete all the `--x` options. + */ + export type ActionType = "replace" | "merge" | "delete" | "deleteAll"; + + /** + * An object represents an build argument (i.e., `--x=y`). + */ + export interface IArg { + /** + * The option name (`x`). + */ + option: string; + /** + * The value of the option (`y`). + */ + value: string | null; + /** + * The arg change action type. + */ + type: ActionType; + } + + /** + * Build step args change action - An action to change the build step arguments + */ + export class BuilderArgsChangeAction implements IAction { + /** + * Create a `BuilderArgsChangeAction` + * @param proj The Project instance. + * @param desc The action description. + * @param args The argument(s) to be updated. + * @param builderID The builder to be updated with the `args`. + * @param refresh Whether refresh the cache of the builders or not when applying this action. + */ + constructor(proj: Project, desc: string, args: IArg[], builderID: number, refresh: boolean); + + /** + * The type of the action. This should be the same as class name `BuilderArgsChangeAction`. + */ + readonly type: string; + /** + * The project instance. + */ + readonly proj: Project; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The argument(s) to be updated. + */ + readonly args: IArg[]; + /** + * The builder ID that is to be updated with `args`. + */ + readonly builderID: number; + /** + * Whether to refresh the cache of the builders or not. The default is true. + */ + readonly refresh: boolean; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of this action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): BuilderArgsChangeAction; + } + + /** + * An object represents a region/index range of build steps. + */ + export class BuildStepRegion { + /** + * Create a `BuildStepRegion` object represents the region [iStart, iEnd), + * 0 indexed. + * @param iStart Start of the region, 0 indexed. + * @param iEnd End of the region. The default value is the same as `iStart`. + */ + constructor(iStart: number, iEnd?: number); + + /** + * The start index of the region. + */ + readonly iStart: number; + /** + * The end index of the region. + */ + readonly iEnd: number; + + /** + * Serialize to JSON object. + * @returns An JSON object of this `BuildStepRegion`. + */ + toJson(): IJsonObject; + /** + * Create the `BuildStepRegion` from a JSON object. + * @param o The JSON object + * @returns The object deserialized from JSON data. + */ + static fromJson(o: IJsonObject): BuildStepRegion; + + // isIntersected(r: BuildStepRegion): boolean; + /** + * Calculate the index to be changed if some build steps are changed previously. + * @param r The region that is changed previously. + * @param nNewSteps Number of build steps to be changed. + * @returns Indexes shift for this change. + */ + indexesToAdjust(r: BuildStepRegion, nNewSteps: number): number; + } + + /** + * Build step change action - An action to change the build steps. + */ + export class BuildStepChangeAction implements IAction { + /** + * Create a `BuildStepChangeAction`. + * @param proj The project instance. + * @param desc The action description. + * @param region The build step region to be changed. + * @param newBuildSteps The new build steps to change. + */ + constructor( + proj: Project, + desc: string, + region: BuildStepRegion, + newBuildSteps: IBuilderJson[] | null + ); + + /** + * The type of the action. This should be the same as the class name `BuildStepChangeAction`. + */ + readonly type: string; + /** + * The project instance. + */ + readonly proj: Project; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The build step region to be changed. + */ + readonly region: BuildStepRegion; + /** + * The new buile step(s) to be changed to. + */ + readonly newBuildSteps: IBuilderJson[]; + /** + * The number of the new build step(s). + */ + readonly nNewSteps: number; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of thie action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): BuildStepChangeAction; + /** + * Calculate the actual build step region to apply the action. + * @param changes All the previously applied actions. + * @returns The actual build step region to apply the action. + */ + actualBuildStepRegion(changes: BuildStepChangeAction[]): BuildStepRegion | null; + } + + export interface IBuildStepChangeManager { + /** + * Apply the action. + * @param action The action to be applied. + * @returns Whether the action is applied successfully or not. + */ + apply(action: BuildStepChangeAction): Promise; + } + + /** + * Config env change action - An action to change the project compiler and linker flags. + */ + export class ConfigEnvChangeAction implements IAction { + /** + * Create a `ConfigEnvChangeAction`. + * @param proj the Project object + * @param desc action description + * @param partToUpdate the envs args to be updated + */ + constructor(proj: Project, desc: string, partToUpdate: Partial>); + + /** + * The type of the action. This should be the same as the class name `ConfigEnvChangeAction`. + */ + readonly type: string; + /** + * The project instance. + */ + readonly proj: Project; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The new args to be updated in project config envs. + */ + readonly partToUpdate: Partial>; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of thie action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): ConfigEnvChangeAction; + } + + /** + * Config option change action - An action to change the project config options + */ + export class ConfigOptionChangeAction implements IAction { + /** + * Create a `ConfigOptionChangeAction` + * @param proj The Project instance. + * @param desc The action description. + * @param partToUpdate The the config part to be updated. + */ + constructor(proj: Project, desc: string, partToUpdate: { [k in string]: boolean }); + + /** + * The type of the action. This should be the same as the class name `ConfigOptionChangeAction`. + */ + readonly type: string; + /** + * The project instance. + */ + readonly proj: Project; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The new options object to be updated in project config options. + */ + readonly partToUpdate: { [k in string]: boolean }; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of thie action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): ConfigOptionChangeAction; + } + + /** + * Show suggestion action - An action to show suggestion to user + */ + export class ShowSuggestionAction implements IAction { + /** + * Create a `ShowSuggestionAction`. + * @param init The initiator of the suggestion. + * @param desc The action description. + * @param suggestion The suggestion example. + * @param region The file region related with the suggestion. + */ + constructor( + init: SuggestionInitiator, + desc: string, + suggestion: SuggestionExample | null, + region: FileRegion | null + ); + + /** + * The type of the action. This should be the same as the class name `ShowSuggestionAction`. + */ + readonly type: string; + /** + * The initiator of this action, generated from `error` messages or project config `option` check. + */ + readonly initiator: SuggestionInitiator; + /** + * The description of the action. + */ + readonly desc: string; + /** + * The suggestion example. + */ + readonly suggestion: SuggestionExample | null; + /** + * The file region related with the suggestion. + */ + readonly region: FileRegion | null; + + /** + * Apply the action. + * @returns Whether the action is applied successfully or not. + */ + apply(): Promise; + /** + * Convert this action to JSON object. + * @returns The serialized JSON object of this action. + */ + toJson(): IJsonObject; + /** + * Create this action from a JSON object. + * @param proj The project instance. + * @param o The JSON data of thie action. + * @returns The action object deserialized from a JSON object. + */ + static fromJson(proj: Project, o: IJsonObject): ShowSuggestionAction; + } + + /** + * A string represents the suggestion initiator. + * - `option`: The suggestion is generated based on user config options. + * - `error`: The suggestion is generated based on error requests. + */ + export type SuggestionInitiator = "option" | "error"; + + /** + * An object represents a suggestion example. + */ + export class SuggestionExample { + /** + * Create a `SugggestionExample` object. + * @param before The original content to be modified. + * @param after The suggested examples to show the modification. + */ + constructor(before: string, after: string); + + /** + * The original content to be modified. + */ + readonly before: string; + /** + * The suggested examples to show the modification. + */ + readonly after: string; + + /** + * Convert a `SuggestionExample` object to a JSON object. + * @returns The serialized JSON object. + */ + toJson(): IJsonObject; + /** + * Create the `SuggestionExample` object from a JSON object. + * @param o The JSON object. + * @returns The `SuggestionExample` object deserialized from JSON data. + */ + static fromJson(o: IJsonObject): SuggestionExample; + } +}