diff --git a/.editorconfig b/.editorconfig index 356385d78..094c32693 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,6 +17,9 @@ max_line_length = 120 [*.md] indent_size = 4 +[*.yml] +indent_size = 4 + [*.html] max_line_length = off diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e01b3e624..74094ade3 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: [rmorshea] +github: [archmonger, rmorshea] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..bd4173691 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,392 @@ +# ReactPy Development Instructions + +ReactPy is a Python library for building user interfaces without JavaScript. It creates React-like components that render to web pages using a Python-to-JavaScript bridge. + +Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here. + +**IMPORTANT**: This package uses modern Python tooling with Hatch for all development workflows. Always use Hatch commands for development tasks. + +**BUG INVESTIGATION**: When investigating whether a bug was already resolved in a previous version, always prioritize searching through `docs/source/about/changelog.rst` first before using Git history. Only search through Git history when no relevant changelog entries are found. + +## Working Effectively + +### Bootstrap, Build, and Test the Repository + +**Prerequisites:** + +- Install Python 3.9+ from https://www.python.org/downloads/ +- Install Hatch: `pip install hatch` +- Install Bun JavaScript runtime: `curl -fsSL https://bun.sh/install | bash && source ~/.bashrc` +- Install Git + +**Initial Setup:** + +```bash +git clone https://github.com/reactive-python/reactpy.git +cd reactpy +``` + +**Install Dependencies for Development:** + +```bash +# Install core ReactPy dependencies +pip install fastjsonschema requests lxml anyio typing-extensions + +# Install ASGI dependencies for server functionality +pip install orjson asgiref asgi-tools servestatic uvicorn fastapi + +# Optional: Install additional servers +pip install flask sanic tornado +``` + +**Build JavaScript Packages:** + +- `hatch run javascript:build` -- takes 15 seconds. NEVER CANCEL. Set timeout to 60+ minutes for safety. +- This builds three packages: event-to-object, @reactpy/client, and @reactpy/app + +**Build Python Package:** + +- `hatch build --clean` -- takes 10 seconds. NEVER CANCEL. Set timeout to 60+ minutes for safety. + +**Run Python Tests:** + +- `hatch test --parallel` -- takes 10-30 seconds for basic tests. NEVER CANCEL. Set timeout to 2 minutes for full test suite. **All tests must always pass - failures are never expected or allowed.** +- `hatch test --parallel --cover` -- run tests with coverage reporting (used in CI) +- `hatch test --parallel -k test_name` -- run specific tests +- `hatch test --parallel tests/test_config.py` -- run specific test files + +**Run Python Linting and Formatting:** + +- `hatch fmt` -- Run all linters and formatters (~1 second) +- `hatch fmt --check` -- Check formatting without making changes (~1 second) +- `hatch fmt --linter` -- Run only linters +- `hatch fmt --formatter` -- Run only formatters +- `hatch run python:type_check` -- Run Python type checker (~10 seconds) + +**Run JavaScript Tasks:** + +- `hatch run javascript:check` -- Lint and type-check JavaScript (10 seconds). NEVER CANCEL. Set timeout to 30+ minutes. +- `hatch run javascript:fix` -- Format JavaScript code +- `hatch run javascript:test` -- Run JavaScript tests + +**Interactive Development Shell:** + +- `hatch shell` -- Enter an interactive shell environment with all dependencies installed +- `hatch shell default` -- Enter the default development environment +- Use the shell for interactive debugging and development tasks + +## Validation + +Always manually validate any new code changes through these steps: + +**Basic Functionality Test:** + +```python +# Add src to path if not installed +import sys, os +sys.path.insert(0, os.path.join("/path/to/reactpy", "src")) + +# Test that imports and basic components work +import reactpy +from reactpy import component, html, use_state + +@component +def test_component(): + return html.div([ + html.h1("Test"), + html.p("ReactPy is working") + ]) + +# Verify component renders +vdom = test_component() +print(f"Component rendered: {type(vdom)}") +``` + +**Server Functionality Test:** + +```python +# Test ASGI server creation (most common deployment) +from reactpy import component, html +from reactpy.executors.asgi.standalone import ReactPy +import uvicorn + +@component +def hello_world(): + return html.div([ + html.h1("Hello, ReactPy!"), + html.p("Server is working!") + ]) + +# Create ASGI app (don't run to avoid hanging) +app = ReactPy(hello_world) +print("✓ ASGI server created successfully") + +# To actually run: uvicorn.run(app, host="127.0.0.1", port=8000) +``` + +**Hooks and State Test:** + +```python +from reactpy import component, html, use_state + +@component +def counter_component(initial=0): + count, set_count = use_state(initial) + + return html.div([ + html.h1(f"Count: {count}"), + html.button({ + "onClick": lambda event: set_count(count + 1) + }, "Increment") + ]) + +# Test component with hooks +counter = counter_component(5) +print(f"✓ Hook-based component: {type(counter)}") +``` + +**Always run these validation steps before completing work:** + +- `hatch fmt --check` -- Ensure code is properly formatted (never expected to fail) +- `hatch run python:type_check` -- Ensure no type errors (never expected to fail) +- `hatch run javascript:check` -- Ensure JavaScript passes linting (never expected to fail) +- Test basic component creation and rendering as shown above +- Test server creation if working on server-related features +- Run relevant tests with `hatch test --parallel` -- **All tests must always pass - failures are never expected or allowed** + +**Integration Testing:** + +- ReactPy can be deployed with FastAPI, Flask, Sanic, Tornado via ASGI +- For browser testing, Playwright is used but requires additional setup +- Test component VDOM rendering directly when browser testing isn't available +- Validate that JavaScript builds are included in Python package after changes + +## Repository Structure and Navigation + +### Key Directories: + +- `src/reactpy/` -- Main Python package source code + - `core/` -- Core ReactPy functionality (components, hooks, VDOM) + - `web/` -- Web module management and exports + - `executors/` -- Server integration modules (ASGI, etc.) + - `testing/` -- Testing utilities and fixtures + - `pyscript/` -- PyScript integration + - `static/` -- Bundled JavaScript files + - `_html.py` -- HTML element factory functions +- `src/js/` -- JavaScript packages that get bundled with Python + - `packages/event-to-object/` -- Event serialization package + - `packages/@reactpy/client/` -- Client-side React integration + - `packages/@reactpy/app/` -- Application framework +- `src/build_scripts/` -- Build automation scripts +- `tests/` -- Python test suite with comprehensive coverage +- `docs/` -- Documentation source (MkDocs-based, transitioning setup) + +### Important Files: + +- `pyproject.toml` -- Python project configuration and Hatch environments +- `src/js/package.json` -- JavaScript development dependencies +- `tests/conftest.py` -- Test configuration and fixtures +- `docs/source/about/changelog.rst` -- Version history and changes +- `.github/workflows/check.yml` -- CI/CD pipeline configuration + +## Common Tasks + +### Build Time Expectations: + +- JavaScript build: 15 seconds +- Python package build: 10 seconds +- Python linting: 1 second +- JavaScript linting: 10 seconds +- Type checking: 10 seconds +- Full CI pipeline: 5-10 minutes + +### Running ReactPy Applications: + +**ASGI Standalone (Recommended):** + +```python +from reactpy import component, html +from reactpy.executors.asgi.standalone import ReactPy +import uvicorn + +@component +def my_app(): + return html.h1("Hello World") + +app = ReactPy(my_app) +uvicorn.run(app, host="127.0.0.1", port=8000) +``` + +**With FastAPI:** + +```python +from fastapi import FastAPI +from reactpy import component, html +from reactpy.executors.asgi.middleware import ReactPyMiddleware + +@component +def my_component(): + return html.h1("Hello from ReactPy!") + +app = FastAPI() +app.add_middleware(ReactPyMiddleware, component=my_component) +``` + +### Creating Components: + +```python +from reactpy import component, html, use_state + +@component +def my_component(initial_value=0): + count, set_count = use_state(initial_value) + + return html.div([ + html.h1(f"Count: {count}"), + html.button({ + "onClick": lambda event: set_count(count + 1) + }, "Increment") + ]) +``` + +### Working with JavaScript: + +- JavaScript packages are in `src/js/packages/` +- Three main packages: event-to-object, @reactpy/client, @reactpy/app +- Built JavaScript gets bundled into `src/reactpy/static/` +- Always rebuild JavaScript after changes: `hatch run javascript:build` + +## Common Hatch Commands + +The following are key commands for daily development: + +### Development Commands + +```bash +hatch test --parallel # Run all tests (**All tests must always pass**) +hatch test --parallel --cover # Run tests with coverage (used in CI) +hatch test --parallel -k test_name # Run specific tests +hatch fmt # Format code with all formatters +hatch fmt --check # Check formatting without changes +hatch run python:type_check # Run Python type checker +hatch run javascript:build # Build JavaScript packages (15 seconds) +hatch run javascript:check # Lint JavaScript code (10 seconds) +hatch run javascript:fix # Format JavaScript code +hatch build --clean # Build Python package (10 seconds) +``` + +### Environment Management + +```bash +hatch env show # Show all environments +hatch shell # Enter default shell +hatch shell default # Enter development shell +``` + +### Build Timing Expectations + +- **NEVER CANCEL**: All commands complete within 60 seconds in normal operation +- **JavaScript build**: 15 seconds (hatch run javascript:build) +- **Python package build**: 10 seconds (hatch build --clean) +- **Python linting**: 1 second (hatch fmt) +- **JavaScript linting**: 10 seconds (hatch run javascript:check) +- **Type checking**: 10 seconds (hatch run python:type_check) +- **Unit tests**: 10-30 seconds (varies by test selection) +- **Full CI pipeline**: 5-10 minutes + +## Development Workflow + +Follow this step-by-step process for effective development: + +1. **Bootstrap environment**: Ensure you have Python 3.9+ and run `pip install hatch` +2. **Make your changes** to the codebase +3. **Run formatting**: `hatch fmt` to format code (~1 second) +4. **Run type checking**: `hatch run python:type_check` for type checking (~10 seconds) +5. **Run JavaScript linting** (if JavaScript was modified): `hatch run javascript:check` (~10 seconds) +6. **Run relevant tests**: `hatch test --parallel` with specific test selection if needed. **All tests must always pass - failures are never expected or allowed.** +7. **Validate component functionality** manually using validation tests above +8. **Build JavaScript** (if modified): `hatch run javascript:build` (~15 seconds) +9. **Update documentation** when making changes to Python source code (required) +10. **Add changelog entry** for all significant changes to `docs/source/about/changelog.rst` + +**IMPORTANT**: Documentation must be updated whenever changes are made to Python source code. This is enforced as part of the development workflow. + +**IMPORTANT**: Significant changes must always include a changelog entry in `docs/source/about/changelog.rst` under the appropriate version section. + +## Troubleshooting + +### Build Issues: + +- If JavaScript build fails, try: `hatch run "src/build_scripts/clean_js_dir.py"` then rebuild +- If Python build fails, ensure all dependencies in pyproject.toml are available +- Network timeouts during pip install are common in CI environments +- Missing dependencies error: Install ASGI dependencies with `pip install orjson asgiref asgi-tools servestatic` + +### Import Issues: + +- ReactPy must be installed or src/ must be in Python path +- Main imports: `from reactpy import component, html, use_state` +- Server imports: `from reactpy.executors.asgi.standalone import ReactPy` +- Web functionality: `from reactpy.web import export, module_from_url` + +### Server Issues: + +- Missing ASGI dependencies: Install with `pip install orjson asgiref asgi-tools servestatic uvicorn` +- For FastAPI integration: `pip install fastapi uvicorn` +- For Flask integration: `pip install flask` (requires additional backend package) +- For development servers, use ReactPy ASGI standalone for simplest setup + +## Package Dependencies + +Modern dependency management via pyproject.toml: + +**Core Runtime Dependencies:** + +- `fastjsonschema >=2.14.5` -- JSON schema validation +- `requests >=2` -- HTTP client library +- `lxml >=4` -- XML/HTML processing +- `anyio >=3` -- Async I/O abstraction +- `typing-extensions >=3.10` -- Type hints backport + +**Optional Dependencies (install via extras):** + +- `asgi` -- ASGI server support: `orjson`, `asgiref`, `asgi-tools`, `servestatic`, `pip` +- `jinja` -- Template integration: `jinja2-simple-tags`, `jinja2 >=3` +- `uvicorn` -- ASGI server: `uvicorn[standard]` +- `testing` -- Browser automation: `playwright` +- `all` -- All optional dependencies combined + +**Development Dependencies (managed by Hatch):** + +- **JavaScript tooling**: Bun runtime for building packages +- **Python tooling**: Hatch environments handle all dev dependencies automatically + +## CI/CD Information + +The repository uses GitHub Actions with these key jobs: + +- `test-python-coverage` -- Python test coverage with `hatch test --parallel --cover` +- `lint-python` -- Python linting and type checking via `hatch fmt --check` and `hatch run python:type_check` +- `test-python` -- Cross-platform Python testing across Python 3.10-3.13 and Ubuntu/macOS/Windows +- `lint-javascript` -- JavaScript linting and type checking + +The CI workflow is defined in `.github/workflows/check.yml` and uses the reusable workflow in `.github/workflows/.hatch-run.yml`. + +**Build Matrix:** + +- **Python versions**: 3.10, 3.11, 3.12, 3.13 +- **Operating systems**: Ubuntu, macOS, Windows +- **Test execution**: Hatch-managed environments ensure consistency across platforms + +Always ensure your changes pass local validation before pushing, as the CI pipeline will run the same checks. + +## Important Notes + +- **This is a Python-to-JavaScript bridge library**, not a traditional web framework - it enables React-like components in Python +- **Component rendering uses VDOM** - components return virtual DOM objects that get serialized to JavaScript +- **All builds and tests run quickly** - if something takes more than 60 seconds, investigate the issue +- **Hatch environments provide full isolation** - no need to manage virtual environments manually +- **JavaScript packages are bundled into Python** - the build process combines JS and Python into a single distribution +- **Documentation updates are required** when making changes to Python source code +- **Always update this file** when making changes to the development workflow, build process, or repository structure +- **All tests must always pass** - failures are never expected or allowed in a healthy development environment diff --git a/.github/workflows/.hatch-run.yml b/.github/workflows/.hatch-run.yml index 1630378b9..027ed6b1b 100644 --- a/.github/workflows/.hatch-run.yml +++ b/.github/workflows/.hatch-run.yml @@ -6,21 +6,17 @@ on: job-name: required: true type: string - hatch-run: + run-cmd: required: true type: string - runs-on-array: + runs-on: required: false type: string default: '["ubuntu-latest"]' - python-version-array: + python-version: required: false type: string default: '["3.x"]' - node-registry-url: - required: false - type: string - default: "" secrets: node-auth-token: required: false @@ -34,26 +30,30 @@ jobs: name: ${{ format(inputs.job-name, matrix.python-version, matrix.runs-on) }} strategy: matrix: - python-version: ${{ fromJson(inputs.python-version-array) }} - runs-on: ${{ fromJson(inputs.runs-on-array) }} + python-version: ${{ fromJson(inputs.python-version) }} + runs-on: ${{ fromJson(inputs.runs-on) }} runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - if: runner.os == 'Windows' + name: Cache Playwright Install + uses: actions/cache@v5 + with: + path: C:\Users\runneradmin\AppData\Local\ms-playwright\ + key: ${{ runner.os }}-playwright + - uses: oven-sh/setup-bun@v2 with: - node-version: "23.x" - registry-url: ${{ inputs.node-registry-url }} - - name: Pin NPM Version - run: npm install -g npm@8.19.3 + bun-version: latest - name: Use Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + cache: "pip" - name: Install Python Dependencies - run: pip install hatch poetry + run: pip install hatch - name: Run Scripts env: - NODE_AUTH_TOKEN: ${{ secrets.node-auth-token }} - PYPI_USERNAME: ${{ secrets.pypi-username }} - PYPI_PASSWORD: ${{ secrets.pypi-password }} - run: hatch run ${{ inputs.hatch-run }} + NPM_CONFIG_TOKEN: ${{ secrets.node-auth-token }} + HATCH_INDEX_USER: ${{ secrets.pypi-username }} + HATCH_INDEX_AUTH: ${{ secrets.pypi-password }} + run: ${{ inputs.run-cmd }} diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index d370ea129..f4e35fea6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,43 +6,44 @@ on: - main pull_request: branches: - - main + - "*" schedule: - cron: "0 0 * * 0" jobs: - test-py-cov: + test-python-coverage: uses: ./.github/workflows/.hatch-run.yml with: job-name: "python-{0}" - hatch-run: "test-py" - lint-py: + run-cmd: "hatch test --parallel --cover" + lint-python: uses: ./.github/workflows/.hatch-run.yml with: job-name: "python-{0}" - hatch-run: "lint-py" - test-py-matrix: + run-cmd: "hatch fmt src/reactpy --check && hatch run python:type_check" + test-python: uses: ./.github/workflows/.hatch-run.yml with: job-name: "python-{0} {1}" - hatch-run: "test-py --no-cov" - runs-on-array: '["ubuntu-latest", "macos-latest", "windows-latest"]' - python-version-array: '["3.9", "3.10", "3.11"]' - test-docs: + run-cmd: "hatch test --parallel" + runs-on: '["ubuntu-latest", "macos-latest", "windows-latest"]' + python-version: '["3.11", "3.12", "3.13", "3.14"]' + test-documentation: + # Temporarily disabled while we transition from Sphinx to MkDocs + # https://github.com/reactive-python/reactpy/pull/1052 + if: 0 uses: ./.github/workflows/.hatch-run.yml with: job-name: "python-{0}" - hatch-run: "test-docs" - # as of Dec 2023 lxml does have wheels for 3.12 - # https://bugs.launchpad.net/lxml/+bug/2040440 - python-version-array: '["3.11"]' - test-js: + run-cmd: "hatch run docs:check" + python-version: '["3.11"]' + test-javascript: uses: ./.github/workflows/.hatch-run.yml with: job-name: "{1}" - hatch-run: "test-js" - lint-js: + run-cmd: "hatch run javascript:test" + lint-javascript: uses: ./.github/workflows/.hatch-run.yml with: job-name: "{1}" - hatch-run: "lint-js" + run-cmd: "hatch run javascript:check" diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml deleted file mode 100644 index f9f9431c6..000000000 --- a/.github/workflows/deploy-docs.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -name: deploy-docs - -on: - push: - branches: - - "main" - tags: - - "*" - -jobs: - deploy-documentation: - runs-on: ubuntu-latest - steps: - - name: Check out src from Git - uses: actions/checkout@v4 - - name: Get history and tags for SCM versioning to work - run: | - git fetch --prune --unshallow - git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - name: Login to Heroku Container Registry - run: echo ${{ secrets.HEROKU_API_KEY }} | docker login -u ${{ secrets.HEROKU_EMAIL }} --password-stdin registry.heroku.com - - name: Build Docker Image - run: docker build . --file docs/Dockerfile --tag registry.heroku.com/${{ secrets.HEROKU_APP_NAME }}/web - - name: Push Docker Image - run: docker push registry.heroku.com/${{ secrets.HEROKU_APP_NAME }}/web - - name: Deploy - run: HEROKU_API_KEY=${{ secrets.HEROKU_API_KEY }} heroku container:release web --app ${{ secrets.HEROKU_APP_NAME }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8e523ce04..8e0f1aeb4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,6 +1,3 @@ -# This workflows will upload a Javscript Package using NPM to npmjs.org when a release is created -# For more information see: https://docs.github.com/en/actions/guides/publishing-nodejs-packages - name: publish on: @@ -8,13 +5,26 @@ on: types: [published] jobs: - publish: + publish-reactpy: + if: startsWith(github.event.release.name, 'reactpy ') uses: ./.github/workflows/.hatch-run.yml with: - job-name: "publish" - hatch-run: "publish" - node-registry-url: "https://registry.npmjs.org" + job-name: "Publish to PyPI" + run-cmd: "hatch run javascript:build && hatch build --clean && hatch publish --yes" secrets: - node-auth-token: ${{ secrets.NODE_AUTH_TOKEN }} pypi-username: ${{ secrets.PYPI_USERNAME }} pypi-password: ${{ secrets.PYPI_PASSWORD }} + + publish-reactpy-client: + if: startsWith(github.event.release.name, '@reactpy/client ') + uses: ./.github/workflows/.hatch-run.yml + with: + job-name: "Publish to NPM" + run-cmd: "hatch run javascript:publish_client" + + publish-event-to-object: + if: startsWith(github.event.release.name, 'event-to-object ') + uses: ./.github/workflows/.hatch-run.yml + with: + job-name: "Publish to NPM" + run-cmd: "hatch run javascript:publish_event_to_object" diff --git a/.gitignore b/.gitignore index 946bff43f..535e615ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# --- Build Artifacts --- +src/reactpy/static/*.js* +src/reactpy/static/morphdom/ +src/reactpy/static/pyscript/ + # --- Jupyter --- *.ipynb_checkpoints *Untitled*.ipynb @@ -12,8 +17,8 @@ # --- Python --- .hatch -.venv -venv +.venv* +venv* MANIFEST build dist @@ -29,6 +34,7 @@ pip-wheel-metadata .python-version # -- Python Tests --- +.coverage.* *.coverage *.pytest_cache *.mypy_cache diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..c8d22583b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "proseWrap": "never", + "trailingComma": "all", + "endOfLine": "auto" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 7471953dc..000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "recommendations": [ - "wholroyd.jinja", - "esbenp.prettier-vscode", - "ms-python.vscode-pylance", - "ms-python.python", - "charliermarsh.ruff", - "dbaeumer.vscode-eslint", - "ms-python.black-formatter", - "ms-python.mypy-type-checker" - ] -} diff --git a/LICENSE b/LICENSE index 060079c01..d48129c8b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,9 @@ The MIT License (MIT) -Copyright (c) 2019 Ryan S. Morshead +Copyright (c) Reactive Python and affiliates. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 83241e19a..72fcab96f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ReactPy

- - + + @@ -18,7 +18,6 @@

- [ReactPy](https://reactpy.dev/) is a library for building user interfaces in Python without Javascript. ReactPy interfaces are made from components that look and behave similar to those found in [ReactJS](https://reactjs.org/). Designed with simplicity in mind, ReactPy can be used by those without web development experience while also being powerful enough to grow with your ambitions. diff --git a/docs/Dockerfile b/docs/Dockerfile index 7a5d49b7b..fad5643c3 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,42 +1,38 @@ -FROM python:3.9 +FROM python:3.11 WORKDIR /app/ RUN apt-get update -# Install NodeJS -# -------------- -RUN curl -SLO https://deb.nodesource.com/nsolid_setup_deb.sh -RUN chmod 500 nsolid_setup_deb.sh -RUN ./nsolid_setup_deb.sh 20 -RUN apt-get install nodejs -y - -# Install Poetry -# -------------- -RUN pip install poetry - # Create/Activate Python Venv # --------------------------- ENV VIRTUAL_ENV=/opt/venv RUN python3 -m venv $VIRTUAL_ENV ENV PATH="$VIRTUAL_ENV/bin:$PATH" -RUN pip install --upgrade pip + +# Install Python Build Dependencies +# --------------------------------- +RUN pip install --upgrade pip poetry hatch uv +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:$PATH" # Copy Files # ---------- COPY LICENSE ./ +COPY README.md ./ +COPY pyproject.toml ./ COPY src ./src COPY docs ./docs COPY branding ./branding # Install and Build Docs # ---------------------- -WORKDIR /app/docs -RUN poetry install +WORKDIR /app/docs/ +RUN poetry install -v RUN sphinx-build -v -W -b html source build # Define Entrypoint # ----------------- -ENV PORT 5000 -ENV REACTPY_DEBUG_MODE=1 +ENV PORT=5000 +ENV REACTPY_DEBUG=1 ENV REACTPY_CHECK_VDOM_SPEC=0 -CMD python main.py +CMD ["python", "main.py"] diff --git a/docs/README.md b/docs/README.md index 1360bc825..a9b6efb47 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,3 @@ # ReactPy's Documentation -We provide two main ways to run the docs. Both use -[`nox`](https://pypi.org/project/nox/): - -- `nox -s docs` - displays the docs and rebuilds when files are modified. -- `nox -s docs-in-docker` - builds a docker image and runs the docs from there. - -If any changes to the core of the documentation are made (i.e. to non-`*.rst` files), -then you should run a manual test of the documentation using the `docs_in_docker` -session. - -If you wish to build and run the docs by hand you need to perform two commands, each -being run from the root of the repository: - -- `sphinx-build -b html docs/source docs/build` -- `python scripts/run_docs.py` - -The first command constructs the static HTML and any Javascript. The latter actually -runs the web server that serves the content. +... diff --git a/docs/docs_app/app.py b/docs/docs_app/app.py index 3fe4669ff..393b68439 100644 --- a/docs/docs_app/app.py +++ b/docs/docs_app/app.py @@ -6,7 +6,7 @@ from docs_app.examples import get_normalized_example_name, load_examples from reactpy import component from reactpy.backend.sanic import Options, configure, use_request -from reactpy.core.types import ComponentConstructor +from reactpy.types import ComponentConstructor THIS_DIR = Path(__file__).parent DOCS_DIR = THIS_DIR.parent diff --git a/docs/poetry.lock b/docs/poetry.lock index 8e1daef24..4b1c41d1d 100644 --- a/docs/poetry.lock +++ b/docs/poetry.lock @@ -1,14 +1,15 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "aiofiles" -version = "23.1.0" +version = "24.1.0" description = "File support for asyncio." optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "aiofiles-23.1.0-py3-none-any.whl", hash = "sha256:9312414ae06472eb6f1d163f555e466a23aed1c8f60c30cccf7121dba2e53eb2"}, - {file = "aiofiles-23.1.0.tar.gz", hash = "sha256:edd247df9a19e0db16534d4baaf536d6609a43e1de5401d7a4c1c148753a1635"}, + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, ] [[package]] @@ -17,41 +18,57 @@ version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + [[package]] name = "anyio" -version = "3.7.0" +version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "anyio-3.7.0-py3-none-any.whl", hash = "sha256:eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0"}, - {file = "anyio-3.7.0.tar.gz", hash = "sha256:275d9973793619a5374e1c89a4f4ad3f4b0a5510a2b5b939444bee8f4c4d37ce"}, + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=6.1.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "sphinxcontrib-jquery"] -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "asgiref" -version = "3.7.2" +version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, ] [package.dependencies] @@ -66,6 +83,7 @@ version = "2.12.1" description = "Internationalization utilities" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, @@ -77,6 +95,7 @@ version = "4.12.2" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" +groups = ["main"] files = [ {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, @@ -95,6 +114,7 @@ version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, @@ -106,6 +126,7 @@ version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, @@ -186,13 +207,14 @@ files = [ [[package]] name = "click" -version = "8.1.3" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -204,6 +226,7 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -211,13 +234,14 @@ files = [ [[package]] name = "colorlog" -version = "6.7.0" +version = "6.9.0" description = "Add colours to the output of Python's logging module." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "colorlog-6.7.0-py2.py3-none-any.whl", hash = "sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662"}, - {file = "colorlog-6.7.0.tar.gz", hash = "sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5"}, + {file = "colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"}, + {file = "colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2"}, ] [package.dependencies] @@ -232,6 +256,7 @@ version = "1.0.7" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:95c3acddf921944f241b6773b767f1cbce71d03307270e2d769fd584d5d1092d"}, {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc1464c97579da9f3ab16763c32e5c5d5bb5fa1ec7ce509a4ca6108b61b84fab"}, @@ -306,6 +331,7 @@ version = "0.11.0" description = "Composable style cycles" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, @@ -317,6 +343,7 @@ version = "0.17.1" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, @@ -324,13 +351,14 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, - {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -338,34 +366,35 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.96.0" +version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "fastapi-0.96.0-py3-none-any.whl", hash = "sha256:b8e11fe81e81eab4e1504209917338e0b80f783878a42c2b99467e5e1019a1e9"}, - {file = "fastapi-0.96.0.tar.gz", hash = "sha256:71232d47c2787446991c81c41c249f8a16238d52d779c0e6b43927d3773dbe3c"}, + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.27.0,<0.28.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.40.0,<0.42.0" +typing-extensions = ">=4.8.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "fastjsonschema" -version = "2.17.1" +version = "2.21.1" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" +groups = ["main"] files = [ - {file = "fastjsonschema-2.17.1-py3-none-any.whl", hash = "sha256:4b90b252628ca695280924d863fe37234eebadc29c5360d322571233dc9746e0"}, - {file = "fastjsonschema-2.17.1.tar.gz", hash = "sha256:f4eeb8a77cef54861dbf7424ac8ce71306f12cbb086c45131bcba2c6a4f726e3"}, + {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"}, + {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"}, ] [package.extras] @@ -377,6 +406,7 @@ version = "2.1.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Flask-2.1.3-py3-none-any.whl", hash = "sha256:9013281a7402ad527f8fd56375164f3aa021ecfaff89bfe3825346c24f87e04c"}, {file = "Flask-2.1.3.tar.gz", hash = "sha256:15972e5017df0575c3d6c090ba168b6db90259e620ac8d7ea813a396bad5b6cb"}, @@ -395,40 +425,45 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-cors" -version = "3.0.10" +version = "5.0.0" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" +groups = ["main"] files = [ - {file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"}, - {file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"}, + {file = "Flask_Cors-5.0.0-py2.py3-none-any.whl", hash = "sha256:b9e307d082a9261c100d8fb0ba909eec6a228ed1b60a8315fd85f783d61910bc"}, + {file = "flask_cors-5.0.0.tar.gz", hash = "sha256:5aadb4b950c4e93745034594d9f3ea6591f734bb3662e16e255ffbf5e89c88ef"}, ] [package.dependencies] Flask = ">=0.9" -Six = "*" [[package]] name = "flask-sock" -version = "0.6.0" +version = "0.7.0" description = "WebSocket support for Flask" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "flask-sock-0.6.0.tar.gz", hash = "sha256:435cf81bb497ac7622cd1dda554fbfa3e369e629daea0a1d21b73a24f1bd6229"}, - {file = "flask_sock-0.6.0-py3-none-any.whl", hash = "sha256:593fffb186928080a5b5b03d717efc56dac2d5ed690ce6bfff333b3597a2f518"}, + {file = "flask-sock-0.7.0.tar.gz", hash = "sha256:e023b578284195a443b8d8bdb4469e6a6acf694b89aeb51315b1a34fcf427b7d"}, + {file = "flask_sock-0.7.0-py3-none-any.whl", hash = "sha256:caac4d679392aaf010d02fabcf73d52019f5bdaf1c9c131ec5a428cb3491204a"}, ] [package.dependencies] flask = ">=2" simple-websocket = ">=0.5.1" +[package.extras] +docs = ["sphinx"] + [[package]] name = "fonttools" version = "4.39.4" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "fonttools-4.39.4-py3-none-any.whl", hash = "sha256:106caf6167c4597556b31a8d9175a3fdc0356fdcd70ab19973c3b0d4c893c461"}, {file = "fonttools-4.39.4.zip", hash = "sha256:dba8d7cdb8e2bac1b3da28c5ed5960de09e59a2fe7e63bb73f5a59e57b0430d2"}, @@ -454,6 +489,7 @@ version = "2022.4.7" description = "A clean customisable Sphinx documentation theme." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "furo-2022.4.7-py3-none-any.whl", hash = "sha256:7f3e3d2fb977483590f8ecb2c2cd511bd82661b79c18efb24de9558bc9cdf2d7"}, {file = "furo-2022.4.7.tar.gz", hash = "sha256:96204ab7cd047e4b6c523996e0279c4c629a8fc31f4f109b2efd470c17f49c80"}, @@ -466,75 +502,89 @@ sphinx = ">=4.0,<5.0" [[package]] name = "greenlet" -version = "2.0.2" +version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -files = [ - {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, - {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, - {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, - {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, - {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, - {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, - {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, - {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, - {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, - {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, - {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, - {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, - {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, - {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, - {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, - {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, - {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, - {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, - {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, - {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, - {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, - {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [package.extras] -docs = ["Sphinx", "docutils (<0.18)"] +docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] [[package]] @@ -543,6 +593,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -554,6 +605,7 @@ version = "1.3.0" description = "Pythonic HTML generation/templating (no template files)" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "html5tagger-1.3.0-py3-none-any.whl", hash = "sha256:ce14313515edffec8ed8a36c5890d023922641171b4e6e5774ad1a74998f5351"}, {file = "html5tagger-1.3.0.tar.gz", hash = "sha256:84fa3dfb49e5c83b79bbd856ab7b1de8e2311c3bb46a8be925f119e3880a8da9"}, @@ -561,56 +613,59 @@ files = [ [[package]] name = "httptools" -version = "0.5.0" +version = "0.6.4" description = "A collection of framework independent HTTP protocol utils." optional = false -python-versions = ">=3.5.0" -files = [ - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51"}, - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a"}, - {file = "httptools-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f"}, - {file = "httptools-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1"}, - {file = "httptools-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324"}, - {file = "httptools-0.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86"}, - {file = "httptools-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25"}, - {file = "httptools-0.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901"}, - {file = "httptools-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372"}, - {file = "httptools-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b"}, - {file = "httptools-0.5.0.tar.gz", hash = "sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09"}, +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, + {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, + {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, + {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, + {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, + {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, + {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, + {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, ] [package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] +test = ["Cython (>=0.29.24)"] [[package]] name = "idna" @@ -618,6 +673,7 @@ version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, @@ -629,6 +685,7 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -640,6 +697,8 @@ version = "6.6.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, @@ -659,6 +718,8 @@ version = "5.12.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, @@ -673,13 +734,14 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec [[package]] name = "itsdangerous" -version = "2.1.2" +version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] @@ -688,6 +750,7 @@ version = "3.1.2" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, @@ -701,13 +764,14 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonpatch" -version = "1.32" +version = "1.33" description = "Apply JSON-Patches (RFC 6902)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +groups = ["main"] files = [ - {file = "jsonpatch-1.32-py2.py3-none-any.whl", hash = "sha256:26ac385719ac9f54df8a2f0827bb8253aa3ea8ab7b3368457bcdb8c14595a397"}, - {file = "jsonpatch-1.32.tar.gz", hash = "sha256:b6ddfe6c3db30d81a96aaeceb6baf916094ffa23d7dd5fa2c13e13f8b6e600c2"}, + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, ] [package.dependencies] @@ -715,13 +779,14 @@ jsonpointer = ">=1.9" [[package]] name = "jsonpointer" -version = "2.3" +version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "jsonpointer-2.3-py2.py3-none-any.whl", hash = "sha256:51801e558539b4e9cd268638c078c6c5746c9ac96bc38152d443400e4f3793e9"}, - {file = "jsonpointer-2.3.tar.gz", hash = "sha256:97cba51526c829282218feb99dab1b1e6bdf8efd1c43dc9d57be093c0d69c99a"}, + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] [[package]] @@ -730,6 +795,7 @@ version = "1.4.4" description = "A fast implementation of the Cassowary constraint solver" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, @@ -807,6 +873,7 @@ version = "2.6.3" description = "Python LiveReload is an awesome tool for web developers" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"}, {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, @@ -818,95 +885,158 @@ tornado = {version = "*", markers = "python_version > \"2.7\""} [[package]] name = "lxml" -version = "4.9.2" +version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" -files = [ - {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, - {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, - {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, - {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, - {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, - {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, - {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, - {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, - {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, - {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, - {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, - {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, - {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, - {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, - {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, - {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, - {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, - {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, - {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, - {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, - {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, - {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, - {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, + {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, + {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, + {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, + {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, + {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, + {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] +source = ["Cython (>=3.0.11)"] [[package]] name = "markupsafe" @@ -914,6 +1044,7 @@ version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, @@ -992,6 +1123,7 @@ version = "3.7.1" description = "Python plotting package" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "matplotlib-3.7.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:95cbc13c1fc6844ab8812a525bbc237fa1470863ff3dace7352e910519e194b1"}, {file = "matplotlib-3.7.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:08308bae9e91aca1ec6fd6dda66237eef9f6294ddb17f0d0b3c863169bf82353"}, @@ -1050,93 +1182,116 @@ python-dateutil = ">=2.7" [[package]] name = "multidict" -version = "6.0.4" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" -files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1148,6 +1303,7 @@ version = "1.24.3" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, @@ -1185,6 +1341,7 @@ version = "23.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, @@ -1196,6 +1353,7 @@ version = "9.5.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, @@ -1271,96 +1429,184 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "playwright" -version = "1.34.0" +version = "1.49.1" description = "A high-level API to automate web browsers" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "playwright-1.34.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:69bb9b3296e366a23a99277b4c7673cb54ce71a3f5d630f114f7701b61f98f25"}, - {file = "playwright-1.34.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:402d946631c8458436e099d7731bbf54cf79c9e62e3acae0ea8421e72616926b"}, - {file = "playwright-1.34.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:462251cda0fcbb273497d357dbe14b11e43ebceb0bac9b892beda041ff209aa9"}, - {file = "playwright-1.34.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:a8ba124ea302596a03a66993cd500484fb255cbc10fe0757fa4d49f974267a80"}, - {file = "playwright-1.34.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf0cb6aac49d24335fe361868aea72b11f276a95e7809f1a5d1c69b4120c46ac"}, - {file = "playwright-1.34.0-py3-none-win32.whl", hash = "sha256:c50fef189d87243cc09ae0feb8e417fbe434359ccbcc863fb19ba06d46d31c33"}, - {file = "playwright-1.34.0-py3-none-win_amd64.whl", hash = "sha256:42e16c930e1e910461f4c551a72fc1b900f37124431bf2b6a6d9ddae70042db4"}, + {file = "playwright-1.49.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:1041ffb45a0d0bc44d698d3a5aa3ac4b67c9bd03540da43a0b70616ad52592b8"}, + {file = "playwright-1.49.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f38ed3d0c1f4e0a6d1c92e73dd9a61f8855133249d6f0cec28648d38a7137be"}, + {file = "playwright-1.49.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:3be48c6d26dc819ca0a26567c1ae36a980a0303dcd4249feb6f59e115aaddfb8"}, + {file = "playwright-1.49.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:753ca90ee31b4b03d165cfd36e477309ebf2b4381953f2a982ff612d85b147d2"}, + {file = "playwright-1.49.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd9bc8dab37aa25198a01f555f0a2e2c3813fe200fef018ac34dfe86b34994b9"}, + {file = "playwright-1.49.1-py3-none-win32.whl", hash = "sha256:43b304be67f096058e587dac453ece550eff87b8fbed28de30f4f022cc1745bb"}, + {file = "playwright-1.49.1-py3-none-win_amd64.whl", hash = "sha256:47b23cb346283278f5b4d1e1990bcb6d6302f80c0aa0ca93dd0601a1400191df"}, ] [package.dependencies] -greenlet = "2.0.2" -pyee = "9.0.4" +greenlet = "3.1.1" +pyee = "12.0.0" [[package]] name = "pydantic" -version = "1.10.8" -description = "Data validation and settings management using python type hints" +version = "2.10.5" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, - {file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, - {file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, - {file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, - {file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, - {file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, - {file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, - {file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, - {file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, - {file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, + {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, + {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.6.0" +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyee" -version = "9.0.4" -description = "A port of node.js's EventEmitter to python." +version = "12.0.0" +description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own" optional = false -python-versions = "*" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "pyee-9.0.4-py2.py3-none-any.whl", hash = "sha256:9f066570130c554e9cc12de5a9d86f57c7ee47fece163bbdaa3e9c933cfbdfa5"}, - {file = "pyee-9.0.4.tar.gz", hash = "sha256:2770c4928abc721f46b705e6a72b0c59480c4a69c9a83ca0b00bb994f1ea4b32"}, + {file = "pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990"}, + {file = "pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145"}, ] [package.dependencies] typing-extensions = "*" +[package.extras] +dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "pytest", "pytest-asyncio", "pytest-trio", "sphinx", "toml", "tox", "trio", "trio", "trio-typing", "twine", "twisted", "validate-pyproject[all]"] + [[package]] name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, @@ -1375,6 +1621,7 @@ version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" +groups = ["main"] files = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, @@ -1389,6 +1636,7 @@ version = "2.8.2" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] files = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, @@ -1399,13 +1647,14 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.0.0" +version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, - {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] [package.extras] @@ -1413,59 +1662,74 @@ cli = ["click (>=5.0)"] [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "reactpy" -version = "1.0.0" -description = "Reactive user interfaces with pure Python" +version = "1.1.0" +description = "It's React, but in Python." optional = false python-versions = ">=3.9" +groups = ["main"] files = [] develop = false @@ -1473,36 +1737,39 @@ develop = false anyio = ">=3" asgiref = ">=3" colorlog = ">=6" -fastapi = {version = ">=0.63.0", optional = true, markers = "extra == \"fastapi\""} +exceptiongroup = ">=1.0" +fastapi = {version = ">=0.63.0", optional = true, markers = "extra == \"all\""} fastjsonschema = ">=2.14.5" -flask = {version = "*", optional = true, markers = "extra == \"flask\""} -flask-cors = {version = "*", optional = true, markers = "extra == \"flask\""} -flask-sock = {version = "*", optional = true, markers = "extra == \"flask\""} +flask = {version = "*", optional = true, markers = "extra == \"all\""} +flask-cors = {version = "*", optional = true, markers = "extra == \"all\""} +flask-sock = {version = "*", optional = true, markers = "extra == \"all\""} jsonpatch = ">=1.32" lxml = ">=4" -markupsafe = {version = ">=1.1.1,<2.1", optional = true, markers = "extra == \"flask\""} +markupsafe = {version = ">=1.1.1,<2.1", optional = true, markers = "extra == \"all\""} mypy-extensions = ">=0.4.3" -playwright = {version = "*", optional = true, markers = "extra == \"testing\""} +playwright = {version = "*", optional = true, markers = "extra == \"all\""} requests = ">=2" -sanic = {version = ">=21", optional = true, markers = "extra == \"sanic\""} -sanic-cors = {version = "*", optional = true, markers = "extra == \"sanic\""} -starlette = {version = ">=0.13.6", optional = true, markers = "extra == \"starlette\""} -tornado = {version = "*", optional = true, markers = "extra == \"tornado\""} +sanic = {version = ">=21", optional = true, markers = "extra == \"all\""} +sanic-cors = {version = "*", optional = true, markers = "extra == \"all\""} +setuptools = {version = "*", optional = true, markers = "extra == \"all\""} +starlette = {version = ">=0.13.6", optional = true, markers = "extra == \"all\""} +tornado = {version = "*", optional = true, markers = "extra == \"all\""} +tracerite = {version = ">=1.1.1", optional = true, markers = "extra == \"all\""} typing-extensions = ">=3.10" -uvicorn = {version = ">=0.19.0", extras = ["standard"], optional = true, markers = "extra == \"fastapi\" or extra == \"sanic\" or extra == \"starlette\""} +uvicorn = {version = ">=0.19.0", extras = ["standard"], optional = true, markers = "extra == \"all\""} [package.extras] -all = ["reactpy[fastapi,flask,sanic,starlette,testing,tornado]"] +all = ["fastapi (>=0.63.0)", "flask", "flask-cors", "flask-sock", "markupsafe (>=1.1.1,<2.1)", "playwright", "sanic (>=21)", "sanic-cors", "setuptools", "starlette (>=0.13.6)", "tornado", "tracerite (>=1.1.1)", "uvicorn[standard] (>=0.19.0)"] fastapi = ["fastapi (>=0.63.0)", "uvicorn[standard] (>=0.19.0)"] flask = ["flask", "flask-cors", "flask-sock", "markupsafe (>=1.1.1,<2.1)"] -sanic = ["sanic (>=21)", "sanic-cors", "uvicorn[standard] (>=0.19.0)"] +sanic = ["sanic (>=21)", "sanic-cors", "setuptools", "tracerite (>=1.1.1)", "uvicorn[standard] (>=0.19.0)"] starlette = ["starlette (>=0.13.6)", "uvicorn[standard] (>=0.19.0)"] testing = ["playwright"] tornado = ["tornado"] [package.source] type = "directory" -url = "../src/py/reactpy" +url = ".." [[package]] name = "requests" @@ -1510,6 +1777,7 @@ version = "2.31.0" description = "Python HTTP for Humans." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, @@ -1527,13 +1795,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "sanic" -version = "23.3.0" +version = "24.12.0" description = "A web server and web framework that's written to go fast. Build fast. Run fast." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "sanic-23.3.0-py3-none-any.whl", hash = "sha256:7cafbd63da9c6c6d8aeb8cb4304addf8a274352ab812014386c63e55f474fbee"}, - {file = "sanic-23.3.0.tar.gz", hash = "sha256:b80ebc5c38c983cb45ae5ecc7a669a54c823ec1dff297fbd5f817b1e9e9e49af"}, + {file = "sanic-24.12.0-py3-none-any.whl", hash = "sha256:3c2a01ec0b6c5926e3efe34eac1b497d31ed989038fe213eb25ad0c98687d388"}, + {file = "sanic-24.12.0.tar.gz", hash = "sha256:09c23aa917616c1e60e44c66dfd7582cb9fd6503f78298c309945909f5839836"}, ] [package.dependencies] @@ -1541,19 +1810,21 @@ aiofiles = ">=0.6.0" html5tagger = ">=1.2.1" httptools = ">=0.0.10" multidict = ">=5.0,<7.0" -sanic-routing = ">=22.8.0" +sanic-routing = ">=23.12.0" +setuptools = ">=70.1.0" tracerite = ">=1.0.0" +typing-extensions = ">=4.4.0" ujson = {version = ">=1.35", markers = "sys_platform != \"win32\" and implementation_name == \"cpython\""} uvloop = {version = ">=0.15.0", markers = "sys_platform != \"win32\" and implementation_name == \"cpython\""} websockets = ">=10.0" [package.extras] -all = ["bandit", "beautifulsoup4", "black", "chardet (==3.*)", "coverage", "cryptography", "docutils", "enum-tools[sphinx]", "flake8", "isort (>=5.0.0)", "m2r2", "mistune (<2.0.0)", "mypy (>=0.901,<0.910)", "pygments", "pytest (==7.1.*)", "pytest-benchmark", "pytest-sanic", "sanic-testing (>=23.3.0)", "slotscheck (>=0.8.0,<1)", "sphinx (>=2.1.2)", "sphinx-rtd-theme (>=0.4.3)", "towncrier", "tox", "types-ujson", "uvicorn (<0.15.0)"] -dev = ["bandit", "beautifulsoup4", "black", "chardet (==3.*)", "coverage", "cryptography", "docutils", "flake8", "isort (>=5.0.0)", "mypy (>=0.901,<0.910)", "pygments", "pytest (==7.1.*)", "pytest-benchmark", "pytest-sanic", "sanic-testing (>=23.3.0)", "slotscheck (>=0.8.0,<1)", "towncrier", "tox", "types-ujson", "uvicorn (<0.15.0)"] -docs = ["docutils", "enum-tools[sphinx]", "m2r2", "mistune (<2.0.0)", "pygments", "sphinx (>=2.1.2)", "sphinx-rtd-theme (>=0.4.3)"] +all = ["autodocsumm (>=0.2.11)", "bandit", "beautifulsoup4", "chardet (==3.*)", "coverage", "cryptography", "docutils", "enum-tools[sphinx]", "m2r2", "mistune (<2.0.0)", "mypy", "pygments", "pytest (>=8.2.2)", "pytest-benchmark", "pytest-sanic", "ruff", "sanic-testing (>=23.6.0)", "slotscheck (>=0.8.0,<1)", "sphinx (>=2.1.2)", "sphinx_rtd_theme (>=0.4.3)", "towncrier", "tox", "types-ujson", "uvicorn"] +dev = ["bandit", "beautifulsoup4", "chardet (==3.*)", "coverage", "cryptography", "docutils", "mypy", "pygments", "pytest (>=8.2.2)", "pytest-benchmark", "pytest-sanic", "ruff", "sanic-testing (>=23.6.0)", "slotscheck (>=0.8.0,<1)", "towncrier", "tox", "types-ujson", "uvicorn"] +docs = ["autodocsumm (>=0.2.11)", "docutils", "enum-tools[sphinx]", "m2r2", "mistune (<2.0.0)", "pygments", "sphinx (>=2.1.2)", "sphinx_rtd_theme (>=0.4.3)"] ext = ["sanic-ext"] http3 = ["aioquic"] -test = ["bandit", "beautifulsoup4", "black", "chardet (==3.*)", "coverage", "docutils", "flake8", "isort (>=5.0.0)", "mypy (>=0.901,<0.910)", "pygments", "pytest (==7.1.*)", "pytest-benchmark", "pytest-sanic", "sanic-testing (>=23.3.0)", "slotscheck (>=0.8.0,<1)", "types-ujson", "uvicorn (<0.15.0)"] +test = ["bandit", "beautifulsoup4", "chardet (==3.*)", "coverage", "docutils", "mypy", "pygments", "pytest (>=8.2.2)", "pytest-benchmark", "pytest-sanic", "ruff", "sanic-testing (>=23.6.0)", "slotscheck (>=0.8.0,<1)", "types-ujson", "uvicorn"] [[package]] name = "sanic-cors" @@ -1561,6 +1832,7 @@ version = "2.2.0" description = "A Sanic extension adding a decorator for CORS support. Based on flask-cors by Cory Dolphin." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "Sanic-Cors-2.2.0.tar.gz", hash = "sha256:f8d7515da4c8b837871d422c66314c4b5704396a78894b59c50e26aa72a95873"}, {file = "Sanic_Cors-2.2.0-py2.py3-none-any.whl", hash = "sha256:c3b133ff1f0bb609a53db35f727f5c371dc4ebeb6be4cc2c37c19dd8b9301115"}, @@ -1572,35 +1844,63 @@ sanic = ">=21.9.3" [[package]] name = "sanic-routing" -version = "22.8.0" +version = "23.12.0" description = "Core routing component for Sanic" optional = false python-versions = "*" +groups = ["main"] files = [ - {file = "sanic-routing-22.8.0.tar.gz", hash = "sha256:305729b4e0bf01f074044a2a315ff401fa7eeffb009eec1d2c81d35e1038ddfc"}, - {file = "sanic_routing-22.8.0-py3-none-any.whl", hash = "sha256:9a928ed9e19a36bc019223be90a5da0ab88cdd76b101e032510b6a7073c017e9"}, + {file = "sanic-routing-23.12.0.tar.gz", hash = "sha256:1dcadc62c443e48c852392dba03603f9862b6197fc4cba5bbefeb1ace0848b04"}, + {file = "sanic_routing-23.12.0-py3-none-any.whl", hash = "sha256:1558a72afcb9046ed3134a5edae02fc1552cff08f0fff2e8d5de0877ea43ed73"}, ] +[[package]] +name = "setuptools" +version = "75.8.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, + {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] + [[package]] name = "simple-websocket" -version = "0.10.0" +version = "1.1.0" description = "Simple WebSocket server and client for Python" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "simple-websocket-0.10.0.tar.gz", hash = "sha256:82c0b0b1006d5490f09ff66392394d90dd758285635edad241e093e9a8abd3eb"}, - {file = "simple_websocket-0.10.0-py3-none-any.whl", hash = "sha256:fc1bc56c393a187e7268f8ab99da1a8e8da9b5dfb7769a2f3b8dada00067745b"}, + {file = "simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c"}, + {file = "simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4"}, ] [package.dependencies] wsproto = "*" +[package.extras] +dev = ["flake8", "pytest", "pytest-cov", "tox"] +docs = ["sphinx"] + [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -1608,13 +1908,14 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] @@ -1623,6 +1924,7 @@ version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, @@ -1634,6 +1936,7 @@ version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, @@ -1645,6 +1948,7 @@ version = "4.5.0" description = "Python documentation generator" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, @@ -1680,6 +1984,7 @@ version = "2021.3.14" description = "Rebuild Sphinx documentation on changes, with live-reload in the browser." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "sphinx-autobuild-2021.3.14.tar.gz", hash = "sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"}, {file = "sphinx_autobuild-2021.3.14-py3-none-any.whl", hash = "sha256:8fe8cbfdb75db04475232f05187c776f46f6e9e04cacf1e49ce81bdac649ccac"}, @@ -1699,6 +2004,7 @@ version = "1.19.1" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sphinx_autodoc_typehints-1.19.1-py3-none-any.whl", hash = "sha256:9be46aeeb1b315eb5df1f3a7cb262149895d16c7d7dcd77b92513c3c3a1e85e6"}, {file = "sphinx_autodoc_typehints-1.19.1.tar.gz", hash = "sha256:6c841db55e0e9be0483ff3962a2152b60e79306f4288d8c4e7e86ac84486a5ea"}, @@ -1717,6 +2023,7 @@ version = "0.5.2" description = "Add a copy button to each of your code cells." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"}, {file = "sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e"}, @@ -1735,6 +2042,7 @@ version = "0.4.1" description = "A sphinx extension for designing beautiful, view size responsive web components." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sphinx_design-0.4.1-py3-none-any.whl", hash = "sha256:23bf5705eb31296d4451f68b0222a698a8a84396ffe8378dfd9319ba7ab8efd9"}, {file = "sphinx_design-0.4.1.tar.gz", hash = "sha256:5b6418ba4a2dc3d83592ea0ff61a52a891fe72195a4c3a18b2fa1c7668ce4708"}, @@ -1758,6 +2066,7 @@ version = "0.1.2" description = "Handles redirects for moved pages in Sphinx documentation projects" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "sphinx_reredirects-0.1.2-py3-none-any.whl", hash = "sha256:3a22161771aadd448bb608a4fe7277252182a337af53c18372b7104531d71489"}, {file = "sphinx_reredirects-0.1.2.tar.gz", hash = "sha256:a0e7213304759b01edc22f032f1715a1c61176fc8f167164e7a52b9feec9ac64"}, @@ -1772,6 +2081,7 @@ version = "0.1.0" description = "Better python object resolution in Sphinx" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sphinx_resolve_py_references-0.1.0-py2.py3-none-any.whl", hash = "sha256:ccf44a6b62d75c3a568285f4e1815734088c1a7cab7bbb7935bb22fbf0d78bc2"}, {file = "sphinx_resolve_py_references-0.1.0.tar.gz", hash = "sha256:0f87c06b29ec128964aee2e40d170d1d3c0e5f4955b2618a89ca724f42385372"}, @@ -1786,6 +2096,7 @@ version = "1.0.4" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, @@ -1801,6 +2112,7 @@ version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, @@ -1816,6 +2128,7 @@ version = "2.0.1" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, @@ -1831,6 +2144,7 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -1845,6 +2159,7 @@ version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, @@ -1860,6 +2175,7 @@ version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, @@ -1875,6 +2191,7 @@ version = "0.8.2" description = "Sphinx Extension to enable OGP support" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sphinxext-opengraph-0.8.2.tar.gz", hash = "sha256:45a693b6704052c426576f0a1f630649c55b4188bc49eb63e9587e24a923db39"}, {file = "sphinxext_opengraph-0.8.2-py3-none-any.whl", hash = "sha256:6a05bdfe5176d9dd0a1d58a504f17118362ab976631213cd36fb44c4c40544c9"}, @@ -1886,13 +2203,14 @@ sphinx = ">=4.0" [[package]] name = "starlette" -version = "0.27.0" +version = "0.41.3" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, - {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, + {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, + {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, ] [package.dependencies] @@ -1900,7 +2218,7 @@ anyio = ">=3.4.0,<5" typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] [[package]] name = "tornado" @@ -1908,6 +2226,7 @@ version = "6.3.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">= 3.8" +groups = ["main"] files = [ {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829"}, {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c"}, @@ -1924,13 +2243,14 @@ files = [ [[package]] name = "tracerite" -version = "1.1.0" +version = "1.1.1" description = "Human-readable HTML tracebacks for Python exceptions" optional = false python-versions = "*" +groups = ["main"] files = [ - {file = "tracerite-1.1.0-py3-none-any.whl", hash = "sha256:4cccac04db05eeeabda45e72b57199e147fa2f73cf64d89cfd625df321bd2ab6"}, - {file = "tracerite-1.1.0.tar.gz", hash = "sha256:041dab8fd4bb405f73506293ac7438a2d311e5f9044378ba7d9a6540392f9e4b"}, + {file = "tracerite-1.1.1-py3-none-any.whl", hash = "sha256:3a787a9ecb1a136ea9ce17e6328e414ec414a4f644130af4e1e330bec2dece29"}, + {file = "tracerite-1.1.1.tar.gz", hash = "sha256:6400a35a187747189e4bb8d4a8e471bd86d14dbdcc94bcad23f4eda023f41356"}, ] [package.dependencies] @@ -1938,87 +2258,103 @@ html5tagger = ">=1.2.1" [[package]] name = "typing-extensions" -version = "4.6.3" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, - {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "ujson" -version = "5.7.0" +version = "5.10.0" description = "Ultra fast JSON encoder and decoder for Python" optional = false -python-versions = ">=3.7" -files = [ - {file = "ujson-5.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5eba5e69e4361ac3a311cf44fa71bc619361b6e0626768a494771aacd1c2f09b"}, - {file = "ujson-5.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aae4d9e1b4c7b61780f0a006c897a4a1904f862fdab1abb3ea8f45bd11aa58f3"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2e43ccdba1cb5c6d3448eadf6fc0dae7be6c77e357a3abc968d1b44e265866d"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54384ce4920a6d35fa9ea8e580bc6d359e3eb961fa7e43f46c78e3ed162d56ff"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24ad1aa7fc4e4caa41d3d343512ce68e41411fb92adf7f434a4d4b3749dc8f58"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:afff311e9f065a8f03c3753db7011bae7beb73a66189c7ea5fcb0456b7041ea4"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e80f0d03e7e8646fc3d79ed2d875cebd4c83846e129737fdc4c2532dbd43d9e"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:137831d8a0db302fb6828ee21c67ad63ac537bddc4376e1aab1c8573756ee21c"}, - {file = "ujson-5.7.0-cp310-cp310-win32.whl", hash = "sha256:7df3fd35ebc14dafeea031038a99232b32f53fa4c3ecddb8bed132a43eefb8ad"}, - {file = "ujson-5.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:af4639f684f425177d09ae409c07602c4096a6287027469157bfb6f83e01448b"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b0f2680ce8a70f77f5d70aaf3f013d53e6af6d7058727a35d8ceb4a71cdd4e9"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a19fd8e7d8cc58a169bea99fed5666023adf707a536d8f7b0a3c51dd498abf"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6abb8e6d8f1ae72f0ed18287245f5b6d40094e2656d1eab6d99d666361514074"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8cd622c069368d5074bd93817b31bdb02f8d818e57c29e206f10a1f9c6337dd"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14f9082669f90e18e64792b3fd0bf19f2b15e7fe467534a35ea4b53f3bf4b755"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7ff6ebb43bc81b057724e89550b13c9a30eda0f29c2f506f8b009895438f5a6"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7f241488879d91a136b299e0c4ce091996c684a53775e63bb442d1a8e9ae22a"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5593263a7fcfb934107444bcfba9dde8145b282de0ee9f61e285e59a916dda0f"}, - {file = "ujson-5.7.0-cp311-cp311-win32.whl", hash = "sha256:26c2b32b489c393106e9cb68d0a02e1a7b9d05a07429d875c46b94ee8405bdb7"}, - {file = "ujson-5.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed24406454bb5a31df18f0a423ae14beb27b28cdfa34f6268e7ebddf23da807e"}, - {file = "ujson-5.7.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18679484e3bf9926342b1c43a3bd640f93a9eeeba19ef3d21993af7b0c44785d"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee295761e1c6c30400641f0a20d381633d7622633cdf83a194f3c876a0e4b7e"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b738282e12a05f400b291966630a98d622da0938caa4bc93cf65adb5f4281c60"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00343501dbaa5172e78ef0e37f9ebd08040110e11c12420ff7c1f9f0332d939e"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c0d1f7c3908357ee100aa64c4d1cf91edf99c40ac0069422a4fd5fd23b263263"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a5d2f44331cf04689eafac7a6596c71d6657967c07ac700b0ae1c921178645da"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:16b2254a77b310f118717715259a196662baa6b1f63b1a642d12ab1ff998c3d7"}, - {file = "ujson-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:6faf46fa100b2b89e4db47206cf8a1ffb41542cdd34dde615b2fc2288954f194"}, - {file = "ujson-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ff0004c3f5a9a6574689a553d1b7819d1a496b4f005a7451f339dc2d9f4cf98c"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:75204a1dd7ec6158c8db85a2f14a68d2143503f4bafb9a00b63fe09d35762a5e"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7312731c7826e6c99cdd3ac503cd9acd300598e7a80bcf41f604fee5f49f566c"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b9dc5a90e2149643df7f23634fe202fed5ebc787a2a1be95cf23632b4d90651"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a6961fc48821d84b1198a09516e396d56551e910d489692126e90bf4887d29"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b01a9af52a0d5c46b2c68e3f258fdef2eacaa0ce6ae3e9eb97983f5b1166edb6"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7316d3edeba8a403686cdcad4af737b8415493101e7462a70ff73dd0609eafc"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ee997799a23227e2319a3f8817ce0b058923dbd31904761b788dc8f53bd3e30"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dda9aa4c33435147262cd2ea87c6b7a1ca83ba9b3933ff7df34e69fee9fced0c"}, - {file = "ujson-5.7.0-cp38-cp38-win32.whl", hash = "sha256:bea8d30e362180aafecabbdcbe0e1f0b32c9fa9e39c38e4af037b9d3ca36f50c"}, - {file = "ujson-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:c96e3b872bf883090ddf32cc41957edf819c5336ab0007d0cf3854e61841726d"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6411aea4c94a8e93c2baac096fbf697af35ba2b2ed410b8b360b3c0957a952d3"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d3b3499c55911f70d4e074c626acdb79a56f54262c3c83325ffb210fb03e44d"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341f891d45dd3814d31764626c55d7ab3fd21af61fbc99d070e9c10c1190680b"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f242eec917bafdc3f73a1021617db85f9958df80f267db69c76d766058f7b19"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3af9f9f22a67a8c9466a32115d9073c72a33ae627b11de6f592df0ee09b98b6"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a3d794afbf134df3056a813e5c8a935208cddeae975bd4bc0ef7e89c52f0ce0"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:800bf998e78dae655008dd10b22ca8dc93bdcfcc82f620d754a411592da4bbf2"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b5ac3d5c5825e30b438ea92845380e812a476d6c2a1872b76026f2e9d8060fc2"}, - {file = "ujson-5.7.0-cp39-cp39-win32.whl", hash = "sha256:cd90027e6d93e8982f7d0d23acf88c896d18deff1903dd96140613389b25c0dd"}, - {file = "ujson-5.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:523ee146cdb2122bbd827f4dcc2a8e66607b3f665186bce9e4f78c9710b6d8ab"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e87cec407ec004cf1b04c0ed7219a68c12860123dfb8902ef880d3d87a71c172"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bab10165db6a7994e67001733f7f2caf3400b3e11538409d8756bc9b1c64f7e8"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b522be14a28e6ac1cf818599aeff1004a28b42df4ed4d7bc819887b9dac915fc"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7592f40175c723c032cdbe9fe5165b3b5903604f774ab0849363386e99e1f253"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ed22f9665327a981f288a4f758a432824dc0314e4195a0eaeb0da56a477da94d"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:adf445a49d9a97a5a4c9bb1d652a1528de09dd1c48b29f79f3d66cea9f826bf6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64772a53f3c4b6122ed930ae145184ebaed38534c60f3d859d8c3f00911eb122"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35209cb2c13fcb9d76d249286105b4897b75a5e7f0efb0c0f4b90f222ce48910"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90712dfc775b2c7a07d4d8e059dd58636bd6ff1776d79857776152e693bddea6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0e4e8981c6e7e9e637e637ad8ffe948a09e5434bc5f52ecbb82b4b4cfc092bfb"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:581c945b811a3d67c27566539bfcb9705ea09cb27c4be0002f7a553c8886b817"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d36a807a24c7d44f71686685ae6fbc8793d784bca1adf4c89f5f780b835b6243"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4257307e3662aa65e2644a277ca68783c5d51190ed9c49efebdd3cbfd5fa44"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea7423d8a2f9e160c5e011119741682414c5b8dce4ae56590a966316a07a4618"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c592eb91a5968058a561d358d0fef59099ed152cfb3e1cd14eee51a7a93879e"}, - {file = "ujson-5.7.0.tar.gz", hash = "sha256:e788e5d5dcae8f6118ac9b45d0b891a0d55f7ac480eddcb7f07263f2bcf37b23"}, +python-versions = ">=3.8" +groups = ["main"] +markers = "sys_platform != \"win32\" and implementation_name == \"cpython\"" +files = [ + {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, + {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, + {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, + {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, + {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, + {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, + {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, + {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, + {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, + {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, + {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, + {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, + {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, + {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, + {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, ] [[package]] @@ -2027,6 +2363,7 @@ version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, @@ -2040,102 +2377,163 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.22.0" +version = "0.34.0" description = "The lightning-fast ASGI server." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, - {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, + {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, + {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, ] [package.dependencies] click = ">=7.0" colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" -httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "uvloop" -version = "0.17.0" +version = "0.21.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false -python-versions = ">=3.7" -files = [ - {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"}, - {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"}, - {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"}, - {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024"}, - {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa"}, - {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811"}, - {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c"}, - {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e"}, - {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539"}, - {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4"}, - {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05"}, - {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376"}, - {file = "uvloop-0.17.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b"}, - {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8"}, - {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62"}, - {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d"}, - {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667"}, - {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738"}, - {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20"}, - {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f"}, - {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595"}, - {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578"}, - {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474"}, - {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b"}, - {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c"}, - {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8"}, - {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c"}, - {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9"}, - {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"}, - {file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"}, +python-versions = ">=3.8.0" +groups = ["main"] +markers = "implementation_name == \"cpython\" and sys_platform != \"win32\" or (sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\"" +files = [ + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, ] [package.extras] -dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] [[package]] name = "watchfiles" -version = "0.19.0" +version = "1.0.4" description = "Simple, modern and high performance file watching and code reload in python." optional = false -python-versions = ">=3.7" -files = [ - {file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, - {file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, - {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, - {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, - {file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, - {file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, - {file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, - {file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "watchfiles-1.0.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ba5bb3073d9db37c64520681dd2650f8bd40902d991e7b4cfaeece3e32561d08"}, + {file = "watchfiles-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f25d0ba0fe2b6d2c921cf587b2bf4c451860086534f40c384329fb96e2044d1"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47eb32ef8c729dbc4f4273baece89398a4d4b5d21a1493efea77a17059f4df8a"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:076f293100db3b0b634514aa0d294b941daa85fc777f9c698adb1009e5aca0b1"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eacd91daeb5158c598fe22d7ce66d60878b6294a86477a4715154990394c9b3"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13c2ce7b72026cfbca120d652f02c7750f33b4c9395d79c9790b27f014c8a5a2"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90192cdc15ab7254caa7765a98132a5a41471cf739513cc9bcf7d2ffcc0ec7b2"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278aaa395f405972e9f523bd786ed59dfb61e4b827856be46a42130605fd0899"}, + {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a462490e75e466edbb9fc4cd679b62187153b3ba804868452ef0577ec958f5ff"}, + {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8d0d0630930f5cd5af929040e0778cf676a46775753e442a3f60511f2409f48f"}, + {file = "watchfiles-1.0.4-cp310-cp310-win32.whl", hash = "sha256:cc27a65069bcabac4552f34fd2dce923ce3fcde0721a16e4fb1b466d63ec831f"}, + {file = "watchfiles-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:8b1f135238e75d075359cf506b27bf3f4ca12029c47d3e769d8593a2024ce161"}, + {file = "watchfiles-1.0.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2a9f93f8439639dc244c4d2902abe35b0279102bca7bbcf119af964f51d53c19"}, + {file = "watchfiles-1.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eea33ad8c418847dd296e61eb683cae1c63329b6d854aefcd412e12d94ee235"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f1a379c9dcbb3f09cf6be1b7e83b67c0e9faabed0471556d9438a4a4e14202"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab594e75644421ae0a2484554832ca5895f8cab5ab62de30a1a57db460ce06c6"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2eb5d14a8e0d5df7b36288979176fbb39672d45184fc4b1c004d7c3ce29317"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f68d8e9d5a321163ddacebe97091000955a1b74cd43724e346056030b0bacee"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9ce064e81fe79faa925ff03b9f4c1a98b0bbb4a1b8c1b015afa93030cb21a49"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b77d5622ac5cc91d21ae9c2b284b5d5c51085a0bdb7b518dba263d0af006132c"}, + {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1941b4e39de9b38b868a69b911df5e89dc43767feeda667b40ae032522b9b5f1"}, + {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f8c4998506241dedf59613082d1c18b836e26ef2a4caecad0ec41e2a15e4226"}, + {file = "watchfiles-1.0.4-cp311-cp311-win32.whl", hash = "sha256:4ebbeca9360c830766b9f0df3640b791be569d988f4be6c06d6fae41f187f105"}, + {file = "watchfiles-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:05d341c71f3d7098920f8551d4df47f7b57ac5b8dad56558064c3431bdfc0b74"}, + {file = "watchfiles-1.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:32b026a6ab64245b584acf4931fe21842374da82372d5c039cba6bf99ef722f3"}, + {file = "watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2"}, + {file = "watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a"}, + {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff"}, + {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e"}, + {file = "watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94"}, + {file = "watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c"}, + {file = "watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90"}, + {file = "watchfiles-1.0.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9"}, + {file = "watchfiles-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902"}, + {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1"}, + {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303"}, + {file = "watchfiles-1.0.4-cp313-cp313-win32.whl", hash = "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80"}, + {file = "watchfiles-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc"}, + {file = "watchfiles-1.0.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d3452c1ec703aa1c61e15dfe9d482543e4145e7c45a6b8566978fbb044265a21"}, + {file = "watchfiles-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7b75fee5a16826cf5c46fe1c63116e4a156924d668c38b013e6276f2582230f0"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e997802d78cdb02623b5941830ab06f8860038faf344f0d288d325cc9c5d2ff"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0611d244ce94d83f5b9aff441ad196c6e21b55f77f3c47608dcf651efe54c4a"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9745a4210b59e218ce64c91deb599ae8775c8a9da4e95fb2ee6fe745fc87d01a"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4810ea2ae622add560f4aa50c92fef975e475f7ac4900ce5ff5547b2434642d8"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:740d103cd01458f22462dedeb5a3382b7f2c57d07ff033fbc9465919e5e1d0f3"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdbd912a61543a36aef85e34f212e5d2486e7c53ebfdb70d1e0b060cc50dd0bf"}, + {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0bc80d91ddaf95f70258cf78c471246846c1986bcc5fd33ccc4a1a67fcb40f9a"}, + {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab0311bb2ffcd9f74b6c9de2dda1612c13c84b996d032cd74799adb656af4e8b"}, + {file = "watchfiles-1.0.4-cp39-cp39-win32.whl", hash = "sha256:02a526ee5b5a09e8168314c905fc545c9bc46509896ed282aeb5a8ba9bd6ca27"}, + {file = "watchfiles-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:a5ae5706058b27c74bac987d615105da17724172d5aaacc6c362a40599b6de43"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdcc92daeae268de1acf5b7befcd6cfffd9a047098199056c72e4623f531de18"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8d3d9203705b5797f0af7e7e5baa17c8588030aaadb7f6a86107b7247303817"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdef5a1be32d0b07dcea3318a0be95d42c98ece24177820226b56276e06b63b0"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:342622287b5604ddf0ed2d085f3a589099c9ae8b7331df3ae9845571586c4f3d"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9fe37a2de80aa785d340f2980276b17ef697ab8db6019b07ee4fd28a8359d2f3"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9d1ef56b56ed7e8f312c934436dea93bfa3e7368adfcf3df4c0da6d4de959a1e"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b42cac65beae3a362629950c444077d1b44f1790ea2772beaea95451c086bb"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e0227b8ed9074c6172cf55d85b5670199c99ab11fd27d2c473aa30aec67ee42"}, + {file = "watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205"}, ] [package.dependencies] @@ -2143,81 +2541,81 @@ anyio = ">=3.0.0" [[package]] name = "websockets" -version = "11.0.3" +version = "14.2" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.7" -files = [ - {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"}, - {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"}, - {file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"}, - {file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"}, - {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11"}, - {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca"}, - {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"}, - {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"}, - {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"}, - {file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"}, - {file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"}, - {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"}, - {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"}, - {file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"}, - {file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"}, - {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b"}, - {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6"}, - {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"}, - {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"}, - {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"}, - {file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"}, - {file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"}, - {file = "websockets-11.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152"}, - {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f"}, - {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b"}, - {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb"}, - {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007"}, - {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0"}, - {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af"}, - {file = "websockets-11.0.3-cp37-cp37m-win32.whl", hash = "sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f"}, - {file = "websockets-11.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de"}, - {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0"}, - {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae"}, - {file = "websockets-11.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99"}, - {file = "websockets-11.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa"}, - {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86"}, - {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c"}, - {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0"}, - {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e"}, - {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788"}, - {file = "websockets-11.0.3-cp38-cp38-win32.whl", hash = "sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74"}, - {file = "websockets-11.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f"}, - {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8"}, - {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd"}, - {file = "websockets-11.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016"}, - {file = "websockets-11.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61"}, - {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b"}, - {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd"}, - {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7"}, - {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1"}, - {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311"}, - {file = "websockets-11.0.3-cp39-cp39-win32.whl", hash = "sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128"}, - {file = "websockets-11.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e"}, - {file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"}, - {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"}, - {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998"}, - {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b"}, - {file = "websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"}, - {file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"}, - {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"}, - {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9"}, - {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280"}, - {file = "websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"}, - {file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"}, - {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"}, - {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d"}, - {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4"}, - {file = "websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"}, - {file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"}, - {file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"}, + {file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"}, + {file = "websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d"}, + {file = "websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d"}, + {file = "websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f"}, + {file = "websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d"}, + {file = "websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a"}, + {file = "websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967"}, + {file = "websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe"}, + {file = "websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205"}, + {file = "websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad"}, + {file = "websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307"}, + {file = "websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc"}, + {file = "websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12"}, + {file = "websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc"}, + {file = "websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661"}, + {file = "websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a"}, + {file = "websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270"}, + {file = "websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365"}, + {file = "websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b"}, + {file = "websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5"}, ] [[package]] @@ -2226,6 +2624,7 @@ version = "2.1.2" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "Werkzeug-2.1.2-py3-none-any.whl", hash = "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255"}, {file = "Werkzeug-2.1.2.tar.gz", hash = "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6"}, @@ -2240,6 +2639,7 @@ version = "1.2.0" description = "WebSockets state-machine based protocol implementation" optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, @@ -2254,6 +2654,8 @@ version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, @@ -2264,6 +2666,6 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.9" -content-hash = "629118cfac10f1dab4c39c6ccd50bd69ca68a7fc05dd2baf1d020082d6b19e4e" +content-hash = "ce11f3670471f6ab3537180188001140700188469fbc1a03a25a630b2c6abbef" diff --git a/docs/pyproject.toml b/docs/pyproject.toml index f47b0e944..3be4b4a8a 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -7,8 +7,8 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.9" -reactpy = { path = "../src/py/reactpy", extras = ["starlette", "sanic", "fastapi", "flask", "tornado", "testing"], develop = false } furo = "2022.04.07" +reactpy = { path = "..", extras = ["all"], develop = false } sphinx = "*" sphinx-autodoc-typehints = "*" sphinx-copybutton = "*" diff --git a/docs/source/_custom_js/README.md b/docs/source/_custom_js/README.md index 4d5d75dc2..ef30b9a76 100644 --- a/docs/source/_custom_js/README.md +++ b/docs/source/_custom_js/README.md @@ -3,7 +3,7 @@ Build the javascript with ``` -npm run build +bun run build ``` This will drop a javascript bundle into `../_static/custom.js` diff --git a/docs/source/_custom_js/bun.lockb b/docs/source/_custom_js/bun.lockb new file mode 100644 index 000000000..39e1393c3 Binary files /dev/null and b/docs/source/_custom_js/bun.lockb differ diff --git a/docs/source/_custom_js/package-lock.json b/docs/source/_custom_js/package-lock.json deleted file mode 100644 index 98cbb7014..000000000 --- a/docs/source/_custom_js/package-lock.json +++ /dev/null @@ -1,766 +0,0 @@ -{ - "name": "reactpy-docs-example-loader", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "reactpy-docs-example-loader", - "version": "1.0.0", - "dependencies": { - "@reactpy/client": "file:../../../src/js/packages/@reactpy/client" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-node-resolve": "^13.1.1", - "@rollup/plugin-replace": "^3.0.0", - "prettier": "^2.2.1", - "rollup": "^2.35.1" - } - }, - "../../../src/client/packages/@reactpy/client": { - "version": "0.3.1", - "integrity": "sha512-pIK5eNwFSHKXg7ClpASWFVKyZDYxz59MSFpVaX/OqJFkrJaAxBuhKGXNTMXmuyWOL5Iyvb/ErwwDRxQRzMNkfQ==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "event-to-object": "^0.1.2", - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "../../../src/client/packages/client": { - "name": "@reactpy/client", - "version": "0.2.0", - "extraneous": true, - "license": "MIT", - "dependencies": { - "event-to-object": "^0.1.0", - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "prettier": "^3.0.0-alpha.6", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "../../../src/js/packages/@reactpy/client": { - "version": "0.3.1", - "license": "MIT", - "dependencies": { - "event-to-object": "^0.1.2", - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "node_modules/@reactpy/client": { - "resolved": "../../../src/js/packages/@reactpy/client", - "link": true - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.1.tgz", - "integrity": "sha512-6QKtRevXLrmEig9UiMYt2fSvee9TyltGRfw+qSs6xjUnxwjOzTOqy+/Lpxsgjb8mJn1EQNbCDAvt89O4uzL5kw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" - } - }, - "node_modules/@rollup/plugin-node-resolve/node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.0.tgz", - "integrity": "sha512-3c7JCbMuYXM4PbPWT4+m/4Y6U60SgsnDT/cCyAyUKwFHg7pTSfsSQzIpETha3a3ig6OdOKzZz87D9ZXIK3qsDg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", - "dev": true - }, - "node_modules/@types/node": { - "version": "15.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", - "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", - "dev": true - }, - "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==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "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==", - "dev": true - }, - "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/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "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==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "2.52.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.1.tgz", - "integrity": "sha512-/SPqz8UGnp4P1hq6wc9gdTqA2bXQXGx13TtoL03GBm6qGRI6Hm3p4Io7GeiHNLl0BsQAne1JNYY+q/apcY933w==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - }, - "dependencies": { - "@reactpy/client": { - "version": "file:../../../src/js/packages/@reactpy/client", - "requires": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "event-to-object": "^0.1.2", - "json-pointer": "^0.6.2", - "typescript": "^4.9.5" - } - }, - "@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "dependencies": { - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - } - } - }, - "@rollup/plugin-node-resolve": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.1.tgz", - "integrity": "sha512-6QKtRevXLrmEig9UiMYt2fSvee9TyltGRfw+qSs6xjUnxwjOzTOqy+/Lpxsgjb8mJn1EQNbCDAvt89O4uzL5kw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "dependencies": { - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - } - } - }, - "@rollup/plugin-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.0.tgz", - "integrity": "sha512-3c7JCbMuYXM4PbPWT4+m/4Y6U60SgsnDT/cCyAyUKwFHg7pTSfsSQzIpETha3a3ig6OdOKzZz87D9ZXIK3qsDg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", - "dev": true - }, - "@types/node": { - "version": "15.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", - "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", - "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==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "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==", - "dev": true - }, - "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" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "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==", - "dev": true - }, - "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "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==", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "rollup": { - "version": "2.52.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.1.tgz", - "integrity": "sha512-/SPqz8UGnp4P1hq6wc9gdTqA2bXQXGx13TtoL03GBm6qGRI6Hm3p4Io7GeiHNLl0BsQAne1JNYY+q/apcY933w==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - } -} diff --git a/docs/source/_exts/autogen_api_docs.py b/docs/source/_exts/autogen_api_docs.py index b95d85a99..cdd1f184e 100644 --- a/docs/source/_exts/autogen_api_docs.py +++ b/docs/source/_exts/autogen_api_docs.py @@ -8,7 +8,7 @@ HERE = Path(__file__).parent SRC = HERE.parent.parent.parent / "src" -PYTHON_PACKAGE = SRC / "py" / "reactpy" / "reactpy" +PYTHON_PACKAGE = SRC / "reactpy" AUTO_DIR = HERE.parent / "_auto" AUTO_DIR.mkdir(exist_ok=True) @@ -43,7 +43,7 @@ def generate_api_docs(): if file.name == "__init__.py": if file.parent != PYTHON_PACKAGE: content.append(make_package_section(file)) - else: + elif not file.name.startswith("_"): content.append(make_module_section(file)) API_FILE.write_text("\n".join(content)) @@ -104,10 +104,10 @@ def walk_python_files(root: Path, ignore_dirs: Collection[str]) -> Iterator[Path We yield the files in this order:: - project/__init__.py - project/package/__init__.py - project/package/module_a.py - project/module_b.py + project / __init__.py + project / package / __init__.py + project / package / module_a.py + project / module_b.py In this way we generate the section titles in the appropriate order:: diff --git a/docs/source/_exts/build_custom_js.py b/docs/source/_exts/build_custom_js.py index 97857ba74..a12c5c7f7 100644 --- a/docs/source/_exts/build_custom_js.py +++ b/docs/source/_exts/build_custom_js.py @@ -8,5 +8,5 @@ def setup(app: Sphinx) -> None: - subprocess.run("npm install", cwd=CUSTOM_JS_DIR, shell=True) # noqa S607 - subprocess.run("npm run build", cwd=CUSTOM_JS_DIR, shell=True) # noqa S607 + subprocess.run("bun install", cwd=CUSTOM_JS_DIR, shell=True) # noqa S607 + subprocess.run("bun run build", cwd=CUSTOM_JS_DIR, shell=True) # noqa S607 diff --git a/docs/source/about/changelog.rst b/docs/source/about/changelog.rst index fd91cdf19..6ea0fd6b0 100644 --- a/docs/source/about/changelog.rst +++ b/docs/source/about/changelog.rst @@ -5,30 +5,117 @@ Changelog All notable changes to this project will be recorded in this document. The style of which is based on `Keep a Changelog `__. The versioning - scheme for the project adheres to `Semantic Versioning `__. For - more info, see the :ref:`Contributor Guide `. + scheme for the project adheres to `Semantic Versioning `__. -.. INSTRUCTIONS FOR CHANGELOG CONTRIBUTORS -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -.. If you're adding a changelog entry, be sure to read the "Creating a Changelog Entry" -.. section of the documentation before doing so for instructions on how to adhere to the -.. "Keep a Changelog" style guide (https://keepachangelog.com). +.. Using the following categories, list your changes in this order: +.. [Added, Changed, Deprecated, Removed, Fixed, Security] +.. Don't forget to remove deprecated code on each major release! Unreleased ---------- -Nothing (yet)! +**Added** + +- :pull:`1113` - Added support for Python 3.12, 3.13, and 3.14. +- :pull:`1281` - Added type hints to ``reactpy.html`` attributes. +- :pull:`1285` - Added support for nested components in web modules +- :pull:`1289` - Added support for inline JavaScript as event handlers or other attributes that expect a callable via ``reactpy.types.InlineJavaScript`` +- :pull:`1308` - Event functions can now call ``event.preventDefault()`` and ``event.stopPropagation()`` methods directly on the event data object, rather than using the ``@event`` decorator. +- :pull:`1308` - Event data now supports accessing properties via dot notation (ex. ``event.target.value``). +- :pull:`1308` - Added ``reactpy.types.Event`` to provide type hints for the standard ``data`` function argument (for example ``def on_click(event: Event): ...``). +- :pull:`1113` - Added ``asgi`` and ``jinja`` installation extras (for example ``pip install reactpy[asgi, jinja]``). +- :pull:`1267` - Added ``shutdown_timeout`` parameter to the ``reactpy.use_async_effect`` hook. +- :pull:`1113` - Added ``reactpy.executors.asgi.ReactPy`` that can be used to run ReactPy in standalone mode via ASGI. +- :pull:`1269` - Added ``reactpy.executors.asgi.ReactPyCsr`` that can be used to run ReactPy in standalone mode via ASGI, but rendered entirely client-sided. +- :pull:`1113` - Added ``reactpy.executors.asgi.ReactPyMiddleware`` that can be used to utilize ReactPy within any ASGI compatible framework. +- :pull:`1269` - Added ``reactpy.templatetags.ReactPyJinja`` that can be used alongside ``ReactPyMiddleware`` to embed several ReactPy components into your existing application. This includes the following template tags: ``{% component %}``, ``{% pyscript_component %}``, and ``{% pyscript_setup %}``. +- :pull:`1269` - Added ``reactpy.pyscript_component`` that can be used to embed ReactPy components into your existing application. +- :pull:`1264` - Added ``reactpy.use_async_effect`` hook. +- :pull:`1281` - Added ``reactpy.Vdom`` primitive interface for creating VDOM dictionaries. +- :pull:`1307` - Added ``reactpy.reactjs.component_from_file`` to import ReactJS components from a file. +- :pull:`1307` - Added ``reactpy.reactjs.component_from_url`` to import ReactJS components from a URL. +- :pull:`1307` - Added ``reactpy.reactjs.component_from_string`` to import ReactJS components from a string. +- :pull:`1314` - Added ``reactpy.reactjs.component_from_npm`` to import ReactJS components from NPM. +- :pull:`1314` - Added ``reactpy.h`` as a shorthand alias for ``reactpy.html``. + +**Changed** + +- :pull:`1314` - The ``key`` attribute is now stored within ``attributes`` in the VDOM spec. +- :pull:`1251` - Substitute client-side usage of ``react`` with ``preact``. +- :pull:`1239` - Script elements no longer support behaving like effects. They now strictly behave like plain HTML scripts. +- :pull:`1255` - The ``reactpy.html`` module has been modified to allow for auto-creation of any HTML nodes. For example, you can create a ```` element by calling ``html.data_table()``. +- :pull:`1256` - Change ``set_state`` comparison method to check equality with ``==`` more consistently. +- :pull:`1257` - Add support for rendering ``@component`` children within ``vdom_to_html``. +- :pull:`1113` - Renamed the ``use_location`` hook's ``search`` attribute to ``query_string``. +- :pull:`1113` - Renamed the ``use_location`` hook's ``pathname`` attribute to ``path``. +- :pull:`1113` - Renamed ``reactpy.config.REACTPY_DEBUG_MODE`` to ``reactpy.config.REACTPY_DEBUG``. +- :pull:`1263` - ReactPy no longer auto-converts ``snake_case`` props to ``camelCase``. It is now the responsibility of the user to ensure that props are in the correct format. +- :pull:`1196` - Rewrite the ``event-to-object`` package to be more robust at handling properties on events. +- :pull:`1312` - Custom JS components will now automatically assume you are using ReactJS in the absence of a ``bind`` function. +- :pull:`1312` - Refactor layout rendering logic to improve readability and maintainability. +- :pull:`1113` - ``@reactpy/client`` now exports ``React`` and ``ReactDOM``. +- :pull:`1281` - ``reactpy.html`` will now automatically flatten lists recursively (ex. ``reactpy.html(["child1", ["child2"]])``) +- :pull:`1278` - ``reactpy.utils.reactpy_to_string`` will now retain the user's original casing for ``data-*`` and ``aria-*`` attributes. +- :pull:`1278` - ``reactpy.utils.string_to_reactpy`` has been upgraded to handle more complex scenarios without causing ReactJS rendering errors. +- :pull:`1281` - ``reactpy.core.vdom._CustomVdomDictConstructor`` has been moved to ``reactpy.types.CustomVdomConstructor``. +- :pull:`1281` - ``reactpy.core.vdom._EllipsisRepr`` has been moved to ``reactpy.types.EllipsisRepr``. +- :pull:`1281` - ``reactpy.types.VdomDictConstructor`` has been renamed to ``reactpy.types.VdomConstructor``. +- :pull:`1312` - ``REACTPY_ASYNC_RENDERING`` can now de-duplicate and cascade renders where necessary. +- :pull:`1312` - ``REACTPY_ASYNC_RENDERING`` is now defaulted to ``True`` for up to 40x performance improvements in environments with high concurrency. + +**Deprecated** + +-:pull:`1307` - ``reactpy.web.export`` is deprecated. Use ``reactpy.reactjs.component_from_*`` instead. +-:pull:`1307` - ``reactpy.web.module_from_file`` is deprecated. Use ``reactpy.reactjs.component_from_file`` instead. +-:pull:`1307` - ``reactpy.web.module_from_url`` is deprecated. Use ``reactpy.reactjs.component_from_url`` instead. +-:pull:`1307` - ``reactpy.web.module_from_string`` is deprecated. Use ``reactpy.reactjs.component_from_string`` instead. +-:pull:`1314` - ``reactpy.web.*`` is deprecated. Use ``reactpy.reactjs.*`` instead. + +**Removed** + +- :pull:`1113` - Removed support for Python 3.9 and 3.10. +- :pull:`1255` - Removed the ability to import ``reactpy.html.*`` elements directly. You must now call ``html.*`` to access the elements. +- :pull:`1113` - Removed backend specific installation extras (such as ``pip install reactpy[starlette]``). +- :pull:`1264` - Removed support for async functions within ``reactpy.use_effect`` hook. Use ``reactpy.use_async_effect`` instead. +- :pull:`1113` - Removed deprecated function ``module_from_template``. +- :pull:`1311` - Removed deprecated exception type ``reactpy.core.serve.Stop``. +- :pull:`1311` - Removed deprecated component ``reactpy.widgets.hotswap``. +- :pull:`1255` - Removed ``reactpy.sample`` module. +- :pull:`1255` - Removed ``reactpy.svg`` module. Contents previously within ``reactpy.svg.*`` can now be accessed via ``reactpy.html.svg.*``. +- :pull:`1255` - Removed ``reactpy.html._`` function. Use ``reactpy.html(...)`` or ``reactpy.html.fragment(...)`` instead. +- :pull:`1113` - Removed ``reactpy.run``. See the documentation for the new method to run ReactPy applications. +- :pull:`1113` - Removed ``reactpy.backend.*``. See the documentation for the new method to run ReactPy applications. +- :pull:`1113` - Removed ``reactpy.core.types`` module. Use ``reactpy.types`` instead. +- :pull:`1278` - Removed ``reactpy.utils.html_to_vdom``. Use ``reactpy.utils.string_to_reactpy`` instead. +- :pull:`1278` - Removed ``reactpy.utils.vdom_to_html``. Use ``reactpy.utils.reactpy_to_string`` instead. +- :pull:`1281` - Removed ``reactpy.vdom``. Use ``reactpy.Vdom`` instead. +- :pull:`1281` - Removed ``reactpy.core.make_vdom_constructor``. Use ``reactpy.Vdom`` instead. +- :pull:`1281` - Removed ``reactpy.core.custom_vdom_constructor``. Use ``reactpy.Vdom`` instead. +- :pull:`1311` - Removed ``reactpy.Layout`` top-level re-export. Use ``reactpy.core.layout.Layout`` instead. +- :pull:`1312` - Removed ``reactpy.types.LayoutType``. Use ``reactpy.types.BaseLayout`` instead. +- :pull:`1312` - Removed ``reactpy.types.ContextProviderType``. Use ``reactpy.types.ContextProvider`` instead. +- :pull:`1312` - Removed ``reactpy.core.hooks._ContextProvider``. Use ``reactpy.types.ContextProvider`` instead. +- :pull:`1314` - Removed ``reactpy.web.utils``. Use ``reactpy.reactjs.utils`` instead. + +**Fixed** + +- :pull:`1239` - Fixed a bug where script elements would not render to the DOM as plain text. +- :pull:`1271` - Fixed a bug where the ``key`` property provided within server-side ReactPy code was failing to propagate to the front-end JavaScript components. +- :pull:`1254` - Fixed a bug where ``RuntimeError("Hook stack is in an invalid state")`` errors could be generated when using a webserver that reuses threads. +- :pull:`1314` - Allow for ReactPy and ReactJS components to be arbitrarily inserted onto the page with any possible hierarchy. + v1.1.0 ------ +:octicon:`milestone` *released on 2024-11-24* **Fixed** - :pull:`1118` - ``module_from_template`` is broken with a recent release of ``requests`` - :pull:`1131` - ``module_from_template`` did not work when using Flask backend - :pull:`1200` - Fixed ``UnicodeDecodeError`` when using ``reactpy.web.export`` -- :pull:`1224` - Fixes needless unmounting of JavaScript components during each ReactPy render. +- :pull:`1224` - Fixed needless unmounting of JavaScript components during each ReactPy render. - :pull:`1126` - Fixed missing ``event["target"]["checked"]`` on checkbox inputs - :pull:`1191` - Fixed missing static files on `sdist` Python distribution @@ -42,12 +129,8 @@ v1.1.0 **Changed** - :pull:`1171` - Previously ``None``, when present in an HTML element, would render as - the string ``"None"``. Now ``None`` will not render at all. This is consistent with - how ``None`` is handled when returned from components. It also makes it easier to - conditionally render elements. For example, previously you would have needed to use a - fragment to conditionally render an element by writing - ``something if condition else html._()``. Now you can simply write - ``something if condition else None``. + the string ``"None"``. Now ``None`` will not render at all. This is now equivalent to + how ``None`` is handled when returned from components. - :pull:`1210` - Move hooks from ``reactpy.backend.hooks`` into ``reactpy.core.hooks``. **Deprecated** @@ -61,6 +144,7 @@ v1.1.0 v1.0.2 ------ +:octicon:`milestone` *released on 2023-07-03* **Fixed** @@ -69,6 +153,7 @@ v1.0.2 v1.0.1 ------ +:octicon:`milestone` *released on 2023-06-16* **Changed** @@ -221,7 +306,7 @@ v0.43.0 **Deprecated** -- :pull:`870` - ``ComponentType.should_render()``. This method was implemented based on +- :pull:`870` - ``ComponentType.()``. This method was implemented based on reading the React/Preact source code. As it turns out though it seems like it's mostly a vestige from the fact that both these libraries still support class-based components. The ability for components to not render also caused several bugs. diff --git a/docs/source/about/contributor-guide.rst b/docs/source/about/contributor-guide.rst index 73ae3f23d..45ce4a512 100644 --- a/docs/source/about/contributor-guide.rst +++ b/docs/source/about/contributor-guide.rst @@ -1,329 +1,137 @@ Contributor Guide ================= -.. note:: +Creating a development environment +---------------------------------- - The - `Code of Conduct `__ - applies in all community spaces. If you are not familiar with our Code of Conduct - policy, take a minute to read it before making your first contribution. +If you plan to make code changes to this repository, you will need to install the following dependencies first: -The ReactPy team welcomes contributions and contributors of all kinds - whether they come -as code changes, participation in the discussions, opening issues and pointing out bugs, -or simply sharing your work with your colleagues and friends. We're excited to see how -you can help move this project and community forward! +- `Git `__ +- `Python 3.9+ `__ +- `Hatch `__ +- `Bun `__ +- `Docker `__ (optional) - -.. _everyone can contribute: - -Everyone Can Contribute! ------------------------- - -Trust us, there's so many ways to support the project. We're always looking for people -who can: - -- Improve our documentation -- Teach and tell others about ReactPy -- Share ideas for new features -- Report bugs -- Participate in general discussions - -Still aren't sure what you have to offer? Just :discussion-type:`ask us ` and -we'll help you make your first contribution. - - -Making a Pull Request ---------------------- - -To make your first code contribution to ReactPy, you'll need to install Git_ (or -`Git Bash`_ on Windows). Thankfully there are many helpful -`tutorials `__ -about how to get started. To make a change to ReactPy you'll do the following: - -`Fork ReactPy `__: - Go to `this URL `__ and click the "Fork" button. - -`Clone your fork `__: - You use a ``git clone`` command to copy the code from GitHub to your computer. - -`Create a new branch `__: - You'll ``git checkout -b your-first-branch`` to create a new space to start your work. - -:ref:`Prepare your Development Environment `: - We explain in more detail below how to install all ReactPy's dependencies. - -`Push your changes `__: - Once you've made changes to ReactPy, you'll ``git push`` them to your fork. - -:ref:`Create a changelog entry `: - Record your changes in the :ref:`changelog` so we can publicize them in the next release. - -`Create a Pull Request `__: - We'll review your changes, run some :ref:`tests ` and - :ref:`equality checks ` and, with any luck, accept your request. - At that point your contribution will be merged into the main codebase! - - -Development Environment ------------------------ - -.. note:: - - If you have any questions during set up or development post on our - :discussion-type:`discussion board ` and we'll answer them. - -In order to develop ReactPy locally you'll first need to install the following: - -.. list-table:: - :header-rows: 1 - - * - What to Install - - How to Install - - * - Python >= 3.9 - - https://realpython.com/installing-python/ - - * - Hatch - - https://hatch.pypa.io/latest/install/ - - * - Poetry - - https://python-poetry.org/docs/#installation - - * - Git - - https://git-scm.com/book/en/v2/Getting-Started-Installing-Git - - * - NodeJS >= 14 - - https://nodejs.org/en/download/package-manager/ - - * - NPM >= 7.13 - - https://docs.npmjs.com/try-the-latest-stable-version-of-npm - - * - Docker (optional) - - https://docs.docker.com/get-docker/ - -.. note:: - - NodeJS distributes a version of NPM, but you'll want to get the latest - -Once done, you can clone a local copy of this repository: +Once you finish installing these dependencies, you can clone this repository: .. code-block:: bash git clone https://github.com/reactive-python/reactpy.git cd reactpy -Then, you should be able to activate your development environment with: - -.. code-block:: bash - - hatch shell - -From within the shell, to install the projects in this repository, you should then run: - -.. code-block:: bash - - invoke env - -Project Structure ------------------ - -This repository is set up to be able to manage many applications and libraries written -in a variety of languages. All projects can be found under the ``src`` directory: - -- ``src/py/{project}`` - Python packages -- ``src/js/app`` - ReactPy's built-in JS client -- ``src/js/packages/{project}`` - JS packages - -At the root of the repository is a ``pyproject.toml`` file that contains scripts and -their respective dependencies for managing all other projects. Most of these global -scripts can be run via ``hatch run ...`` however, for more complex scripting tasks, we -rely on Invoke_. Scripts implements with Invoke can be found in ``tasks.py``. - -Running The Tests ------------------ - -Tests exist for both Python and Javascript. These can be run with the following: - -.. code-block:: bash - - hatch run test-py - hatch run test-js - -If you want to run tests for individual packages you'll need to ``cd`` into the -package directory and run the tests from there. For example, to run the tests just for -the ``reactpy`` package you'd do: - -.. code-block:: bash - - cd src/py/reactpy - hatch run test --headed # run the tests in a browser window - -For Javascript, you'd do: - -.. code-block:: bash +Executing test environment commands +----------------------------------- - cd src/js/packages/event-to-object - npm run check:tests +By utilizing ``hatch``, the following commands are available to manage the development environment. +Python Tests +............ -Code Quality Checks -------------------- - -Several tools are run on the codebase to help validate its quality. For the most part, -if you set up your :ref:`Development Environment` with pre-commit_ to check your work -before you commit it, then you'll be notified when changes need to be made or, in the -best case, changes will be made automatically for you. - -The following are currently being used: - -- MyPy_ - a static type checker -- Black_ - an opinionated code formatter -- Flake8_ - a style guide enforcement tool -- Ruff_ - An extremely fast Python linter, written in Rust. -- Prettier_ - a tool for automatically formatting various file types -- EsLint_ - A Javascript linter - -The most strict measure of quality enforced on the codebase is 100% test coverage in -Python files. This means that every line of coded added to ReactPy requires a test case -that exercises it. This doesn't prevent all bugs, but it should ensure that we catch the -most common ones. - -If you need help understanding why code you've submitted does not pass these checks, -then be sure to ask, either in the :discussion-type:`Community Forum ` or in -your :ref:`Pull Request `. - -.. note:: - - You can manually run ``hatch run lint --fix`` to auto format your code without - having to do so via ``pre-commit``. However, many IDEs have ways to automatically - format upon saving a file (e.g. - `VSCode `__) - - -Building The Documentation --------------------------- - -To build and display the documentation locally run: - -.. code-block:: bash +.. list-table:: + :header-rows: 1 - hatch run docs + * - Command + - Description + * - ``hatch test`` + - Run Python tests using the current environment's Python version + * - ``hatch test --all`` + - Run tests using all compatible Python versions + * - ``hatch test --python 3.9`` + - Run tests using a specific Python version + * - ``hatch test -k test_use_connection`` + - Run only a specific test -This will compile the documentation from its source files into HTML, start a web server, -and open a browser to display the now generated documentation. Whenever you change any -source files the web server will automatically rebuild the documentation and refresh the -page. Under the hood this is using -`sphinx-autobuild `__. +Python Package +.............. -To run some of the examples in the documentation as if they were tests run: +.. list-table:: + :header-rows: 1 -.. code-block:: bash + * - Command + - Description + * - ``hatch fmt`` + - Run all linters and formatters + * - ``hatch fmt --check`` + - Run all linters and formatters, but do not save fixes to the disk + * - ``hatch fmt --linter`` + - Run only linters + * - ``hatch fmt --formatter`` + - Run only formatters + * - ``hatch run python:type_check`` + - Run the Python type checker + +JavaScript Packages +................... - hatch run test-docs +.. list-table:: + :header-rows: 1 -Building the documentation as it's deployed in production requires Docker_. Once you've -installed Docker, you can run: + * - Command + - Description + * - ``hatch run javascript:check`` + - Run the JavaScript linter/formatter + * - ``hatch run javascript:fix`` + - Run the JavaScript linter/formatter and write fixes to disk + * - ``hatch run javascript:test`` + - Run the JavaScript tests + * - ``hatch run javascript:build`` + - Build all JavaScript packages + * - ``hatch run javascript:build_event_to_object`` + - Build the ``event-to-object`` package + * - ``hatch run javascript:build_client`` + - Build the ``@reactpy/client`` package + * - ``hatch run javascript:build_app`` + - Build the ``@reactpy/app`` package + +Documentation +............. -.. code-block:: bash +.. list-table:: + :header-rows: 1 - hatch run docs --docker + * - Command + - Description + * - ``hatch run docs:serve`` + - Start the documentation preview webserver + * - ``hatch run docs:build`` + - Build the documentation + * - ``hatch run docs:check`` + - Check the documentation for build errors + * - ``hatch run docs:docker_serve`` + - Start the documentation preview webserver using Docker + * - ``hatch run docs:docker_build`` + - Build the documentation using Docker + +Environment Management +...................... -Where you can then navigate to http://localhost:5000.. +.. list-table:: + :header-rows: 1 + * - Command + - Description + * - ``hatch build --clean`` + - Build the package from source + * - ``hatch env prune`` + - Delete all virtual environments created by ``hatch`` + * - ``hatch python install 3.12`` + - Install a specific Python version to your system -Creating a Changelog Entry +Other ReactPy Repositories -------------------------- -As part of your pull request, you'll want to edit the `Changelog -`__ by -adding an entry describing what you've changed or improved. You should write an entry in -the style of `Keep a Changelog `__ that falls under one of -the following categories, and add it to the :ref:`Unreleased` section of the changelog: - -- **Added** - for new features. -- **Changed** - for changes in existing functionality. -- **Deprecated** - for soon-to-be removed features. -- **Removed** - for now removed features. -- **Fixed** - for any bug fixes. -- **Documented** - for improvements to this documentation. -- **Security** - in case of vulnerabilities. - -If one of the sections doesn't exist, add it. If it does already, add a bullet point -under the relevant section. Your description should begin with a reference to the -relevant issue or pull request number. Here's a short example of what an unreleased -changelog entry might look like: - -.. code-block:: rst - - Unreleased - ---------- - - **Added** - - - :pull:`123` - A really cool new feature - - **Changed** - - - :pull:`456` - The behavior of some existing feature - - **Fixed** - - - :issue:`789` - Some really bad bug - -.. hint:: - - ``:issue:`` and ``:pull:`` refer to issue and pull request ticket numbers. - - -Release Process ---------------- - -Creating a release for ReactPy involves two steps: - -1. Tagging a version -2. Publishing a release - -To **tag a version** you'll run the following command: - -.. code-block:: bash - - nox -s tag -- - -Which will update the version for: - -- Python packages -- Javascript packages -- The changelog - -You'll be then prompted to confirm the auto-generated updates before those changes will -be staged, committed, and pushed along with a new tag matching ```` -which was specified earlier. - -Lastly, to **publish a release** `create one in GitHub -`__. -Because we pushed a tag using the command above, there should already be a saved tag you -can target when authoring the release. The release needs a title and description. The -title should simply be the version (same as the tag), and the description should simply -use GitHub's "Auto-generated release notes". - - -Other Core Repositories ------------------------ - -ReactPy depends on, or is used by several other core projects. For documentation on them +ReactPy has several external packages that can be installed to enhance your user experience. For documentation on them you should refer to their respective documentation in the links below: +- `reactpy-router `__ - ReactPy support for URL + routing - `reactpy-js-component-template `__ - Template repo for making :ref:`Custom Javascript Components`. -- `reactpy-flake8 `__ - Enforces the - :ref:`Rules of Hooks` -- `reactpy-jupyter `__ - ReactPy integration for - Jupyter -- `reactpy-dash `__ - ReactPy integration for Plotly - Dash - `reactpy-django `__ - ReactPy integration for Django +- `reactpy-jupyter `__ - ReactPy integration for + Jupyter .. Links .. ===== diff --git a/docs/source/guides/escape-hatches/distributing-javascript.rst b/docs/source/guides/escape-hatches/distributing-javascript.rst index 9eb478965..5333742ce 100644 --- a/docs/source/guides/escape-hatches/distributing-javascript.rst +++ b/docs/source/guides/escape-hatches/distributing-javascript.rst @@ -188,7 +188,7 @@ loaded with :func:`~reactpy.web.module.export`. .. note:: - When :data:`reactpy.config.REACTPY_DEBUG_MODE` is active, named exports will be validated. + When :data:`reactpy.config.REACTPY_DEBUG` is active, named exports will be validated. The remaining files that we need to create are concerned with creating a Python package. We won't cover all the details here, so refer to the Setuptools_ documentation for diff --git a/docs/source/guides/getting-started/_examples/run_starlette.py b/docs/source/guides/getting-started/_examples/run_starlette.py index 966b9ef77..47a08fb47 100644 --- a/docs/source/guides/getting-started/_examples/run_starlette.py +++ b/docs/source/guides/getting-started/_examples/run_starlette.py @@ -1,4 +1,4 @@ -# :lines: 11- +# :lines: 10- from reactpy import run from reactpy.backend import starlette as starlette_server diff --git a/docs/source/guides/getting-started/installing-reactpy.rst b/docs/source/guides/getting-started/installing-reactpy.rst index 0b2ffc28a..869dbcb02 100644 --- a/docs/source/guides/getting-started/installing-reactpy.rst +++ b/docs/source/guides/getting-started/installing-reactpy.rst @@ -101,14 +101,14 @@ For Development If you want to contribute to the development of ReactPy or modify it, you'll want to install a development version of ReactPy. This involves cloning the repository where ReactPy's -source is maintained, and setting up a :ref:`development environment`. From there you'll -be able to modifying ReactPy's source code and :ref:`run its tests ` to +source is maintained, and setting up a :ref:`Contributor Guide`. From there you'll +be able to modifying ReactPy's source code and :ref:`run its tests ` to ensure the modifications you've made are backwards compatible. If you want to add a new feature to ReactPy you should write your own test that validates its behavior. If you have questions about how to modify ReactPy or help with its development, be sure to :discussion:`start a discussion `. The ReactPy team are always -excited to :ref:`welcome ` new contributions and contributors +excited to welcome new contributions and contributors of all kinds .. card:: diff --git a/docs/source/guides/getting-started/running-reactpy.rst b/docs/source/guides/getting-started/running-reactpy.rst index 8abbd574f..90a03cbc3 100644 --- a/docs/source/guides/getting-started/running-reactpy.rst +++ b/docs/source/guides/getting-started/running-reactpy.rst @@ -103,7 +103,7 @@ Running ReactPy in Debug Mode ----------------------------- ReactPy provides a debug mode that is turned off by default. This can be enabled when you -run your application by setting the ``REACTPY_DEBUG_MODE`` environment variable. +run your application by setting the ``REACTPY_DEBUG`` environment variable. .. tab-set:: @@ -111,21 +111,21 @@ run your application by setting the ``REACTPY_DEBUG_MODE`` environment variable. .. code-block:: - export REACTPY_DEBUG_MODE=1 + export REACTPY_DEBUG=1 python my_reactpy_app.py .. tab-item:: Command Prompt .. code-block:: text - set REACTPY_DEBUG_MODE=1 + set REACTPY_DEBUG=1 python my_reactpy_app.py .. tab-item:: PowerShell .. code-block:: powershell - $env:REACTPY_DEBUG_MODE = "1" + $env:REACTPY_DEBUG = "1" python my_reactpy_app.py .. danger:: diff --git a/docs/source/reference/_examples/simple_dashboard.py b/docs/source/reference/_examples/simple_dashboard.py index 66913fc84..58a3e6fff 100644 --- a/docs/source/reference/_examples/simple_dashboard.py +++ b/docs/source/reference/_examples/simple_dashboard.py @@ -49,7 +49,7 @@ def RandomWalkGraph(mu, sigma): interval = use_interval(0.5) data, set_data = reactpy.hooks.use_state([{"x": 0, "y": 0}] * 50) - @reactpy.hooks.use_effect + @reactpy.hooks.use_async_effect async def animate(): await interval last_data_point = data[-1] diff --git a/docs/source/reference/_examples/snake_game.py b/docs/source/reference/_examples/snake_game.py index 36916410e..bb4bbb541 100644 --- a/docs/source/reference/_examples/snake_game.py +++ b/docs/source/reference/_examples/snake_game.py @@ -90,7 +90,7 @@ def on_direction_change(event): interval = use_interval(0.5) - @reactpy.hooks.use_effect + @reactpy.hooks.use_async_effect async def animate(): if new_game_state is not None: await asyncio.sleep(1) diff --git a/pyproject.toml b/pyproject.toml index 1745a3dfe..c756663c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,71 +1,256 @@ -# --- Project ---------------------------------------------------------------------------- +[build-system] +build-backend = "hatchling.build" +requires = ["hatchling", "hatch-build-scripts", "hatch"] + +############################## +# >>> Hatch Build Config <<< # +############################## [project] -name = "scripts" -version = "0.0.0" -description = "Scripts for managing the ReactPy repository" +name = "reactpy" +description = "It's React, but in Python." +readme = "README.md" +keywords = [ + "react", + "reactjs", + "reactpy", + "components", + "asgi", + "wsgi", + "website", + "interactive", + "reactive", + "javascript", + "server", +] +license = "MIT" +authors = [ + { name = "Mark Bakhit", email = "archiethemonger@gmail.com" }, + { name = "Ryan Morshead", email = "ryan.morshead@gmail.com" }, +] +requires-python = ">=3.11" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = ["fastjsonschema>=2.14.5", "requests>=2", "lxml>=4", "anyio>=3"] +dynamic = ["version"] +urls.Changelog = "https://reactpy.dev/docs/about/changelog.html" +urls.Documentation = "https://reactpy.dev/" +urls.Source = "https://github.com/reactive-python/reactpy" + +[project.optional-dependencies] +all = ["reactpy[asgi,jinja,testing]"] +asgi = ["asgiref", "asgi-tools", "servestatic", "orjson"] +jinja = ["jinja2-simple-tags", "jinja2>=3"] +testing = ["playwright", "uvicorn[standard]"] -# --- Hatch ---------------------------------------------------------------------------- +[tool.hatch.version] +path = "src/reactpy/__init__.py" + +[tool.hatch.build.targets.sdist] +include = ["/src"] +artifacts = ["/src/reactpy/static/"] + +[tool.hatch.build.targets.wheel] +artifacts = ["/src/reactpy/static/"] + +[tool.hatch.metadata] +license-files = { paths = ["LICENSE"] } [tool.hatch.envs.default] +installer = "uv" + +[project.scripts] +reactpy = "reactpy._console.cli:entry_point" + +[[tool.hatch.build.hooks.build-scripts.scripts]] +commands = [] +artifacts = [] + +############################# +# >>> Hatch Test Runner <<< # +############################# +[tool.hatch.envs.hatch-test.scripts] +run = [ + 'hatch --env default run "src/build_scripts/install_playwright.py"', + "hatch --env default run javascript:build --dev", + "hatch --env default build -t wheel", + "pytest{env:HATCH_TEST_ARGS:} {args} --max-worker-restart 10", +] +run-cov = [ + 'hatch --env default run "src/build_scripts/install_playwright.py"', + "hatch --env default run javascript:build --dev", + "hatch --env default build -t wheel", + 'hatch --env default run "src/build_scripts/delete_old_coverage.py"', + "coverage run -m pytest{env:HATCH_TEST_ARGS:} {args} --max-worker-restart 10", +] +cov-combine = "coverage combine" +cov-report = "coverage report" + +[tool.hatch.envs.hatch-test] +extra-dependencies = [ + "pytest-sugar", + "pytest-asyncio", + "pytest-timeout", + "responses", + "exceptiongroup", + "jsonpointer", + "starlette", +] +features = ["all"] + +[[tool.hatch.envs.hatch-test.matrix]] +python = ["3.11", "3.12", "3.13", "3.14"] + +[tool.pytest.ini_options] +addopts = ["--strict-config", "--strict-markers"] +filterwarnings = """ + ignore::DeprecationWarning:uvicorn.* + ignore::DeprecationWarning:websockets.* + ignore::UserWarning:tests.test_core.test_vdom + ignore::UserWarning:tests.test_pyscript.test_components + ignore::UserWarning:tests.test_utils +""" +testpaths = "tests" +xfail_strict = true +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" +asyncio_default_test_loop_scope = "session" +log_cli_level = "INFO" +timeout = 120 + +####################################### +# >>> Hatch Documentation Scripts <<< # +####################################### +[tool.hatch.envs.docs] +template = "docs" +dependencies = ["poetry"] detached = true -dependencies = [ - "invoke", - # lint - "black==24.1.1", # Pin lint tools we don't control to avoid breaking changes - "ruff==0.0.278", # Pin lint tools we don't control to avoid breaking changes - "toml", - "flake8==7.0.0", # Pin lint tools we don't control to avoid breaking changes - "flake8-pyproject", - # types - "mypy", - "types-toml", - # publish - "semver >=2, <3", - "twine", - "pre-commit", + +[tool.hatch.envs.docs.scripts] +build = [ + "cd docs && poetry install", + "cd docs && poetry run sphinx-build -a -T -W --keep-going -b doctest source build", +] +docker_build = [ + "hatch run docs:build", + "docker build . --file ./docs/Dockerfile --tag reactpy-docs:latest", +] +docker_serve = [ + "hatch run docs:docker_build", + "docker run --rm -p 5000:5000 reactpy-docs:latest", +] +check = [ + "cd docs && poetry install", + "cd docs && poetry run sphinx-build -a -T -W --keep-going -b doctest source build", + "docker build . --file ./docs/Dockerfile", +] +serve = [ + "cd docs && poetry install", + "cd docs && poetry run python main.py --watch=../src/ --ignore=**/_auto/* --ignore=**/custom.js --ignore=**/node_modules/* --ignore=**/package-lock.json -a -E -b html source build", ] -[tool.hatch.envs.default.scripts] -publish = "invoke publish {args}" -docs = "invoke docs {args}" -check = ["lint-py", "lint-js", "test-py", "test-js", "test-docs"] +################################ +# >>> Hatch Python Scripts <<< # +################################ -lint = ["lint-py", "lint-js"] -lint-py = "invoke lint-py {args}" -lint-js = "invoke lint-js {args}" +[tool.hatch.envs.python] +extra-dependencies = [ + "reactpy[all]", + "pyright", + "types-toml", + "types-click", + "types-requests", + "types-lxml", + "jsonpointer", + "pytest", +] -test = ["test-py", "test-js", "test-docs"] -test-py = "invoke test-py {args}" -test-js = "invoke test-js" -test-docs = "invoke test-docs" +[tool.hatch.envs.python.scripts] +type_check = ["pyright src/reactpy"] -# --- Black ---------------------------------------------------------------------------- +############################ +# >>> Hatch JS Scripts <<< # +############################ -[tool.black] -target-version = ["py39"] -line-length = 88 +[tool.hatch.envs.javascript] +detached = true -# --- MyPy ----------------------------------------------------------------------------- +[tool.hatch.envs.javascript.scripts] +check = [ + 'hatch run javascript:build', + 'bun run --cwd "src/js" lint', + 'bun run --cwd "src/js/packages/event-to-object" checkTypes', + 'bun run --cwd "src/js/packages/@reactpy/client" checkTypes', + 'bun run --cwd "src/js/packages/@reactpy/app" checkTypes', +] +fix = ['bun install --cwd "src/js"', 'bun run --cwd "src/js" format'] +test = ['hatch run javascript:build_event_to_object --dev', 'bun test'] +build = [ + 'hatch run "src/build_scripts/clean_js_dir.py"', + 'bun install --cwd "src/js"', + 'hatch run javascript:build_event_to_object {args}', + 'hatch run javascript:build_client {args}', + 'hatch run javascript:build_app {args}', + 'hatch --env default run "src/build_scripts/copy_dir.py" "src/js/node_modules/@pyscript/core/dist" "src/reactpy/static/pyscript"', + 'hatch --env default run "src/build_scripts/copy_dir.py" "src/js/node_modules/morphdom/dist" "src/reactpy/static/morphdom"', -[tool.mypy] -ignore_missing_imports = true -warn_unused_configs = true -warn_redundant_casts = true -warn_unused_ignores = true +] +build_event_to_object = [ + 'hatch run "src/build_scripts/build_js_event_to_object.py" {args}', +] +build_client = ['hatch run "src/build_scripts/build_js_client.py" {args}'] +build_app = ['hatch run "src/build_scripts/build_js_app.py" {args}'] +publish_event_to_object = [ + 'hatch run javascript:build_event_to_object', + 'cd "src/js/packages/event-to-object" && bun publish --access public', +] +publish_client = [ + 'hatch run javascript:build_client', + 'cd "src/js/packages/@reactpy/client" && bun publish --access public', +] -# --- Flake8 --------------------------------------------------------------------------- +######################### +# >>> Generic Tools <<< # +######################### -[tool.flake8] -select = ["RPY"] # only need to check with reactpy-flake8 -exclude = ["**/node_modules/*", ".eggs/*", ".tox/*", "**/venv/*"] +[tool.pyright] +reportIncompatibleVariableOverride = false -# --- Ruff ----------------------------------------------------------------------------- +[tool.coverage.run] +source_pkgs = ["reactpy"] +branch = false +parallel = false +omit = [ + "src/reactpy/__init__.py", + "src/reactpy/_console/*", + "src/reactpy/__main__.py", + "src/reactpy/executors/pyscript/layout_handler.py", + "src/reactpy/executors/pyscript/component_template.py", +] + +[tool.coverage.report] +fail_under = 100 +show_missing = true +skip_covered = true +sort = "Name" +exclude_also = [ + "no ?cov", + '\.\.\.', + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] [tool.ruff] -target-version = "py39" line-length = 88 -select = [ +lint.select = [ "A", "ARG", "B", @@ -79,7 +264,6 @@ select = [ # "FBT", "I", "ICN", - "ISC", "N", "PLC", "PLE", @@ -94,7 +278,7 @@ select = [ "W", "YTT", ] -ignore = [ +lint.ignore = [ # TODO: turn this on later "N802", "N806", # allow TitleCase functions/variables @@ -127,19 +311,19 @@ ignore = [ "PLR0912", "PLR0913", "PLR0915", + # Allow imports anywhere + "PLC0415", ] -unfixable = [ +lint.unfixable = [ # Don't touch unused imports "F401", ] -[tool.ruff.isort] +[tool.ruff.lint.isort] known-first-party = ["reactpy"] +known-third-party = ["js"] -[tool.ruff.flake8-tidy-imports] -ban-relative-imports = "all" - -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] # Tests can use magic values, assertions, and relative imports "**/tests/**/*" = ["PLR2004", "S101", "TID252"] "docs/**/*.py" = [ diff --git a/src/build_scripts/build_js_app.py b/src/build_scripts/build_js_app.py new file mode 100644 index 000000000..36bc73f85 --- /dev/null +++ b/src/build_scripts/build_js_app.py @@ -0,0 +1,29 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// +import pathlib +import subprocess +import sys + +dev_mode = "--dev" in sys.argv +root_dir = pathlib.Path(__file__).parent.parent.parent +build_commands = [ + [ + "bun", + "install", + "--cwd", + "src/js/packages/@reactpy/app", + ], + [ + "bun", + "run", + "--cwd", + "src/js/packages/@reactpy/app", + "buildDev" if dev_mode else "build", + ], +] + +for command in build_commands: + print(f"Running command: '{command}'...") # noqa: T201 + subprocess.run(command, check=True, cwd=root_dir) # noqa: S603 diff --git a/src/build_scripts/build_js_client.py b/src/build_scripts/build_js_client.py new file mode 100644 index 000000000..5fab9440d --- /dev/null +++ b/src/build_scripts/build_js_client.py @@ -0,0 +1,29 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// +import pathlib +import subprocess +import sys + +dev_mode = "--dev" in sys.argv +root_dir = pathlib.Path(__file__).parent.parent.parent +build_commands = [ + [ + "bun", + "install", + "--cwd", + "src/js/packages/@reactpy/client", + ], + [ + "bun", + "run", + "--cwd", + "src/js/packages/@reactpy/client", + "build", + ], +] + +for command in build_commands: + print(f"Running command: '{command}'...") # noqa: T201 + subprocess.run(command, check=True, cwd=root_dir) # noqa: S603 diff --git a/src/build_scripts/build_js_event_to_object.py b/src/build_scripts/build_js_event_to_object.py new file mode 100644 index 000000000..88f4af64f --- /dev/null +++ b/src/build_scripts/build_js_event_to_object.py @@ -0,0 +1,29 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// +import pathlib +import subprocess +import sys + +dev_mode = "--dev" in sys.argv +root_dir = pathlib.Path(__file__).parent.parent.parent +build_commands = [ + [ + "bun", + "install", + "--cwd", + "src/js/packages/event-to-object", + ], + [ + "bun", + "run", + "--cwd", + "src/js/packages/event-to-object", + "build", + ], +] + +for command in build_commands: + print(f"Running command: '{command}'...") # noqa: T201 + subprocess.run(command, check=True, cwd=root_dir) # noqa: S603 diff --git a/src/build_scripts/clean_js_dir.py b/src/build_scripts/clean_js_dir.py new file mode 100644 index 000000000..f6b2b000f --- /dev/null +++ b/src/build_scripts/clean_js_dir.py @@ -0,0 +1,44 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// + +# Deletes `dist`, `node_modules`, and `tsconfig.tsbuildinfo` from all JS packages in the JS source directory. + +import contextlib +import glob +import os +import pathlib +import shutil + +print("Cleaning JS source directory...") # noqa: T201 + +# Get the path to the JS source directory +js_src_dir = pathlib.Path(__file__).parent.parent / "js" +static_output_dir = pathlib.Path(__file__).parent.parent / "reactpy" / "static" + +# Delete all `dist` folders +dist_dirs = glob.glob(str(js_src_dir / "**/dist"), recursive=True) +for dist_dir in dist_dirs: + with contextlib.suppress(FileNotFoundError): + shutil.rmtree(dist_dir) + +# Delete all `node_modules` folders +node_modules_dirs = glob.glob(str(js_src_dir / "**/node_modules"), recursive=True) +for node_modules_dir in node_modules_dirs: + with contextlib.suppress(FileNotFoundError): + shutil.rmtree(node_modules_dir) + +# Delete all `tsconfig.tsbuildinfo` files +tsconfig_tsbuildinfo_files = glob.glob( + str(js_src_dir / "**/tsconfig.tsbuildinfo"), recursive=True +) +for tsconfig_tsbuildinfo_file in tsconfig_tsbuildinfo_files: + with contextlib.suppress(FileNotFoundError): + os.remove(tsconfig_tsbuildinfo_file) + +# Delete all `index-*.js` files +index_js_files = glob.glob(str(static_output_dir / "index-*.js*")) +for index_js_file in index_js_files: + with contextlib.suppress(FileNotFoundError): + os.remove(index_js_file) diff --git a/src/build_scripts/copy_dir.py b/src/build_scripts/copy_dir.py new file mode 100644 index 000000000..64910e6fa --- /dev/null +++ b/src/build_scripts/copy_dir.py @@ -0,0 +1,40 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// + +import logging +import shutil +import sys +from pathlib import Path + + +def copy_files(source: Path, destination: Path) -> None: + if destination.exists(): + shutil.rmtree(destination) + destination.mkdir() + + for file in source.iterdir(): + if file.is_file(): + shutil.copy(file, destination / file.name) + else: + copy_files(file, destination / file.name) + + +if __name__ == "__main__": + if len(sys.argv) != 3: # noqa + logging.error( + "Script used incorrectly!\nUsage: python copy_dir.py " + ) + sys.exit(1) + + root_dir = Path(__file__).parent.parent.parent + src = Path(root_dir / sys.argv[1]) + dest = Path(root_dir / sys.argv[2]) + print(f"Copying files from '{sys.argv[1]}' to '{sys.argv[2]}'...") # noqa: T201 + + if not src.exists(): + logging.error("Source directory %s does not exist", src) + sys.exit(1) + + copy_files(src, dest) diff --git a/src/build_scripts/delete_old_coverage.py b/src/build_scripts/delete_old_coverage.py new file mode 100644 index 000000000..341eadfb1 --- /dev/null +++ b/src/build_scripts/delete_old_coverage.py @@ -0,0 +1,21 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// + +import logging +from glob import glob +from pathlib import Path + +# Delete old `.coverage*` files in the project root +print("Deleting old coverage files...") # noqa: T201 +root_dir = Path(__file__).parent.parent.parent +coverage_files = glob(str(root_dir / ".coverage*")) + +for path in coverage_files: + coverage_file = Path(path) + if coverage_file.exists(): + try: + coverage_file.unlink() + except Exception as e: + logging.error(f"Failed to delete {coverage_file}: {e}") diff --git a/src/build_scripts/install_playwright.py b/src/build_scripts/install_playwright.py new file mode 100644 index 000000000..d8d9cee70 --- /dev/null +++ b/src/build_scripts/install_playwright.py @@ -0,0 +1,17 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [] +# /// + +import subprocess + +print("Installing Playwright browsers...") # noqa: T201 + +# Install Chromium browser for Playwright, and fail if it cannot be installed +subprocess.run(["playwright", "install", "chromium"], check=True) # noqa: S607 + +# Try to install system dependencies. We don't generate an exception if this fails +# as *nix systems (such as WSL) return a failure code if there are *any* dependencies +# that could be cleaned up via `sudo apt autoremove`. This occurs even if we weren't +# the ones to install those dependencies in the first place. +subprocess.run(["playwright", "install-deps", "chromium"], check=False) # noqa: S607 diff --git a/src/js/.eslintrc.json b/src/js/.eslintrc.json deleted file mode 100644 index 8536da62b..000000000 --- a/src/js/.eslintrc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "env": { - "browser": true, - "node": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended" - ], - "overrides": [], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": ["react", "@typescript-eslint"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-empty-function": "off", - "react/prop-types": "off" - }, - "settings": { - "react": { - "version": "detect" - } - } -} diff --git a/src/js/.gitignore b/src/js/.gitignore index fedd7ea26..42f1aa542 100644 --- a/src/js/.gitignore +++ b/src/js/.gitignore @@ -1,3 +1,5 @@ tsconfig.tsbuildinfo packages/**/package-lock.json -dist +**/dist/* +node_modules +*.tgz diff --git a/src/js/README.md b/src/js/README.md deleted file mode 100644 index e99df49c0..000000000 --- a/src/js/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ReactPy Client - -An ES6 Javascript client for ReactPy diff --git a/src/js/app/.eslintrc.json b/src/js/app/.eslintrc.json deleted file mode 100644 index 442025c3d..000000000 --- a/src/js/app/.eslintrc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended" - ], - "overrides": [], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": ["react", "@typescript-eslint"], - "rules": {} -} diff --git a/src/js/app/index.html b/src/js/app/index.html deleted file mode 100644 index e94280368..000000000 --- a/src/js/app/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - {__head__} - - -
- - diff --git a/src/js/app/package-lock.json b/src/js/app/package-lock.json deleted file mode 100644 index 5af5f0fd8..000000000 --- a/src/js/app/package-lock.json +++ /dev/null @@ -1,1193 +0,0 @@ -{ - "name": "ui", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "license": "MIT", - "dependencies": { - "@reactpy/client": "^0.2.0", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5", - "vite": "^3.2.11" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@reactpy/client": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@reactpy/client/-/client-0.2.1.tgz", - "integrity": "sha512-9sgGH+pJ2BpLT+QSVe7FQLS2VQ9acHgPlO8X3qiTumGw43O0X82sm8pzya8H8dAew463SeGza/pZc0mpUBHmqA==", - "dependencies": { - "event-to-object": "^0.1.2", - "json-pointer": "^0.6.2" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "17.0.57", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.57.tgz", - "integrity": "sha512-e4msYpu5QDxzNrXDHunU/VPyv2M1XemGG/p7kfCjUiPtlLDCWLGQfgAMng6YyisWYxZ09mYdQlmMnyS0NfZdEg==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", - "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, - "dependencies": { - "@types/react": "^17" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/event-to-object": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/event-to-object/-/event-to-object-0.1.2.tgz", - "integrity": "sha512-+fUmp1XOCZiYomwe5Zxp4IlchuZZfdVdjFUk5MbgRT4M+V2TEWKc0jJwKLCX/nxlJ6xM5VUb/ylzERh7YDCRrg==", - "dependencies": { - "json-pointer": "^0.6.2" - } - }, - "node_modules/foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" - }, - "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==", - "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==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "peer": true - }, - "node_modules/json-pointer": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", - "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", - "dependencies": { - "foreach": "^2.0.4" - } - }, - "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==", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "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==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/preact": { - "version": "10.13.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.2.tgz", - "integrity": "sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.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/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - } - }, - "dependencies": { - "@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "dev": true, - "optional": true - }, - "@reactpy/client": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@reactpy/client/-/client-0.2.1.tgz", - "integrity": "sha512-9sgGH+pJ2BpLT+QSVe7FQLS2VQ9acHgPlO8X3qiTumGw43O0X82sm8pzya8H8dAew463SeGza/pZc0mpUBHmqA==", - "requires": { - "event-to-object": "^0.1.2", - "json-pointer": "^0.6.2" - } - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "@types/react": { - "version": "17.0.57", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.57.tgz", - "integrity": "sha512-e4msYpu5QDxzNrXDHunU/VPyv2M1XemGG/p7kfCjUiPtlLDCWLGQfgAMng6YyisWYxZ09mYdQlmMnyS0NfZdEg==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", - "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, - "requires": { - "@types/react": "^17" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, - "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, - "esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "dev": true, - "optional": true - }, - "event-to-object": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/event-to-object/-/event-to-object-0.1.2.tgz", - "integrity": "sha512-+fUmp1XOCZiYomwe5Zxp4IlchuZZfdVdjFUk5MbgRT4M+V2TEWKc0jJwKLCX/nxlJ6xM5VUb/ylzERh7YDCRrg==", - "requires": { - "json-pointer": "^0.6.2" - } - }, - "foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" - }, - "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==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true - }, - "json-pointer": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", - "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", - "requires": { - "foreach": "^2.0.4" - } - }, - "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==", - "peer": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true - }, - "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==", - "peer": 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==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "requires": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "preact": { - "version": "10.13.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.2.tgz", - "integrity": "sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw==" - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "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==", - "dev": true - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true - }, - "vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", - "dev": true, - "requires": { - "esbuild": "^0.15.9", - "fsevents": "~2.3.2", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - } - } - } -} diff --git a/src/js/app/package.json b/src/js/app/package.json deleted file mode 100644 index f3b7a1cf7..000000000 --- a/src/js/app/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "author": "Ryan Morshead", - "license": "MIT", - "main": "src/dist/index.js", - "types": "src/dist/index.d.ts", - "description": "Main entry point for ReactPy.", - "dependencies": { - "@reactpy/client": "file:../packages/@reactpy/client", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5", - "vite": "^3.2.11" - }, - "repository": { - "type": "git", - "url": "https://github.com/reactive-python/reactpy" - }, - "scripts": { - "build": "vite build", - "format": "prettier --write . && eslint --fix .", - "test": "npm run check:tests", - "check:tests": "echo 'no tests'", - "check:types": "tsc --noEmit" - } -} diff --git a/src/js/app/public/assets/reactpy-logo.ico b/src/js/app/public/assets/reactpy-logo.ico deleted file mode 100644 index 62be5f5ba..000000000 Binary files a/src/js/app/public/assets/reactpy-logo.ico and /dev/null differ diff --git a/src/js/app/src/index.ts b/src/js/app/src/index.ts deleted file mode 100644 index 1f47853aa..000000000 --- a/src/js/app/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { mount, SimpleReactPyClient } from "@reactpy/client"; - -export function app(element: HTMLElement) { - const client = new SimpleReactPyClient({ - serverLocation: { - url: document.location.origin, - route: document.location.pathname, - query: document.location.search, - }, - }); - mount(element, client); -} diff --git a/src/js/app/vite.config.js b/src/js/app/vite.config.js deleted file mode 100644 index 64a015757..000000000 --- a/src/js/app/vite.config.js +++ /dev/null @@ -1,13 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - build: { emptyOutDir: true }, - resolve: { - alias: { - react: "preact/compat", - "react-dom": "preact/compat", - }, - preserveSymlinks: true, - }, - base: "/_reactpy/", -}); diff --git a/src/js/bun.lockb b/src/js/bun.lockb new file mode 100644 index 000000000..99af1eb11 Binary files /dev/null and b/src/js/bun.lockb differ diff --git a/src/js/eslint.config.mjs b/src/js/eslint.config.mjs new file mode 100644 index 000000000..12494f73d --- /dev/null +++ b/src/js/eslint.config.mjs @@ -0,0 +1,25 @@ +import { default as eslint } from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + { ignores: ["**/node_modules/", "**/dist/"] }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + ecmaVersion: "latest", + sourceType: "module", + }, + rules: { + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-empty-function": "off", + }, + }, +]; diff --git a/src/js/package-lock.json b/src/js/package-lock.json deleted file mode 100644 index 924f59171..000000000 --- a/src/js/package-lock.json +++ /dev/null @@ -1,5989 +0,0 @@ -{ - "name": "js", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "license": "MIT", - "workspaces": [ - "packages/event-to-object", - "packages/@reactpy/client", - "app" - ], - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.58.0", - "@typescript-eslint/parser": "^5.58.0", - "eslint": "^8.38.0", - "eslint-plugin-react": "^7.32.2", - "prettier": "^3.0.0-alpha.6" - } - }, - "app": { - "license": "MIT", - "dependencies": { - "@reactpy/client": "file:../packages/@reactpy/client", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5", - "vite": "^3.2.11" - } - }, - "app/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" - } - }, - "apps/ui": { - "extraneous": true, - "license": "MIT", - "dependencies": { - "@reactpy/client": "^0.2.0", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "prettier": "^3.0.0-alpha.6", - "typescript": "^4.9.5", - "vite": "^3.1.8" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "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/js": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", - "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "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/@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/@reactpy/client": { - "resolved": "packages/@reactpy/client", - "link": true - }, - "node_modules/@types/json-pointer": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/@types/json-pointer/-/json-pointer-1.0.31.tgz", - "integrity": "sha512-hTPul7Um6LqsHXHQpdkXTU7Oysjsf+9k4Yfmg6JhSKG/jj9QuQGyMUdj6trPH6WHiIdxw7nYSROgOxeFmCVK2w==", - "dev": true - }, - "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/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "17.0.53", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", - "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", - "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, - "dependencies": { - "@types/react": "^17" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "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/@typescript-eslint/eslint-plugin": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", - "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/type-utils": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz", - "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", - "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.58.0", - "@typescript-eslint/utils": "5.58.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz", - "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "eslint-scope": "^5.1.1", - "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/utils/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/@typescript-eslint/utils/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/@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.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/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/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/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/app": { - "resolved": "app", - "link": 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-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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.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/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/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "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/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "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/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==", - "dev": true, - "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==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "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/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "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.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "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/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "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/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/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "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.5", - "is-array-buffer": "^3.0.2", - "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.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "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/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", - "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.38.0", - "@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-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "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", - "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-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/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.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "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-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "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/event-to-object": { - "resolved": "packages/event-to-object", - "link": true - }, - "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==", - "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/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.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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-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/foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" - }, - "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==", - "dev": true - }, - "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==", - "dev": true - }, - "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/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/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, - "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": "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/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/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/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/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/happy-dom": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-8.9.0.tgz", - "integrity": "sha512-JZwJuGdR7ko8L61136YzmrLv7LgTh5b8XaEM3P709mLjyQuXJ3zHTDXvUtBBahRjGlcYW0zGjIiEWizoTUGKfA==", - "dev": true, - "dependencies": { - "css.escape": "^1.5.1", - "he": "^1.2.0", - "iconv-lite": "^0.6.3", - "node-fetch": "^2.x.x", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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/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/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==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "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/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==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "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==", - "dev": true, - "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==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "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-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==", - "dev": true, - "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-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-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-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-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-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==", - "dev": true - }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "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==" - }, - "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/json-pointer": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", - "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", - "dependencies": { - "foreach": "^2.0.4" - } - }, - "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/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/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/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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/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==", - "dev": true - }, - "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/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==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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/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/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/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "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/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "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==", - "dev": true, - "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/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "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/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/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/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==", - "dev": true, - "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==", - "dev": true - }, - "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/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "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/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/preact": { - "version": "10.15.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.15.1.tgz", - "integrity": "sha512-qs2ansoQEwzNiV5eAcRT1p1EC/dmEzaATVDJNiB3g2sRDWdA7b7MurXdJjB2+/WQktGWZwxvDrnuRFbWuIr64g==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "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": "3.0.0-alpha.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0-alpha.6.tgz", - "integrity": "sha512-AdbQSZ6Oo+iy9Ekzmsgno05P1uX2vqPkjOMJqRfP8hTe+m6iDw4Nt7bPFpWZ/HYCU+3f0P5U0o2ghxQwwkLH7A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "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/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "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/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/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.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/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==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "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/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/semver": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", - "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "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/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/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "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/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==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/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/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "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/tsm": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.3.0.tgz", - "integrity": "sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==", - "dev": true, - "dependencies": { - "esbuild": "^0.15.16" - }, - "bin": { - "tsm": "bin.js" - }, - "engines": { - "node": ">=12" - } - }, - "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/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-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/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/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "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/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", - "dev": true, - "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - }, - "bin": { - "uvu": "bin.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "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==", - "dev": true, - "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/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "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" - } - }, - "packages/@reactpy/client": { - "version": "0.3.2", - "license": "MIT", - "dependencies": { - "event-to-object": "file:../event-to-object", - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "packages/@reactpy/client/node_modules/event-to-object": { - "resolved": "packages/@reactpy/event-to-object", - "link": true - }, - "packages/@reactpy/client/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" - } - }, - "packages/@reactpy/event-to-object": {}, - "packages/app": { - "name": "@reactpy/app", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@reactpy/client": "^0.1.0", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "prettier": "^3.0.0-alpha.6", - "typescript": "^4.9.5", - "vite": "^3.1.8" - } - }, - "packages/client": { - "name": "@reactpy/client", - "version": "0.2.0", - "extraneous": true, - "license": "MIT", - "dependencies": { - "event-to-object": "^0.1.0", - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "prettier": "^3.0.0-alpha.6", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" - } - }, - "packages/event-to-object": { - "version": "0.1.2", - "license": "MIT", - "dependencies": { - "json-pointer": "^0.6.2" - }, - "devDependencies": { - "happy-dom": "^8.9.0", - "lodash": "^4.17.21", - "tsm": "^2.0.0", - "typescript": "^4.9.5", - "uvu": "^0.5.1" - } - }, - "packages/event-to-object/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" - } - }, - "packages/event-to-object/packages/event-to-object": { - "extraneous": true - }, - "ui": { - "extraneous": true, - "license": "MIT", - "dependencies": { - "@reactpy/client": "^0.2.0", - "preact": "^10.7.0" - }, - "devDependencies": { - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5", - "vite": "^3.1.8" - } - } - }, - "dependencies": { - "@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "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" - } - }, - "@eslint/js": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", - "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", - "dev": true - }, - "@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 - }, - "@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" - } - }, - "@reactpy/client": { - "version": "file:packages/@reactpy/client", - "requires": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "event-to-object": "file:../event-to-object", - "json-pointer": "^0.6.2", - "typescript": "^4.9.5" - }, - "dependencies": { - "event-to-object": { - "version": "file:packages/@reactpy/event-to-object" - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true - } - } - }, - "@types/json-pointer": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/@types/json-pointer/-/json-pointer-1.0.31.tgz", - "integrity": "sha512-hTPul7Um6LqsHXHQpdkXTU7Oysjsf+9k4Yfmg6JhSKG/jj9QuQGyMUdj6trPH6WHiIdxw7nYSROgOxeFmCVK2w==", - "dev": true - }, - "@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/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "@types/react": { - "version": "17.0.53", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", - "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", - "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, - "requires": { - "@types/react": "^17" - } - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "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 - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", - "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/type-utils": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz", - "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", - "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.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.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz", - "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "dependencies": { - "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" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "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": {} - }, - "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": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "app": { - "version": "file:app", - "requires": { - "@reactpy/client": "file:../packages/@reactpy/client", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "preact": "^10.7.0", - "typescript": "^4.9.5", - "vite": "^3.2.11" - }, - "dependencies": { - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "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-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "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.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" - } - }, - "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 - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "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 - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.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==", - "dev": true, - "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==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "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" - } - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "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" - } - }, - "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" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "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.5", - "is-array-buffer": "^3.0.2", - "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.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "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" - } - }, - "esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "dev": true, - "optional": true - }, - "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.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", - "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.38.0", - "@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-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "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", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "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" - } - }, - "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true - }, - "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "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 - }, - "event-to-object": { - "version": "file:packages/event-to-object", - "requires": { - "happy-dom": "^8.9.0", - "json-pointer": "^0.6.2", - "lodash": "^4.17.21", - "tsm": "^2.0.0", - "typescript": "^4.9.5", - "uvu": "^0.5.1" - }, - "dependencies": { - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true - } - } - }, - "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==", - "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" - } - }, - "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.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "requires": { - "to-regex-range": "^5.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-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" - } - }, - "foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "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==", - "dev": true - }, - "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" - } - }, - "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 - }, - "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, - "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": "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": "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" - } - }, - "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" - } - }, - "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 - }, - "happy-dom": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-8.9.0.tgz", - "integrity": "sha512-JZwJuGdR7ko8L61136YzmrLv7LgTh5b8XaEM3P709mLjyQuXJ3zHTDXvUtBBahRjGlcYW0zGjIiEWizoTUGKfA==", - "dev": true, - "requires": { - "css.escape": "^1.5.1", - "he": "^1.2.0", - "iconv-lite": "^0.6.3", - "node-fetch": "^2.x.x", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "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==", - "dev": true - }, - "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==", - "dev": true - }, - "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" - } - }, - "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 - }, - "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==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "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==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "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==", - "dev": true - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "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-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==", - "dev": true, - "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-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-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-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-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-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==", - "dev": true - }, - "js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "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==" - }, - "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" - } - }, - "json-pointer": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", - "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", - "requires": { - "foreach": "^2.0.4" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true - }, - "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" - } - }, - "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==", - "dev": true - }, - "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 - }, - "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==", - "requires": { - "js-tokens": "^3.0.0 || ^4.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==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "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 - }, - "node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, - "requires": { - "whatwg-url": "^5.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==", - "dev": true - }, - "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" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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==", - "dev": true - }, - "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==", - "dev": true - }, - "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 - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "requires": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "preact": { - "version": "10.15.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.15.1.tgz", - "integrity": "sha512-qs2ansoQEwzNiV5eAcRT1p1EC/dmEzaATVDJNiB3g2sRDWdA7b7MurXdJjB2+/WQktGWZwxvDrnuRFbWuIr64g==" - }, - "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": "3.0.0-alpha.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0-alpha.6.tgz", - "integrity": "sha512-AdbQSZ6Oo+iy9Ekzmsgno05P1uX2vqPkjOMJqRfP8hTe+m6iDw4Nt7bPFpWZ/HYCU+3f0P5U0o2ghxQwwkLH7A==", - "dev": true - }, - "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" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "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 - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "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 - }, - "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" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "requires": { - "is-core-module": "^2.11.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 - }, - "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==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "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" - } - }, - "sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "requires": { - "mri": "^1.1.0" - } - }, - "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==", - "dev": true - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "semver": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", - "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "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 - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "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.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.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==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "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==", - "dev": true, - "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==", - "dev": true - }, - "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 - }, - "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" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsm": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.3.0.tgz", - "integrity": "sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==", - "dev": true, - "requires": { - "esbuild": "^0.15.16" - } - }, - "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" - } - }, - "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-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 - }, - "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" - } - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "peer": true - }, - "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" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", - "dev": true, - "requires": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - } - }, - "vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", - "dev": true, - "requires": { - "esbuild": "^0.15.9", - "fsevents": "~2.3.2", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - } - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "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" - } - }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "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/src/js/package.json b/src/js/package.json index a9d84814b..24c53fc70 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -1,26 +1,30 @@ { - "license": "MIT", - "scripts": { - "publish": "npm --workspaces publish", - "test": "npm --workspaces test", - "build": "npm --workspaces run build", - "fix:format": "npm run prettier -- --write && npm run eslint -- --fix", - "check:format": "npm run prettier -- --check && npm run eslint", - "check:tests": "npm --workspaces run check:tests", - "check:types": "npm --workspaces run check:types", - "prettier": "prettier --ignore-path .gitignore .", - "eslint": "eslint --ignore-path .gitignore ." - }, "workspaces": [ "packages/event-to-object", - "packages/@reactpy/client", - "app" + "packages/@reactpy/app", + "packages/@reactpy/client" ], + "catalog": { + "preact": "^10.27.2", + "@pyscript/core": "^0.7.11", + "morphdom": "^2.7.7", + "typescript": "^5.9.3", + "json-pointer": "^0.6.2", + "@types/json-pointer": "^1.0.34", + "@reactpy/client": "file:./packages/@reactpy/client", + "event-to-object": "^1.0.1" + }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.58.0", - "@typescript-eslint/parser": "^5.58.0", - "eslint": "^8.38.0", - "eslint-plugin-react": "^7.32.2", - "prettier": "^3.0.0-alpha.6" + "@eslint/js": "^9.39.1", + "bun-types": "^1.3.3", + "eslint": "^9.39.1", + "globals": "^16.5.0", + "prettier": "^3.6.2", + "typescript-eslint": "^8.47.0" + }, + "license": "MIT", + "scripts": { + "format": "prettier --write . && eslint --fix", + "lint": "prettier --check . && eslint" } } diff --git a/src/js/packages/@reactpy/app/bun.lockb b/src/js/packages/@reactpy/app/bun.lockb new file mode 100644 index 000000000..5c921795b Binary files /dev/null and b/src/js/packages/@reactpy/app/bun.lockb differ diff --git a/src/js/packages/@reactpy/app/package.json b/src/js/packages/@reactpy/app/package.json new file mode 100644 index 000000000..55c11ec50 --- /dev/null +++ b/src/js/packages/@reactpy/app/package.json @@ -0,0 +1,20 @@ +{ + "dependencies": { + "@reactpy/client": "catalog:", + "event-to-object": "catalog:", + "preact": "catalog:" + }, + "description": "ReactPy's client-side entry point. This is strictly for internal use and is not designed to be distributed.", + "devDependencies": { + "@pyscript/core": "catalog:", + "morphdom": "catalog:", + "typescript": "catalog:" + }, + "license": "MIT", + "name": "@reactpy/app", + "scripts": { + "build": "bun build \"src/index.ts\" \"src/preact.ts\" \"src/preact-dom.ts\" \"src/preact-jsx-runtime.ts\" --outdir=\"../../../../reactpy/static/\" --minify --production --sourcemap=\"linked\" --splitting", + "buildDev": "bun build \"src/index.ts\" \"src/preact.ts\" \"src/preact-dom.ts\" \"src/preact-jsx-runtime.ts\" --outdir=\"../../../../reactpy/static/\" --sourcemap=\"linked\" --splitting", + "checkTypes": "tsc --noEmit" + } +} diff --git a/src/js/packages/@reactpy/app/src/index.ts b/src/js/packages/@reactpy/app/src/index.ts new file mode 100644 index 000000000..55ebf2c10 --- /dev/null +++ b/src/js/packages/@reactpy/app/src/index.ts @@ -0,0 +1 @@ +export { mountReactPy } from "@reactpy/client"; diff --git a/src/js/packages/@reactpy/app/src/preact-dom.ts b/src/js/packages/@reactpy/app/src/preact-dom.ts new file mode 100644 index 000000000..17d1e16f1 --- /dev/null +++ b/src/js/packages/@reactpy/app/src/preact-dom.ts @@ -0,0 +1,9 @@ +import ReactDOM from "preact/compat"; + +// @ts-ignore +export * from "preact/compat"; + +// @ts-ignore +export * from "preact/compat/client"; + +export default ReactDOM; diff --git a/src/js/packages/@reactpy/app/src/preact-jsx-runtime.ts b/src/js/packages/@reactpy/app/src/preact-jsx-runtime.ts new file mode 100644 index 000000000..76af78105 --- /dev/null +++ b/src/js/packages/@reactpy/app/src/preact-jsx-runtime.ts @@ -0,0 +1 @@ +export * from "preact/compat/jsx-runtime"; diff --git a/src/js/packages/@reactpy/app/src/preact.ts b/src/js/packages/@reactpy/app/src/preact.ts new file mode 100644 index 000000000..21f104942 --- /dev/null +++ b/src/js/packages/@reactpy/app/src/preact.ts @@ -0,0 +1,6 @@ +import React from "preact/compat"; + +// @ts-ignore +export * from "preact/compat"; + +export default React; diff --git a/src/js/app/tsconfig.json b/src/js/packages/@reactpy/app/tsconfig.json similarity index 53% rename from src/js/app/tsconfig.json rename to src/js/packages/@reactpy/app/tsconfig.json index c736ab13d..de3ec6378 100644 --- a/src/js/app/tsconfig.json +++ b/src/js/packages/@reactpy/app/tsconfig.json @@ -1,14 +1,15 @@ { - "extends": "../tsconfig.package.json", "compilerOptions": { + "composite": true, "outDir": "dist", "rootDir": "src", - "composite": true + "esModuleInterop": true }, + "extends": "../../../tsconfig.json", "include": ["src"], "references": [ { - "path": "../packages/@reactpy/client" + "path": "../client" } ] } diff --git a/src/js/packages/@reactpy/client/.gitignore b/src/js/packages/@reactpy/client/.gitignore deleted file mode 100644 index 787df98f6..000000000 --- a/src/js/packages/@reactpy/client/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Javascript -# ---------- -node_modules - -# IDE -# --- -.vscode -.idea diff --git a/src/js/packages/@reactpy/client/bun.lockb b/src/js/packages/@reactpy/client/bun.lockb new file mode 100644 index 000000000..10334c0e5 Binary files /dev/null and b/src/js/packages/@reactpy/client/bun.lockb differ diff --git a/src/js/packages/@reactpy/client/package.json b/src/js/packages/@reactpy/client/package.json index d399f7b91..d8e2fcefd 100644 --- a/src/js/packages/@reactpy/client/package.json +++ b/src/js/packages/@reactpy/client/package.json @@ -1,34 +1,35 @@ { - "author": "Ryan Morshead", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "description": "A client for ReactPy implemented in React", - "license": "MIT", - "name": "@reactpy/client", - "type": "module", - "version": "0.3.2", + "author": "Mark Bakhit", + "contributors": [ + "Ryan Morshead" + ], "dependencies": { - "event-to-object": "file:../event-to-object", - "json-pointer": "^0.6.2" + "json-pointer": "catalog:", + "preact": "catalog:", + "event-to-object": "catalog:" }, + "description": "A client for ReactPy implemented in React", "devDependencies": { - "@types/json-pointer": "^1.0.31", - "@types/react": "^17.0", - "@types/react-dom": "^17.0", - "typescript": "^4.9.5" - }, - "peerDependencies": { - "react": ">=16 <18", - "react-dom": ">=16 <18" + "@types/json-pointer": "catalog:", + "typescript": "catalog:" }, + "keywords": [ + "react", + "reactive", + "python", + "reactpy" + ], + "license": "MIT", + "main": "dist/index.js", + "name": "@reactpy/client", "repository": { "type": "git", "url": "https://github.com/reactive-python/reactpy" }, "scripts": { "build": "tsc -b", - "test": "npm run check:tests", - "check:tests": "echo 'no tests'", - "check:types": "tsc --noEmit" - } + "checkTypes": "tsc --noEmit" + }, + "type": "module", + "version": "1.0.2" } diff --git a/src/js/packages/@reactpy/client/src/bind.tsx b/src/js/packages/@reactpy/client/src/bind.tsx new file mode 100644 index 000000000..93d7fb2ae --- /dev/null +++ b/src/js/packages/@reactpy/client/src/bind.tsx @@ -0,0 +1,59 @@ +import * as preact from "preact"; + +export async function infer_bind_from_environment() { + try { + // @ts-ignore + const React = await import("react"); + // @ts-ignore + const ReactDOM = await import("react-dom/client"); + return (node: HTMLElement) => reactjs_bind(node, React, ReactDOM); + } catch { + console.error( + "Unknown error occurred: 'react' is missing within this ReactPy environment! \ + Your JavaScript components may not work as expected!", + ); + return (node: HTMLElement) => local_preact_bind(node); + } +} + +function local_preact_bind(node: HTMLElement) { + return { + create: (type: any, props: any, children?: any[]) => + preact.createElement(type, props, ...(children || [])), + render: (element: any) => { + preact.render(element, node); + }, + unmount: () => preact.render(null, node), + }; +} + +const roots = new WeakMap(); + +function reactjs_bind(node: HTMLElement, React: any, ReactDOM: any) { + let root: any = null; + return { + create: (type: any, props: any, children?: any[]) => + React.createElement(type, props, ...(children || [])), + render: (element: any) => { + if (!root) { + if (!roots.get(node)) { + root = ReactDOM.createRoot(node); + roots.set(node, root); + } else { + root = roots.get(node); + } + } + + root.render(element); + }, + unmount: () => { + if (root) { + root.unmount(); + if (roots.get(node) === root) { + roots.delete(node); + } + root = null; + } + }, + }; +} diff --git a/src/js/packages/@reactpy/client/src/client.ts b/src/js/packages/@reactpy/client/src/client.ts new file mode 100644 index 000000000..3b777210b --- /dev/null +++ b/src/js/packages/@reactpy/client/src/client.ts @@ -0,0 +1,83 @@ +import logger from "./logger"; +import type { + ReactPyClientInterface, + ReactPyModule, + GenericReactPyClientProps, + ReactPyUrls, +} from "./types"; +import { createReconnectingWebSocket } from "./websocket"; + +export abstract class BaseReactPyClient implements ReactPyClientInterface { + private readonly handlers: { [key: string]: ((message: any) => void)[] } = {}; + protected readonly ready: Promise; + private resolveReady: (value: undefined) => void; + + constructor() { + this.resolveReady = () => {}; + this.ready = new Promise((resolve) => (this.resolveReady = resolve)); + } + + onMessage(type: string, handler: (message: any) => void): () => void { + (this.handlers[type] || (this.handlers[type] = [])).push(handler); + this.resolveReady(undefined); + return () => { + this.handlers[type] = this.handlers[type].filter((h) => h !== handler); + }; + } + + abstract sendMessage(message: any): void; + abstract loadModule(moduleName: string): Promise; + + /** + * Handle an incoming message. + * + * This should be called by subclasses when a message is received. + * + * @param message The message to handle. The message must have a `type` property. + */ + protected handleIncoming(message: any): void { + if (!message.type) { + logger.warn("Received message without type", message); + return; + } + + const messageHandlers: ((m: any) => void)[] | undefined = + this.handlers[message.type]; + if (!messageHandlers) { + logger.warn("Received message without handler", message); + return; + } + + messageHandlers.forEach((h) => h(message)); + } +} + +export class ReactPyClient + extends BaseReactPyClient + implements ReactPyClientInterface +{ + urls: ReactPyUrls; + socket: { current?: WebSocket }; + mountElement: HTMLElement; + + constructor(props: GenericReactPyClientProps) { + super(); + + this.urls = props.urls; + this.mountElement = props.mountElement; + this.socket = createReconnectingWebSocket({ + url: this.urls.componentUrl, + readyPromise: this.ready, + ...props.reconnectOptions, + onMessage: async ({ data }) => this.handleIncoming(JSON.parse(data)), + }); + } + + sendMessage(message: any): void { + this.socket.current?.send(JSON.stringify(message)); + } + + loadModule(moduleName: string): Promise { + return import(`${this.urls.jsModulesPath}${moduleName}`); + } +} diff --git a/src/js/packages/@reactpy/client/src/components.tsx b/src/js/packages/@reactpy/client/src/components.tsx index 2319f81c7..52f229bae 100644 --- a/src/js/packages/@reactpy/client/src/components.tsx +++ b/src/js/packages/@reactpy/client/src/components.tsx @@ -1,25 +1,20 @@ -import React, { - createElement, - createContext, - useState, - useRef, - useContext, - useEffect, - Fragment, - MutableRefObject, - ChangeEvent, -} from "react"; -// @ts-ignore import { set as setJsonPointer } from "json-pointer"; +import type { MutableRefObject } from "preact/compat"; import { - ReactPyVdom, - ReactPyComponent, - createChildren, - createAttributes, - loadImportSource, + createContext, + createElement, + Fragment, + type JSX, + type TargetedEvent, +} from "preact"; +import { useContext, useEffect, useRef, useState } from "preact/hooks"; +import type { ImportSourceBinding, -} from "./reactpy-vdom"; -import { ReactPyClient } from "./reactpy-client"; + ReactPyComponent, + ReactPyVdom, +} from "./types"; +import { createAttributes, createChildren, loadImportSource } from "./vdom"; +import type { ReactPyClient } from "./client"; const ClientContext = createContext(null as any); @@ -70,7 +65,7 @@ export function Element({ model }: { model: ReactPyVdom }): JSX.Element | null { } function StandardElement({ model }: { model: ReactPyVdom }) { - const client = React.useContext(ClientContext); + const client = useContext(ClientContext); // Use createElement here to avoid warning about variable numbers of children not // having keys. Warning about this must now be the responsibility of the client // providing the models instead of the client rendering them. @@ -78,7 +73,7 @@ function StandardElement({ model }: { model: ReactPyVdom }) { model.tagName === "" ? Fragment : model.tagName, createAttributes(model, client), ...createChildren(model, (child) => { - return ; + return ; }), ); } @@ -86,16 +81,18 @@ function StandardElement({ model }: { model: ReactPyVdom }) { function UserInputElement({ model }: { model: ReactPyVdom }): JSX.Element { const client = useContext(ClientContext); const props = createAttributes(model, client); - const [value, setValue] = React.useState(props.value); + const [value, setValue] = useState(props.value); // honor changes to value from the client via props - React.useEffect(() => setValue(props.value), [props.value]); + useEffect(() => setValue(props.value), [props.value]); const givenOnChange = props.onChange; if (typeof givenOnChange === "function") { - props.onChange = (event: ChangeEvent) => { + props.onChange = (event: TargetedEvent) => { // immediately update the value to give the user feedback - setValue(event.target.value); + if (event.target) { + setValue((event.target as HTMLInputElement).value); + } // allow the client to respond (and possibly change the value) givenOnChange(event); }; @@ -109,7 +106,7 @@ function UserInputElement({ model }: { model: ReactPyVdom }): JSX.Element { // overwrite { ...props, value }, ...createChildren(model, (child) => ( - + )), ); } @@ -117,31 +114,34 @@ function UserInputElement({ model }: { model: ReactPyVdom }): JSX.Element { function ScriptElement({ model }: { model: ReactPyVdom }) { const ref = useRef(null); - React.useEffect(() => { + useEffect(() => { + // Don't run if the parent element is missing if (!ref.current) { return; } + + // Create the script element + const scriptElement: HTMLScriptElement = document.createElement("script"); + for (const [k, v] of Object.entries(model.attributes || {})) { + scriptElement.setAttribute(k, v); + } + + // Add the script content as text const scriptContent = model?.children?.filter( (value): value is string => typeof value == "string", )[0]; - - let scriptElement: HTMLScriptElement; - if (model.attributes) { - scriptElement = document.createElement("script"); - for (const [k, v] of Object.entries(model.attributes)) { - scriptElement.setAttribute(k, v); - } - if (scriptContent) { - scriptElement.appendChild(document.createTextNode(scriptContent)); - } - ref.current.appendChild(scriptElement); - } else if (scriptContent) { - const scriptResult = eval(scriptContent); - if (typeof scriptResult == "function") { - return scriptResult(); - } + if (scriptContent) { + scriptElement.appendChild(document.createTextNode(scriptContent)); } - }, [model.key, ref.current]); + + // Append the script element to the parent element + ref.current.appendChild(scriptElement); + + // Remove the script element when the component is unmounted + return () => { + ref.current?.removeChild(scriptElement); + }; + }, [model.attributes?.key]); return
; } @@ -179,16 +179,20 @@ function useImportSource(model: ReactPyVdom): MutableRefObject { const vdomImportSource = model.importSource; const vdomImportSourceJsonString = JSON.stringify(vdomImportSource); const mountPoint = useRef(null); - const client = React.useContext(ClientContext); + const client = useContext(ClientContext); const [binding, setBinding] = useState(null); + const bindingSource = useRef(null); - React.useEffect(() => { + useEffect(() => { let unmounted = false; + let currentBinding: ImportSourceBinding | null = null; if (vdomImportSource) { loadImportSource(vdomImportSource, client).then((bind) => { if (!unmounted && mountPoint.current) { - setBinding(bind(mountPoint.current)); + currentBinding = bind(mountPoint.current); + bindingSource.current = vdomImportSourceJsonString; + setBinding(currentBinding); } }); } @@ -196,11 +200,11 @@ function useImportSource(model: ReactPyVdom): MutableRefObject { return () => { unmounted = true; if ( - binding && + currentBinding && vdomImportSource && !vdomImportSource.unmountBeforeUpdate ) { - binding.unmount(); + currentBinding.unmount(); } }; }, [client, vdomImportSourceJsonString, setBinding, mountPoint.current]); @@ -210,6 +214,9 @@ function useImportSource(model: ReactPyVdom): MutableRefObject { if (!(binding && vdomImportSource)) { return; } + if (bindingSource.current !== vdomImportSourceJsonString) { + return; + } binding.render(model); if (vdomImportSource.unmountBeforeUpdate) { return binding.unmount; diff --git a/src/js/packages/@reactpy/client/src/index.ts b/src/js/packages/@reactpy/client/src/index.ts index 548fcbfc7..cca51fc00 100644 --- a/src/js/packages/@reactpy/client/src/index.ts +++ b/src/js/packages/@reactpy/client/src/index.ts @@ -1,5 +1,10 @@ +export * from "./client"; export * from "./components"; -export * from "./messages"; export * from "./mount"; -export * from "./reactpy-client"; -export * from "./reactpy-vdom"; +export * from "./types"; +export * from "./vdom"; +export * from "./websocket"; +export { default as React } from "preact/compat"; +export { default as ReactDOM } from "preact/compat"; +export { jsx, jsxs, Fragment } from "preact/jsx-runtime"; +export * as preact from "preact"; diff --git a/src/js/packages/@reactpy/client/src/logger.ts b/src/js/packages/@reactpy/client/src/logger.ts index 4c4cdd264..436e74be1 100644 --- a/src/js/packages/@reactpy/client/src/logger.ts +++ b/src/js/packages/@reactpy/client/src/logger.ts @@ -1,5 +1,6 @@ export default { log: (...args: any[]): void => console.log("[ReactPy]", ...args), + info: (...args: any[]): void => console.info("[ReactPy]", ...args), warn: (...args: any[]): void => console.warn("[ReactPy]", ...args), error: (...args: any[]): void => console.error("[ReactPy]", ...args), }; diff --git a/src/js/packages/@reactpy/client/src/messages.ts b/src/js/packages/@reactpy/client/src/messages.ts deleted file mode 100644 index 34001dcb0..000000000 --- a/src/js/packages/@reactpy/client/src/messages.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ReactPyVdom } from "./reactpy-vdom"; - -export type LayoutUpdateMessage = { - type: "layout-update"; - path: string; - model: ReactPyVdom; -}; - -export type LayoutEventMessage = { - type: "layout-event"; - target: string; - data: any; -}; - -export type IncomingMessage = LayoutUpdateMessage; -export type OutgoingMessage = LayoutEventMessage; -export type Message = IncomingMessage | OutgoingMessage; diff --git a/src/js/packages/@reactpy/client/src/mount.tsx b/src/js/packages/@reactpy/client/src/mount.tsx index 0b824a4ee..281f8291e 100644 --- a/src/js/packages/@reactpy/client/src/mount.tsx +++ b/src/js/packages/@reactpy/client/src/mount.tsx @@ -1,8 +1,40 @@ -import React from "react"; -import { render } from "react-dom"; +import { render } from "preact"; +import { ReactPyClient } from "./client"; import { Layout } from "./components"; -import { ReactPyClient } from "./reactpy-client"; +import type { MountProps } from "./types"; -export function mount(element: HTMLElement, client: ReactPyClient): void { - render(, element); +export function mountReactPy(props: MountProps) { + // WebSocket route for component rendering + const wsProtocol = `ws${window.location.protocol === "https:" ? "s" : ""}:`; + const wsOrigin = `${wsProtocol}//${window.location.host}`; + const componentUrl = new URL( + `${wsOrigin}${props.pathPrefix}${props.componentPath || ""}`, + ); + + // Embed the initial HTTP path into the WebSocket URL + componentUrl.searchParams.append("http_pathname", window.location.pathname); + if (window.location.search) { + componentUrl.searchParams.append( + "http_query_string", + window.location.search, + ); + } + + // Configure a new ReactPy client + const client = new ReactPyClient({ + urls: { + componentUrl: componentUrl, + jsModulesPath: `${window.location.origin}${props.pathPrefix}modules/`, + }, + reconnectOptions: { + interval: props.reconnectInterval || 750, + maxInterval: props.reconnectMaxInterval || 60000, + maxRetries: props.reconnectMaxRetries || 150, + backoffMultiplier: props.reconnectBackoffMultiplier || 1.25, + }, + mountElement: props.mountElement, + }); + + // Start rendering the component + render(, props.mountElement); } diff --git a/src/js/packages/@reactpy/client/src/reactpy-client.ts b/src/js/packages/@reactpy/client/src/reactpy-client.ts deleted file mode 100644 index 6f37b55a1..000000000 --- a/src/js/packages/@reactpy/client/src/reactpy-client.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { ReactPyModule } from "./reactpy-vdom"; -import logger from "./logger"; - -/** - * A client for communicating with a ReactPy server. - */ -export interface ReactPyClient { - /** - * Register a handler for a message type. - * - * The first time this is called, the client will be considered ready. - * - * @param type The type of message to handle. - * @param handler The handler to call when a message of the given type is received. - * @returns A function to unregister the handler. - */ - onMessage(type: string, handler: (message: any) => void): () => void; - - /** - * Send a message to the server. - * - * @param message The message to send. Messages must have a `type` property. - */ - sendMessage(message: any): void; - - /** - * Load a module from the server. - * @param moduleName The name of the module to load. - * @returns A promise that resolves to the module. - */ - loadModule(moduleName: string): Promise; -} - -export abstract class BaseReactPyClient implements ReactPyClient { - private readonly handlers: { [key: string]: ((message: any) => void)[] } = {}; - protected readonly ready: Promise; - private resolveReady: (value: undefined) => void; - - constructor() { - this.resolveReady = () => {}; - this.ready = new Promise((resolve) => (this.resolveReady = resolve)); - } - - onMessage(type: string, handler: (message: any) => void): () => void { - (this.handlers[type] || (this.handlers[type] = [])).push(handler); - this.resolveReady(undefined); - return () => { - this.handlers[type] = this.handlers[type].filter((h) => h !== handler); - }; - } - - abstract sendMessage(message: any): void; - abstract loadModule(moduleName: string): Promise; - - /** - * Handle an incoming message. - * - * This should be called by subclasses when a message is received. - * - * @param message The message to handle. The message must have a `type` property. - */ - protected handleIncoming(message: any): void { - if (!message.type) { - logger.warn("Received message without type", message); - return; - } - - const messageHandlers: ((m: any) => void)[] | undefined = - this.handlers[message.type]; - if (!messageHandlers) { - logger.warn("Received message without handler", message); - return; - } - - messageHandlers.forEach((h) => h(message)); - } -} - -export type SimpleReactPyClientProps = { - serverLocation?: LocationProps; - reconnectOptions?: ReconnectProps; -}; - -/** - * The location of the server. - * - * This is used to determine the location of the server's API endpoints. All endpoints - * are expected to be found at the base URL, with the following paths: - * - * - `_reactpy/stream/${route}${query}`: The websocket endpoint for the stream. - * - `_reactpy/modules`: The directory containing the dynamically loaded modules. - * - `_reactpy/assets`: The directory containing the static assets. - */ -type LocationProps = { - /** - * The base URL of the server. - * - * @default - document.location.origin - */ - url: string; - /** - * The route to the page being rendered. - * - * @default - document.location.pathname - */ - route: string; - /** - * The query string of the page being rendered. - * - * @default - document.location.search - */ - query: string; -}; - -type ReconnectProps = { - maxInterval?: number; - maxRetries?: number; - backoffRate?: number; - intervalJitter?: number; -}; - -export class SimpleReactPyClient - extends BaseReactPyClient - implements ReactPyClient -{ - private readonly urls: ServerUrls; - private readonly socket: { current?: WebSocket }; - - constructor(props: SimpleReactPyClientProps) { - super(); - - this.urls = getServerUrls( - props.serverLocation || { - url: document.location.origin, - route: document.location.pathname, - query: document.location.search, - }, - ); - - this.socket = createReconnectingWebSocket({ - readyPromise: this.ready, - url: this.urls.stream, - onMessage: async ({ data }) => this.handleIncoming(JSON.parse(data)), - ...props.reconnectOptions, - }); - } - - sendMessage(message: any): void { - this.socket.current?.send(JSON.stringify(message)); - } - - loadModule(moduleName: string): Promise { - return import(`${this.urls.modules}/${moduleName}`); - } -} - -type ServerUrls = { - base: URL; - stream: string; - modules: string; - assets: string; -}; - -function getServerUrls(props: LocationProps): ServerUrls { - const base = new URL(`${props.url || document.location.origin}/_reactpy`); - const modules = `${base}/modules`; - const assets = `${base}/assets`; - - const streamProtocol = `ws${base.protocol === "https:" ? "s" : ""}`; - const streamPath = rtrim(`${base.pathname}/stream${props.route || ""}`, "/"); - const stream = `${streamProtocol}://${base.host}${streamPath}${props.query}`; - - return { base, modules, assets, stream }; -} - -function createReconnectingWebSocket( - props: { - url: string; - readyPromise: Promise; - onOpen?: () => void; - onMessage: (message: MessageEvent) => void; - onClose?: () => void; - } & ReconnectProps, -) { - const { - maxInterval = 60000, - maxRetries = 50, - backoffRate = 1.1, - intervalJitter = 0.1, - } = props; - - const startInterval = 750; - let retries = 0; - let interval = startInterval; - const closed = false; - let everConnected = false; - const socket: { current?: WebSocket } = {}; - - const connect = () => { - if (closed) { - return; - } - socket.current = new WebSocket(props.url); - socket.current.onopen = () => { - everConnected = true; - logger.log("client connected"); - interval = startInterval; - retries = 0; - if (props.onOpen) { - props.onOpen(); - } - }; - socket.current.onmessage = props.onMessage; - socket.current.onclose = () => { - if (!everConnected) { - logger.log("failed to connect"); - return; - } - - logger.log("client disconnected"); - if (props.onClose) { - props.onClose(); - } - - if (retries >= maxRetries) { - return; - } - - const thisInterval = addJitter(interval, intervalJitter); - logger.log( - `reconnecting in ${(thisInterval / 1000).toPrecision(4)} seconds...`, - ); - setTimeout(connect, thisInterval); - interval = nextInterval(interval, backoffRate, maxInterval); - retries++; - }; - }; - - props.readyPromise.then(() => logger.log("starting client...")).then(connect); - - return socket; -} - -function nextInterval( - currentInterval: number, - backoffRate: number, - maxInterval: number, -): number { - return Math.min( - currentInterval * - // increase interval by backoff rate - backoffRate, - // don't exceed max interval - maxInterval, - ); -} - -function addJitter(interval: number, jitter: number): number { - return interval + (Math.random() * jitter * interval * 2 - jitter * interval); -} - -function rtrim(text: string, trim: string): string { - return text.replace(new RegExp(`${trim}+$`), ""); -} diff --git a/src/js/packages/@reactpy/client/src/reactpy-vdom.tsx b/src/js/packages/@reactpy/client/src/reactpy-vdom.tsx deleted file mode 100644 index 22fa3e61d..000000000 --- a/src/js/packages/@reactpy/client/src/reactpy-vdom.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import React, { ComponentType } from "react"; -import { ReactPyClient } from "./reactpy-client"; -import serializeEvent from "event-to-object"; - -export async function loadImportSource( - vdomImportSource: ReactPyVdomImportSource, - client: ReactPyClient, -): Promise { - let module: ReactPyModule; - if (vdomImportSource.sourceType === "URL") { - module = await import(vdomImportSource.source); - } else { - module = await client.loadModule(vdomImportSource.source); - } - if (typeof module.bind !== "function") { - throw new Error( - `${vdomImportSource.source} did not export a function 'bind'`, - ); - } - - return (node: HTMLElement) => { - const binding = module.bind(node, { - sendMessage: client.sendMessage, - onMessage: client.onMessage, - }); - if ( - !( - typeof binding.create === "function" && - typeof binding.render === "function" && - typeof binding.unmount === "function" - ) - ) { - console.error(`${vdomImportSource.source} returned an impropper binding`); - return null; - } - - return { - render: (model) => - binding.render( - createImportSourceElement({ - client, - module, - binding, - model, - currentImportSource: vdomImportSource, - }), - ), - unmount: binding.unmount, - }; - }; -} - -function createImportSourceElement(props: { - client: ReactPyClient; - module: ReactPyModule; - binding: ReactPyModuleBinding; - model: ReactPyVdom; - currentImportSource: ReactPyVdomImportSource; -}): any { - let type: any; - if (props.model.importSource) { - if ( - !isImportSourceEqual(props.currentImportSource, props.model.importSource) - ) { - console.error( - "Parent element import source " + - stringifyImportSource(props.currentImportSource) + - " does not match child's import source " + - stringifyImportSource(props.model.importSource), - ); - return null; - } else if (!props.module[props.model.tagName]) { - console.error( - "Module from source " + - stringifyImportSource(props.currentImportSource) + - ` does not export ${props.model.tagName}`, - ); - return null; - } else { - type = props.module[props.model.tagName]; - } - } else { - type = props.model.tagName; - } - return props.binding.create( - type, - createAttributes(props.model, props.client), - createChildren(props.model, (child) => - createImportSourceElement({ - ...props, - model: child, - }), - ), - ); -} - -function isImportSourceEqual( - source1: ReactPyVdomImportSource, - source2: ReactPyVdomImportSource, -) { - return ( - source1.source === source2.source && - source1.sourceType === source2.sourceType - ); -} - -function stringifyImportSource(importSource: ReactPyVdomImportSource) { - return JSON.stringify({ - source: importSource.source, - sourceType: importSource.sourceType, - }); -} - -export function createChildren( - model: ReactPyVdom, - createChild: (child: ReactPyVdom) => Child, -): (Child | string)[] { - if (!model.children) { - return []; - } else { - return model.children.map((child) => { - switch (typeof child) { - case "object": - return createChild(child); - case "string": - return child; - } - }); - } -} - -export function createAttributes( - model: ReactPyVdom, - client: ReactPyClient, -): { [key: string]: any } { - return Object.fromEntries( - Object.entries({ - // Normal HTML attributes - ...model.attributes, - // Construct event handlers - ...Object.fromEntries( - Object.entries(model.eventHandlers || {}).map(([name, handler]) => - createEventHandler(client, name, handler), - ), - ), - // Convert snake_case to camelCase names - }).map(normalizeAttribute), - ); -} - -function createEventHandler( - client: ReactPyClient, - name: string, - { target, preventDefault, stopPropagation }: ReactPyVdomEventHandler, -): [string, () => void] { - return [ - name, - function (...args: any[]) { - const data = Array.from(args).map((value) => { - if (!(typeof value === "object" && value.nativeEvent)) { - return value; - } - const event = value as React.SyntheticEvent; - if (preventDefault) { - event.preventDefault(); - } - if (stopPropagation) { - event.stopPropagation(); - } - return serializeEvent(event.nativeEvent); - }); - client.sendMessage({ type: "layout-event", data, target }); - }, - ]; -} - -function normalizeAttribute([key, value]: [string, any]): [string, any] { - let normKey = key; - let normValue = value; - - if (key === "style" && typeof value === "object") { - normValue = Object.fromEntries( - Object.entries(value).map(([k, v]) => [snakeToCamel(k), v]), - ); - } else if ( - key.startsWith("data_") || - key.startsWith("aria_") || - DASHED_HTML_ATTRS.includes(key) - ) { - normKey = key.split("_").join("-"); - } else { - normKey = snakeToCamel(key); - } - return [normKey, normValue]; -} - -function snakeToCamel(str: string): string { - return str.replace(/([_][a-z])/g, (group) => - group.toUpperCase().replace("_", ""), - ); -} - -// see list of HTML attributes with dashes in them: -// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#attribute_list -const DASHED_HTML_ATTRS = ["accept_charset", "http_equiv"]; - -export type ReactPyComponent = ComponentType<{ model: ReactPyVdom }>; - -export type ReactPyVdom = { - tagName: string; - key?: string; - attributes?: { [key: string]: string }; - children?: (ReactPyVdom | string)[]; - error?: string; - eventHandlers?: { [key: string]: ReactPyVdomEventHandler }; - importSource?: ReactPyVdomImportSource; -}; - -export type ReactPyVdomEventHandler = { - target: string; - preventDefault?: boolean; - stopPropagation?: boolean; -}; - -export type ReactPyVdomImportSource = { - source: string; - sourceType?: "URL" | "NAME"; - fallback?: string | ReactPyVdom; - unmountBeforeUpdate?: boolean; -}; - -export type ReactPyModule = { - bind: ( - node: HTMLElement, - context: ReactPyModuleBindingContext, - ) => ReactPyModuleBinding; -} & { [key: string]: any }; - -export type ReactPyModuleBindingContext = { - sendMessage: ReactPyClient["sendMessage"]; - onMessage: ReactPyClient["onMessage"]; -}; - -export type ReactPyModuleBinding = { - create: ( - type: any, - props?: any, - children?: (any | string | ReactPyVdom)[], - ) => any; - render: (element: any) => void; - unmount: () => void; -}; - -export type BindImportSource = ( - node: HTMLElement, -) => ImportSourceBinding | null; - -export type ImportSourceBinding = { - render: (model: ReactPyVdom) => void; - unmount: () => void; -}; diff --git a/src/js/packages/@reactpy/client/src/types.ts b/src/js/packages/@reactpy/client/src/types.ts new file mode 100644 index 000000000..12bc8f3fa --- /dev/null +++ b/src/js/packages/@reactpy/client/src/types.ts @@ -0,0 +1,151 @@ +import type { ComponentType } from "preact"; + +// #### CONNECTION TYPES #### + +export type ReconnectOptions = { + interval: number; + maxInterval: number; + maxRetries: number; + backoffMultiplier: number; +}; + +export type CreateReconnectingWebSocketProps = { + url: URL; + readyPromise: Promise; + onMessage: (message: MessageEvent) => void; + onOpen?: () => void; + onClose?: () => void; + interval: number; + maxInterval: number; + maxRetries: number; + backoffMultiplier: number; +}; + +export type ReactPyUrls = { + componentUrl: URL; + jsModulesPath: string; +}; + +export type GenericReactPyClientProps = { + urls: ReactPyUrls; + reconnectOptions: ReconnectOptions; + mountElement: HTMLElement; +}; + +export type MountProps = { + mountElement: HTMLElement; + pathPrefix: string; + componentPath?: string; + reconnectInterval?: number; + reconnectMaxInterval?: number; + reconnectMaxRetries?: number; + reconnectBackoffMultiplier?: number; +}; + +// #### COMPONENT TYPES #### + +export type ReactPyComponent = ComponentType<{ model: ReactPyVdom }>; + +export type ReactPyVdom = { + tagName: string; + attributes?: { [key: string]: string }; + children?: (ReactPyVdom | string)[]; + error?: string; + eventHandlers?: { [key: string]: ReactPyVdomEventHandler }; + inlineJavaScript?: { [key: string]: string }; + importSource?: ReactPyVdomImportSource; +}; + +export type ReactPyVdomEventHandler = { + target: string; + preventDefault?: boolean; + stopPropagation?: boolean; +}; + +export type ReactPyVdomImportSource = { + source: string; + sourceType?: "URL" | "NAME"; + fallback?: string | ReactPyVdom; + unmountBeforeUpdate?: boolean; +}; + +export type ReactPyModule = { + bind: ( + node: HTMLElement, + context: ReactPyModuleBindingContext, + ) => ReactPyModuleBinding; +} & { [key: string]: any }; + +export type ReactPyModuleBindingContext = { + sendMessage: ReactPyClientInterface["sendMessage"]; + onMessage: ReactPyClientInterface["onMessage"]; +}; + +export type ReactPyModuleBinding = { + create: ( + type: any, + props?: any, + children?: (any | string | ReactPyVdom)[], + ) => any; + render: (element: any) => void; + unmount: () => void; +}; + +export type BindImportSource = ( + node: HTMLElement, +) => ImportSourceBinding | null; + +export type ImportSourceBinding = { + render: (model: ReactPyVdom) => void; + unmount: () => void; +}; + +// #### MESSAGE TYPES #### + +export type LayoutUpdateMessage = { + type: "layout-update"; + path: string; + model: ReactPyVdom; +}; + +export type LayoutEventMessage = { + type: "layout-event"; + target: string; + data: any; +}; + +export type IncomingMessage = LayoutUpdateMessage; +export type OutgoingMessage = LayoutEventMessage; +export type Message = IncomingMessage | OutgoingMessage; + +// #### INTERFACES #### + +/** + * A client for communicating with a ReactPy server. + */ +export interface ReactPyClientInterface { + /** + * Register a handler for a message type. + * + * The first time this is called, the client will be considered ready. + * + * @param type The type of message to handle. + * @param handler The handler to call when a message of the given type is received. + * @returns A function to unregister the handler. + */ + onMessage(type: string, handler: (message: any) => void): () => void; + + /** + * Send a message to the server. + * + * @param message The message to send. Messages must have a `type` property. + */ + sendMessage(message: any): void; + + /** + * Load a module from the server. + * @param moduleName The name of the module to load. + * @returns A promise that resolves to the module. + */ + loadModule(moduleName: string): Promise; +} diff --git a/src/js/packages/@reactpy/client/src/vdom.tsx b/src/js/packages/@reactpy/client/src/vdom.tsx new file mode 100644 index 000000000..e57ea4594 --- /dev/null +++ b/src/js/packages/@reactpy/client/src/vdom.tsx @@ -0,0 +1,350 @@ +import eventToObject from "event-to-object"; +import type { + ReactPyVdom, + ReactPyVdomImportSource, + ReactPyVdomEventHandler, + ReactPyModule, + BindImportSource, + ReactPyModuleBinding, + ImportSourceBinding, +} from "./types"; +import { infer_bind_from_environment } from "./bind"; +import log from "./logger"; +import type { ReactPyClient } from "./client"; + +export async function loadImportSource( + vdomImportSource: ReactPyVdomImportSource, + client: ReactPyClient, +): Promise { + let module: ReactPyModule; + if (vdomImportSource.sourceType === "URL") { + module = await import(vdomImportSource.source); + } else { + module = await client.loadModule(vdomImportSource.source); + } + + let { bind } = module; + if (typeof bind !== "function") { + bind = await infer_bind_from_environment(); + } + + return (node: HTMLElement) => { + const binding = bind(node, { + sendMessage: client.sendMessage, + onMessage: client.onMessage, + }); + if ( + !( + typeof binding.create === "function" && + typeof binding.render === "function" && + typeof binding.unmount === "function" + ) + ) { + log.error(`${vdomImportSource.source} returned an impropper binding`); + return null; + } + + return { + render: (model) => + binding.render( + createImportSourceElement({ + client, + module, + binding, + model, + currentImportSource: vdomImportSource, + }), + ), + unmount: binding.unmount, + }; + }; +} + +function createImportSourceElement(props: { + client: ReactPyClient; + module: ReactPyModule; + binding: ReactPyModuleBinding; + model: ReactPyVdom; + currentImportSource: ReactPyVdomImportSource; +}): any { + let type: any; + if (props.model.importSource) { + if ( + !isImportSourceEqual(props.currentImportSource, props.model.importSource) + ) { + return props.binding.create("reactpy-child", { + ref: (node: ReactPyChild | null) => { + if (node) { + node.client = props.client; + node.model = props.model; + node.requestUpdate(); + } + }, + }); + } else { + type = getComponentFromModule( + props.module, + props.model.tagName, + props.model.importSource, + ); + if (!type) { + // Error message logged within getComponentFromModule + return null; + } + } + } else { + type = props.model.tagName; + } + return props.binding.create( + type, + createAttributes(props.model, props.client), + createChildren(props.model, (child) => + createImportSourceElement({ + ...props, + model: child, + }), + ), + ); +} + +function getComponentFromModule( + module: ReactPyModule, + componentName: string, + importSource: ReactPyVdomImportSource, +): any { + /* Gets the component with the provided name from the provided module. + + Built specifically to work on inifinitely deep nested components. + For example, component "My.Nested.Component" is accessed from + ModuleA like so: ModuleA["My"]["Nested"]["Component"]. + */ + const componentParts: string[] = componentName.split("."); + let Component: any = null; + for (let i = 0; i < componentParts.length; i++) { + const iterAttr = componentParts[i]; + Component = i == 0 ? module[iterAttr] : Component[iterAttr]; + if (!Component) { + if (i == 0) { + log.error( + "Module from source " + + stringifyImportSource(importSource) + + ` does not export ${iterAttr}`, + ); + } else { + console.error( + `Component ${componentParts.slice(0, i).join(".")} from source ` + + stringifyImportSource(importSource) + + ` does not have subcomponent ${iterAttr}`, + ); + } + break; + } + } + return Component; +} + +function isImportSourceEqual( + source1: ReactPyVdomImportSource, + source2: ReactPyVdomImportSource, +) { + return ( + source1.source === source2.source && + source1.sourceType === source2.sourceType + ); +} + +function stringifyImportSource(importSource: ReactPyVdomImportSource) { + return JSON.stringify({ + source: importSource.source, + sourceType: importSource.sourceType, + }); +} + +export function createChildren( + model: ReactPyVdom, + createChild: (child: ReactPyVdom) => Child, +): (Child | string)[] { + if (!model.children) { + return []; + } else { + return model.children.map((child) => { + switch (typeof child) { + case "object": + return createChild(child); + case "string": + return child; + } + }); + } +} + +export function createAttributes( + model: ReactPyVdom, + client: ReactPyClient, +): { [key: string]: any } { + return Object.fromEntries( + Object.entries({ + // Normal HTML attributes + ...model.attributes, + // Construct event handlers + ...Object.fromEntries( + Object.entries(model.eventHandlers || {}).map(([name, handler]) => + createEventHandler(client, name, handler), + ), + ), + ...Object.fromEntries( + Object.entries(model.inlineJavaScript || {}).map( + ([name, inlineJavaScript]) => + createInlineJavaScript(name, inlineJavaScript), + ), + ), + }), + ); +} + +function createEventHandler( + client: ReactPyClient, + name: string, + { target, preventDefault, stopPropagation }: ReactPyVdomEventHandler, +): [string, () => void] { + const eventHandler = function (...args: any[]) { + const data = Array.from(args).map((value) => { + const event = value as Event; + if (preventDefault) { + event.preventDefault(); + } + if (stopPropagation) { + event.stopPropagation(); + } + + // Convert JavaScript objects to plain JSON, if needed + if (typeof event === "object") { + return eventToObject(event); + } else { + return event; + } + }); + client.sendMessage({ type: "layout-event", data, target }); + }; + eventHandler.isHandler = true; + return [name, eventHandler]; +} + +function createInlineJavaScript( + name: string, + inlineJavaScript: string, +): [string, () => void] { + /* Function that will execute the string-like InlineJavaScript + via eval in the most appropriate way */ + const wrappedExecutable = function (...args: any[]) { + function handleExecution(...args: any[]) { + const evalResult = eval(inlineJavaScript); + if (typeof evalResult == "function") { + return evalResult(...args); + } + } + if (args.length > 0 && args[0] instanceof Event) { + /* If being triggered by an event, set the event's current + target to "this". This ensures that inline + javascript statements such as the following work: + html.button({"onclick": 'this.value = "Clicked!"'}, "Click Me")*/ + return handleExecution.call(args[0].currentTarget, ...args); + } else { + /* If not being triggered by an event, do not set "this" and + just call normally */ + return handleExecution(...args); + } + }; + wrappedExecutable.isHandler = false; + return [name, wrappedExecutable]; +} + +class ReactPyChild extends HTMLElement { + mountPoint: HTMLDivElement; + binding: ImportSourceBinding | null = null; + _client: ReactPyClient | null = null; + _model: ReactPyVdom | null = null; + currentImportSource: ReactPyVdomImportSource | null = null; + + constructor() { + super(); + this.mountPoint = document.createElement("div"); + this.mountPoint.style.display = "contents"; + } + + connectedCallback() { + this.appendChild(this.mountPoint); + } + + set client(value: ReactPyClient) { + this._client = value; + } + + set model(value: ReactPyVdom) { + this._model = value; + } + + requestUpdate() { + this.update(); + } + + async update() { + if (!this._client || !this._model || !this._model.importSource) { + return; + } + + const newImportSource = this._model.importSource; + + if ( + !this.binding || + !this.currentImportSource || + !isImportSourceEqual(this.currentImportSource, newImportSource) + ) { + if (this.binding) { + this.binding.unmount(); + this.binding = null; + } + + this.currentImportSource = newImportSource; + + try { + const bind = await loadImportSource(newImportSource, this._client); + if ( + this.isConnected && + this.currentImportSource && + isImportSourceEqual(this.currentImportSource, newImportSource) + ) { + const oldBinding = this.binding as ImportSourceBinding | null; + if (oldBinding) { + oldBinding.unmount(); + } + this.binding = bind(this.mountPoint); + if (this.binding) { + this.binding.render(this._model); + } + } + } catch (error) { + console.error("Failed to load import source", error); + } + } else { + if (this.binding) { + this.binding.render(this._model); + } + } + } + + disconnectedCallback() { + if (this.binding) { + this.binding.unmount(); + this.binding = null; + this.currentImportSource = null; + } + } +} + +if ( + typeof customElements !== "undefined" && + !customElements.get("reactpy-child") +) { + customElements.define("reactpy-child", ReactPyChild); +} diff --git a/src/js/packages/@reactpy/client/src/websocket.ts b/src/js/packages/@reactpy/client/src/websocket.ts new file mode 100644 index 000000000..4c72620f0 --- /dev/null +++ b/src/js/packages/@reactpy/client/src/websocket.ts @@ -0,0 +1,75 @@ +import type { CreateReconnectingWebSocketProps } from "./types"; +import log from "./logger"; + +export function createReconnectingWebSocket( + props: CreateReconnectingWebSocketProps, +) { + const { interval, maxInterval, maxRetries, backoffMultiplier } = props; + let retries = 0; + let currentInterval = interval; + let everConnected = false; + const closed = false; + const socket: { current?: WebSocket } = {}; + + const connect = () => { + if (closed) { + return; + } + socket.current = new WebSocket(props.url); + socket.current.onopen = () => { + everConnected = true; + log.info("Connected!"); + currentInterval = interval; + retries = 0; + if (props.onOpen) { + props.onOpen(); + } + }; + socket.current.onmessage = (event) => { + if (props.onMessage) { + props.onMessage(event); + } + }; + socket.current.onclose = () => { + if (props.onClose) { + props.onClose(); + } + if (!everConnected) { + log.info("Failed to connect!"); + return; + } + log.info("Disconnected!"); + if (retries >= maxRetries) { + log.info("Connection max retries exhausted!"); + return; + } + log.info( + `Reconnecting in ${(currentInterval / 1000).toPrecision(4)} seconds...`, + ); + setTimeout(connect, currentInterval); + currentInterval = nextInterval( + currentInterval, + backoffMultiplier, + maxInterval, + ); + retries++; + }; + }; + + props.readyPromise.then(() => log.info("Starting client...")).then(connect); + + return socket; +} + +export function nextInterval( + currentInterval: number, + backoffMultiplier: number, + maxInterval: number, +): number { + return Math.min( + // increase interval by backoff multiplier + currentInterval * backoffMultiplier, + // don't exceed max interval + maxInterval, + ); +} diff --git a/src/js/packages/@reactpy/client/tsconfig.json b/src/js/packages/@reactpy/client/tsconfig.json index 2e1483e10..b6bb436d0 100644 --- a/src/js/packages/@reactpy/client/tsconfig.json +++ b/src/js/packages/@reactpy/client/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "../../../tsconfig.package.json", "compilerOptions": { + "composite": true, "outDir": "dist", - "rootDir": "src", - "composite": true + "rootDir": "src" }, + "extends": "../../../tsconfig.json", "include": ["src"], "references": [ { diff --git a/src/js/packages/event-to-object/README.md b/src/js/packages/event-to-object/README.md new file mode 100644 index 000000000..b28f5d3fb --- /dev/null +++ b/src/js/packages/event-to-object/README.md @@ -0,0 +1,3 @@ +# Event to Object + +Converts a JavaScript events to JSON serializable objects. diff --git a/src/js/packages/event-to-object/bun.lockb b/src/js/packages/event-to-object/bun.lockb new file mode 100644 index 000000000..1c6a0e669 Binary files /dev/null and b/src/js/packages/event-to-object/bun.lockb differ diff --git a/src/js/packages/event-to-object/package.json b/src/js/packages/event-to-object/package.json index eaeb99343..85c6b1b2c 100644 --- a/src/js/packages/event-to-object/package.json +++ b/src/js/packages/event-to-object/package.json @@ -1,30 +1,35 @@ { - "author": "Ryan Morshead", - "license": "MIT", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "name": "event-to-object", - "description": "Convert native events to JSON serializable objects", - "type": "module", - "version": "0.1.2", + "author": "Mark Bakhit", + "contributors": [ + "Ryan Morshead" + ], "dependencies": { - "json-pointer": "^0.6.2" + "json-pointer": "catalog:" }, + "description": "Converts a JavaScript events to JSON serializable objects.", "devDependencies": { - "happy-dom": "^8.9.0", + "happy-dom": "^15.0.0", "lodash": "^4.17.21", - "tsm": "^2.0.0", - "typescript": "^4.9.5", - "uvu": "^0.5.1" + "typescript": "^5.8.3", + "vitest": "^2.1.8" }, + "keywords": [ + "event", + "json", + "object", + "convert" + ], + "license": "MIT", + "main": "dist/index.js", + "name": "event-to-object", "repository": { "type": "git", "url": "https://github.com/reactive-python/reactpy" }, "scripts": { "build": "tsc -b", - "test": "npm run check:tests", - "check:tests": "uvu -r tsm tests", - "check:types": "tsc --noEmit" - } + "checkTypes": "tsc --noEmit" + }, + "type": "module", + "version": "1.0.1" } diff --git a/src/js/packages/event-to-object/src/events.ts b/src/js/packages/event-to-object/src/events.ts deleted file mode 100644 index cef37ff09..000000000 --- a/src/js/packages/event-to-object/src/events.ts +++ /dev/null @@ -1,258 +0,0 @@ -// TODO -type FileListObject = any; -type DataTransferItemListObject = any; - -export type EventToObjectMap = { - event: [Event, EventObject]; - animation: [AnimationEvent, AnimationEventObject]; - clipboard: [ClipboardEvent, ClipboardEventObject]; - composition: [CompositionEvent, CompositionEventObject]; - devicemotion: [DeviceMotionEvent, DeviceMotionEventObject]; - deviceorientation: [DeviceOrientationEvent, DeviceOrientationEventObject]; - drag: [DragEvent, DragEventObject]; - focus: [FocusEvent, FocusEventObject]; - formdata: [FormDataEvent, FormDataEventObject]; - gamepad: [GamepadEvent, GamepadEventObject]; - input: [InputEvent, InputEventObject]; - keyboard: [KeyboardEvent, KeyboardEventObject]; - mouse: [MouseEvent, MouseEventObject]; - pointer: [PointerEvent, PointerEventObject]; - submit: [SubmitEvent, SubmitEventObject]; - touch: [TouchEvent, TouchEventObject]; - transition: [TransitionEvent, TransitionEventObject]; - ui: [UIEvent, UIEventObject]; - wheel: [WheelEvent, WheelEventObject]; -}; - -export interface EventObject { - bubbles: boolean; - composed: boolean; - currentTarget: ElementObject | null; - defaultPrevented: boolean; - eventPhase: number; - isTrusted: boolean; - target: ElementObject | null; - timeStamp: DOMHighResTimeStamp; - type: string; - selection: SelectionObject | null; -} - -export interface SubmitEventObject extends EventObject { - submitter: ElementObject; -} - -export interface InputEventObject extends UIEventObject { - data: string | null; - dataTransfer: DataTransferObject | null; - isComposing: boolean; - inputType: string; -} - -export interface GamepadEventObject extends EventObject { - gamepad: GamepadObject; -} - -export interface GamepadObject { - axes: number[]; - buttons: GamepadButtonObject[]; - connected: boolean; - hapticActuators: GamepadHapticActuatorObject[]; - id: string; - index: number; - mapping: GamepadMappingType; - timestamp: DOMHighResTimeStamp; -} - -export interface GamepadButtonObject { - pressed: boolean; - touched: boolean; - value: number; -} -export interface GamepadHapticActuatorObject { - type: string; -} - -export interface DragEventObject extends MouseEventObject { - /** Returns the DataTransfer object for the event. */ - readonly dataTransfer: DataTransferObject | null; -} - -export interface DeviceMotionEventObject extends EventObject { - acceleration: DeviceAccelerationObject | null; - accelerationIncludingGravity: DeviceAccelerationObject | null; - interval: number; - rotationRate: DeviceRotationRateObject | null; -} - -export interface DeviceAccelerationObject { - x: number | null; - y: number | null; - z: number | null; -} - -export interface DeviceRotationRateObject { - alpha: number | null; - beta: number | null; - gamma: number | null; -} - -export interface DeviceOrientationEventObject extends EventObject { - absolute: boolean; - alpha: number | null; - beta: number | null; - gamma: number | null; -} - -export interface MouseEventObject extends EventObject { - altKey: boolean; - button: number; - buttons: number; - clientX: number; - clientY: number; - ctrlKey: boolean; - metaKey: boolean; - movementX: number; - movementY: number; - offsetX: number; - offsetY: number; - pageX: number; - pageY: number; - relatedTarget: ElementObject | null; - screenX: number; - screenY: number; - shiftKey: boolean; - x: number; - y: number; -} - -export interface FormDataEventObject extends EventObject { - formData: FormDataObject; -} - -export type FormDataObject = [string, string | FileObject][]; - -export interface AnimationEventObject extends EventObject { - animationName: string; - elapsedTime: number; - pseudoElement: string; -} - -export interface ClipboardEventObject extends EventObject { - clipboardData: DataTransferObject | null; -} - -export interface UIEventObject extends EventObject { - detail: number; -} - -/** The DOM CompositionEvent represents events that occur due to the user indirectly - * entering text. */ -export interface CompositionEventObject extends UIEventObject { - data: string; -} - -export interface KeyboardEventObject extends UIEventObject { - altKey: boolean; - code: string; - ctrlKey: boolean; - isComposing: boolean; - key: string; - location: number; - metaKey: boolean; - repeat: boolean; - shiftKey: boolean; -} - -export interface FocusEventObject extends UIEventObject { - relatedTarget: ElementObject | null; -} - -export interface TouchEventObject extends UIEventObject { - altKey: boolean; - changedTouches: TouchObject[]; - ctrlKey: boolean; - metaKey: boolean; - shiftKey: boolean; - targetTouches: TouchObject[]; - touches: TouchObject[]; -} - -export interface PointerEventObject extends MouseEventObject { - height: number; - isPrimary: boolean; - pointerId: number; - pointerType: string; - pressure: number; - tangentialPressure: number; - tiltX: number; - tiltY: number; - twist: number; - width: number; -} - -export interface TransitionEventObject extends EventObject { - elapsedTime: number; - propertyName: string; - pseudoElement: string; -} - -export interface WheelEventObject extends MouseEventObject { - readonly deltaMode: number; - readonly deltaX: number; - readonly deltaY: number; - readonly deltaZ: number; -} - -export interface TouchObject { - clientX: number; - clientY: number; - force: number; - identifier: number; - pageX: number; - pageY: number; - radiusX: number; - radiusY: number; - rotationAngle: number; - screenX: number; - screenY: number; - target: ElementObject; -} - -export interface DataTransferObject { - dropEffect: "none" | "copy" | "link" | "move"; - effectAllowed: - | "none" - | "copy" - | "copyLink" - | "copyMove" - | "link" - | "linkMove" - | "move" - | "all" - | "uninitialized"; - files: FileListObject; - items: DataTransferItemListObject; - types: string[]; -} - -export interface SelectionObject { - anchorNode: ElementObject | null; - anchorOffset: number; - focusNode: ElementObject | null; - focusOffset: number; - isCollapsed: boolean; - rangeCount: number; - type: string; - selectedText: string; -} - -export interface ElementObject { - value?: string; - textContent?: string; -} - -export interface FileObject { - name: string; - size: number; - type: string; -} diff --git a/src/js/packages/event-to-object/src/index.ts b/src/js/packages/event-to-object/src/index.ts index 22fb7154d..f6aebe62e 100644 --- a/src/js/packages/event-to-object/src/index.ts +++ b/src/js/packages/event-to-object/src/index.ts @@ -1,430 +1,323 @@ -import * as e from "./events"; - -export default function convert( - event: E, -): - | { - [K in keyof e.EventToObjectMap]: e.EventToObjectMap[K] extends [ - E, - infer P, - ] - ? P - : never; - }[keyof e.EventToObjectMap] - | null { - return event.type in eventConverters - ? eventConverters[event.type](event) - : convertEvent(event); -} - -const convertEvent = (event: Event): e.EventObject => ({ - /** Returns true or false depending on how event was initialized. True if event goes - * through its target's ancestors in reverse tree order, and false otherwise. */ - bubbles: event.bubbles, - composed: event.composed, - currentTarget: convertElement(event.currentTarget), - defaultPrevented: event.defaultPrevented, - eventPhase: event.eventPhase, - isTrusted: event.isTrusted, - target: convertElement(event.target), - timeStamp: event.timeStamp, - type: event.type, - selection: convertSelection(window.getSelection()), -}); - -const convertClipboardEvent = ( - event: ClipboardEvent, -): e.ClipboardEventObject => ({ - ...convertEvent(event), - clipboardData: convertDataTransferObject(event.clipboardData), -}); - -const convertCompositionEvent = ( - event: CompositionEvent, -): e.CompositionEventObject => ({ - ...convertUiEvent(event), - data: event.data, -}); - -const convertInputEvent = (event: InputEvent): e.InputEventObject => ({ - ...convertUiEvent(event), - data: event.data, - inputType: event.inputType, - dataTransfer: convertDataTransferObject(event.dataTransfer), - isComposing: event.isComposing, -}); - -const convertKeyboardEvent = (event: KeyboardEvent): e.KeyboardEventObject => ({ - ...convertUiEvent(event), - code: event.code, - isComposing: event.isComposing, - altKey: event.altKey, - ctrlKey: event.ctrlKey, - key: event.key, - location: event.location, - metaKey: event.metaKey, - repeat: event.repeat, - shiftKey: event.shiftKey, -}); - -const convertMouseEvent = (event: MouseEvent): e.MouseEventObject => ({ - ...convertEvent(event), - altKey: event.altKey, - button: event.button, - buttons: event.buttons, - clientX: event.clientX, - clientY: event.clientY, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - pageX: event.pageX, - pageY: event.pageY, - screenX: event.screenX, - screenY: event.screenY, - shiftKey: event.shiftKey, - movementX: event.movementX, - movementY: event.movementY, - offsetX: event.offsetX, - offsetY: event.offsetY, - x: event.x, - y: event.y, - relatedTarget: convertElement(event.relatedTarget), -}); - -const convertTouchEvent = (event: TouchEvent): e.TouchEventObject => ({ - ...convertUiEvent(event), - altKey: event.altKey, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - shiftKey: event.shiftKey, - touches: Array.from(event.touches).map(convertTouch), - changedTouches: Array.from(event.changedTouches).map(convertTouch), - targetTouches: Array.from(event.targetTouches).map(convertTouch), -}); - -const convertUiEvent = (event: UIEvent): e.UIEventObject => ({ - ...convertEvent(event), - detail: event.detail, -}); - -const convertAnimationEvent = ( - event: AnimationEvent, -): e.AnimationEventObject => ({ - ...convertEvent(event), - animationName: event.animationName, - pseudoElement: event.pseudoElement, - elapsedTime: event.elapsedTime, -}); - -const convertTransitionEvent = ( - event: TransitionEvent, -): e.TransitionEventObject => ({ - ...convertEvent(event), - propertyName: event.propertyName, - pseudoElement: event.pseudoElement, - elapsedTime: event.elapsedTime, -}); - -const convertFocusEvent = (event: FocusEvent): e.FocusEventObject => ({ - ...convertUiEvent(event), - relatedTarget: convertElement(event.relatedTarget), -}); - -const convertDeviceOrientationEvent = ( - event: DeviceOrientationEvent, -): e.DeviceOrientationEventObject => ({ - ...convertEvent(event), - absolute: event.absolute, - alpha: event.alpha, - beta: event.beta, - gamma: event.gamma, -}); - -const convertDragEvent = (event: DragEvent): e.DragEventObject => ({ - ...convertMouseEvent(event), - dataTransfer: convertDataTransferObject(event.dataTransfer), -}); - -const convertGamepadEvent = (event: GamepadEvent): e.GamepadEventObject => ({ - ...convertEvent(event), - gamepad: convertGamepad(event.gamepad), -}); - -const convertPointerEvent = (event: PointerEvent): e.PointerEventObject => ({ - ...convertMouseEvent(event), - pointerId: event.pointerId, - width: event.width, - height: event.height, - pressure: event.pressure, - tiltX: event.tiltX, - tiltY: event.tiltY, - pointerType: event.pointerType, - isPrimary: event.isPrimary, - tangentialPressure: event.tangentialPressure, - twist: event.twist, -}); +const maxDepthSignal = { __stop__: true }; + +/** + * Convert any class object (such as `Event`) to a plain object. + */ +export default function convert( + classObject: { [key: string]: any }, + maxDepth: number = 10, +): object { + // Immediately return `classObject` if given an unexpected (non-object) input + if (!classObject || typeof classObject !== "object") { + console.warn( + "eventToObject: Expected an object input, received:", + classObject, + ); + return classObject; + } -const convertWheelEvent = (event: WheelEvent): e.WheelEventObject => ({ - ...convertMouseEvent(event), - deltaMode: event.deltaMode, - deltaX: event.deltaX, - deltaY: event.deltaY, - deltaZ: event.deltaZ, -}); + // Begin conversion + const visited = new WeakSet(); + visited.add(classObject); + const convertedObj: { [key: string]: any } = {}; + for (const key in classObject) { + // Skip keys that cannot be converted + try { + if (shouldIgnoreValue(classObject[key], key)) { + continue; + } + // Handle objects (potentially cyclical) + else if (typeof classObject[key] === "object") { + const result = deepCloneClass(classObject[key], maxDepth, visited); + if (result !== maxDepthSignal) { + convertedObj[key] = result; + } + } + // Handle simple types (non-cyclical) + else { + convertedObj[key] = classObject[key]; + } + } catch { + continue; + } + } -const convertSubmitEvent = (event: SubmitEvent): e.SubmitEventObject => ({ - ...convertEvent(event), - submitter: convertElement(event.submitter), -}); + // Special case: Event selection + if ( + typeof window !== "undefined" && + window.Event && + classObject instanceof window.Event + ) { + convertedObj["selection"] = serializeSelection(maxDepth, visited); + } -const eventConverters: { [key: string]: (event: any) => any } = { - // animation events - animationcancel: convertAnimationEvent, - animationend: convertAnimationEvent, - animationiteration: convertAnimationEvent, - animationstart: convertAnimationEvent, - // input events - beforeinput: convertInputEvent, - // composition events - compositionend: convertCompositionEvent, - compositionstart: convertCompositionEvent, - compositionupdate: convertCompositionEvent, - // clipboard events - copy: convertClipboardEvent, - cut: convertClipboardEvent, - paste: convertClipboardEvent, - // device orientation events - deviceorientation: convertDeviceOrientationEvent, - // drag events - drag: convertDragEvent, - dragend: convertDragEvent, - dragenter: convertDragEvent, - dragleave: convertDragEvent, - dragover: convertDragEvent, - dragstart: convertDragEvent, - drop: convertDragEvent, - // ui events - error: convertUiEvent, - // focus events - blur: convertFocusEvent, - focus: convertFocusEvent, - focusin: convertFocusEvent, - focusout: convertFocusEvent, - // gamepad events - gamepadconnected: convertGamepadEvent, - gamepaddisconnected: convertGamepadEvent, - // keyboard events - keydown: convertKeyboardEvent, - keypress: convertKeyboardEvent, - keyup: convertKeyboardEvent, - // mouse events - auxclick: convertMouseEvent, - click: convertMouseEvent, - dblclick: convertMouseEvent, - contextmenu: convertMouseEvent, - mousedown: convertMouseEvent, - mouseenter: convertMouseEvent, - mouseleave: convertMouseEvent, - mousemove: convertMouseEvent, - mouseout: convertMouseEvent, - mouseover: convertMouseEvent, - mouseup: convertMouseEvent, - scroll: convertMouseEvent, - // pointer events - gotpointercapture: convertPointerEvent, - lostpointercapture: convertPointerEvent, - pointercancel: convertPointerEvent, - pointerdown: convertPointerEvent, - pointerenter: convertPointerEvent, - pointerleave: convertPointerEvent, - pointerlockchange: convertPointerEvent, - pointerlockerror: convertPointerEvent, - pointermove: convertPointerEvent, - pointerout: convertPointerEvent, - pointerover: convertPointerEvent, - pointerup: convertPointerEvent, - // submit events - submit: convertSubmitEvent, - // touch events - touchcancel: convertTouchEvent, - touchend: convertTouchEvent, - touchmove: convertTouchEvent, - touchstart: convertTouchEvent, - // transition events - transitioncancel: convertTransitionEvent, - transitionend: convertTransitionEvent, - transitionrun: convertTransitionEvent, - transitionstart: convertTransitionEvent, - // wheel events - wheel: convertWheelEvent, -}; + return convertedObj; +} -function convertElement(element: EventTarget | HTMLElement | null): any { - if (!element || !("tagName" in element)) { +/** + * Serialize the current window selection. + */ +function serializeSelection( + maxDepth: number, + visited: WeakSet, +): object | null { + if (typeof window === "undefined" || !window.getSelection) { + return null; + } + const selection = window.getSelection(); + if (!selection) { return null; } - - const htmlElement = element as HTMLElement; - return { - ...convertGenericElement(htmlElement), - ...(htmlElement.tagName in elementConverters - ? elementConverters[htmlElement.tagName](htmlElement) - : {}), + type: selection.type, + anchorNode: selection.anchorNode + ? deepCloneClass(selection.anchorNode, maxDepth, visited) + : null, + anchorOffset: selection.anchorOffset, + focusNode: selection.focusNode + ? deepCloneClass(selection.focusNode, maxDepth, visited) + : null, + focusOffset: selection.focusOffset, + isCollapsed: selection.isCollapsed, + rangeCount: selection.rangeCount, + selectedText: selection.toString(), }; } -const convertGenericElement = (element: HTMLElement) => ({ - tagName: element.tagName, - boundingClientRect: { ...element.getBoundingClientRect() }, -}); - -const convertMediaElement = (element: HTMLMediaElement) => ({ - currentTime: element.currentTime, - duration: element.duration, - ended: element.ended, - error: element.error, - seeking: element.seeking, - volume: element.volume, -}); - -const elementConverters: { [key: string]: (element: any) => any } = { - AUDIO: convertMediaElement, - BUTTON: (element: HTMLButtonElement) => ({ value: element.value }), - DATA: (element: HTMLDataElement) => ({ value: element.value }), - DATALIST: (element: HTMLDataListElement) => ({ - options: Array.from(element.options).map(elementConverters["OPTION"]), - }), - DIALOG: (element: HTMLDialogElement) => ({ - returnValue: element.returnValue, - }), - FIELDSET: (element: HTMLFieldSetElement) => ({ - elements: Array.from(element.elements).map(convertElement), - }), - FORM: (element: HTMLFormElement) => ({ - elements: Array.from(element.elements).map(convertElement), - }), - INPUT: (element: HTMLInputElement) => ({ - value: element.value, - checked: element.checked, - }), - METER: (element: HTMLMeterElement) => ({ value: element.value }), - OPTION: (element: HTMLOptionElement) => ({ value: element.value }), - OUTPUT: (element: HTMLOutputElement) => ({ value: element.value }), - PROGRESS: (element: HTMLProgressElement) => ({ value: element.value }), - SELECT: (element: HTMLSelectElement) => ({ value: element.value }), - TEXTAREA: (element: HTMLTextAreaElement) => ({ value: element.value }), - VIDEO: convertMediaElement, -}; +/** + * Recursively convert a class-based object to a plain object. + */ +function deepCloneClass( + x: any, + _maxDepth: number, + visited: WeakSet, +): object { + const maxDepth = _maxDepth - 1; + + // Return an indicator if maxDepth is reached + if (maxDepth <= 0 && typeof x === "object") { + return maxDepthSignal; + } -const convertGamepad = (gamepad: Gamepad): e.GamepadObject => ({ - axes: Array.from(gamepad.axes), - buttons: Array.from(gamepad.buttons).map(convertGamepadButton), - connected: gamepad.connected, - id: gamepad.id, - index: gamepad.index, - mapping: gamepad.mapping, - timestamp: gamepad.timestamp, - hapticActuators: Array.from(gamepad.hapticActuators).map( - convertGamepadHapticActuator, - ), -}); + // Safety check: WeakSet only accepts objects (and not null) + if (!x || typeof x !== "object") { + return x; + } -const convertGamepadButton = ( - button: GamepadButton, -): e.GamepadButtonObject => ({ - pressed: button.pressed, - touched: button.touched, - value: button.value, -}); + if (visited.has(x)) { + return maxDepthSignal; + } + visited.add(x); + + try { + // Convert array-like class (e.g., NodeList, ClassList, HTMLCollection) + if ( + Array.isArray(x) || + (typeof x?.length === "number" && + typeof x[Symbol.iterator] === "function" && + !Object.prototype.toString.call(x).includes("Map") && + !(x instanceof CSSStyleDeclaration)) + ) { + return classToArray(x, maxDepth, visited); + } + + // Convert mapping-like class (e.g., Node, Map, Set) + return classToObject(x, maxDepth, visited); + } finally { + visited.delete(x); + } +} -const convertGamepadHapticActuator = ( - actuator: GamepadHapticActuator, -): e.GamepadHapticActuatorObject => ({ - type: actuator.type, -}); +/** + * Convert an array-like class to a plain array. + */ +function classToArray( + x: any, + maxDepth: number, + visited: WeakSet, +): Array { + const result: Array = []; + for (let i = 0; i < x.length; i++) { + // Skip anything that should not be converted + if (shouldIgnoreValue(x[i])) { + continue; + } + // Only push objects as if we haven't reached max depth + else if (typeof x[i] === "object") { + const converted = deepCloneClass(x[i], maxDepth, visited); + if (converted !== maxDepthSignal) { + result.push(converted); + } + } + // Add plain values if not skippable + else { + result.push(x[i]); + } + } + return result; +} -const convertFile = (file: File) => ({ - lastModified: file.lastModified, - name: file.name, - size: file.size, - type: file.type, -}); +/** + * Convert a mapping-like class to a plain JSON object. + * We must iterate through it with a for-loop in order to gain + * access to properties from all parent classes. + */ +function classToObject( + x: any, + maxDepth: number, + visited: WeakSet, +): object { + const result: { [key: string]: any } = {}; + for (const key in x) { + try { + // Skip anything that should not be converted + if (shouldIgnoreValue(x[key], key, x)) { + continue; + } + // Add objects as a property if we haven't reached max depth + else if (typeof x[key] === "object") { + const converted = deepCloneClass(x[key], maxDepth, visited); + if (converted !== maxDepthSignal) { + result[key] = converted; + } + } + // Add plain values if not skippable + else { + result[key] = x[key]; + } + } catch { + continue; + } + } -function convertDataTransferObject( - dataTransfer: DataTransfer | null, -): e.DataTransferObject | null { - if (!dataTransfer) { - return null; + // Explicitly include dataset if it exists (it might not be enumerable) + if ( + x && + typeof x === "object" && + "dataset" in x && + !Object.prototype.hasOwnProperty.call(result, "dataset") + ) { + const dataset = x["dataset"]; + if (!shouldIgnoreValue(dataset, "dataset", x)) { + const converted = deepCloneClass(dataset, maxDepth, visited); + if (converted !== maxDepthSignal) { + result["dataset"] = converted; + } + } } - const { dropEffect, effectAllowed, files, items, types } = dataTransfer; - return { - dropEffect, - effectAllowed, - files: Array.from(files).map(convertFile), - items: Array.from(items).map((item) => ({ - kind: item.kind, - type: item.type, - })), - types: Array.from(types), - }; -} -function convertSelection( - selection: Selection | null, -): e.SelectionObject | null { - if (!selection) { - return null; + // Explicitly include common input properties if they exist + const extraProps = ["value", "checked", "files", "type", "name"]; + for (const prop of extraProps) { + if ( + x && + typeof x === "object" && + prop in x && + !Object.prototype.hasOwnProperty.call(result, prop) + ) { + const val = x[prop]; + if (!shouldIgnoreValue(val, prop, x)) { + if (typeof val === "object") { + // Ensure files have enough depth to be serialized + const propDepth = prop === "files" ? Math.max(maxDepth, 3) : maxDepth; + const converted = deepCloneClass(val, propDepth, visited); + if (converted !== maxDepthSignal) { + result[prop] = converted; + } + } else { + result[prop] = val; + } + } + } } - const { - type, - anchorNode, - anchorOffset, - focusNode, - focusOffset, - isCollapsed, - rangeCount, - } = selection; - if (type === "None") { - return null; + + // Explicitly include form elements if they exist and are not enumerable + const win = typeof window !== "undefined" ? window : undefined; + // @ts-ignore + const FormClass = win + ? win.HTMLFormElement + : typeof HTMLFormElement !== "undefined" + ? HTMLFormElement + : undefined; + + if (FormClass && x instanceof FormClass && x.elements) { + for (let i = 0; i < x.elements.length; i++) { + const element = x.elements[i] as any; + if ( + element.name && + !Object.prototype.hasOwnProperty.call(result, element.name) && + !shouldIgnoreValue(element, element.name, x) + ) { + if (typeof element === "object") { + const converted = deepCloneClass(element, maxDepth, visited); + if (converted !== maxDepthSignal) { + result[element.name] = converted; + } + } else { + result[element.name] = element; + } + } + } } - return { - type, - anchorNode: convertElement(anchorNode), - anchorOffset, - focusNode: convertElement(focusNode), - focusOffset, - isCollapsed, - rangeCount, - selectedText: selection.toString(), - }; + + return result; } -function convertTouch({ - identifier, - pageX, - pageY, - screenX, - screenY, - clientX, - clientY, - force, - radiusX, - radiusY, - rotationAngle, - target, -}: Touch): e.TouchObject { - return { - identifier, - pageX, - pageY, - screenX, - screenY, - clientX, - clientY, - force, - radiusX, - radiusY, - rotationAngle, - target: convertElement(target), - }; +/** + * Check if a value is non-convertible or holds minimal value. + */ +function shouldIgnoreValue( + value: any, + keyName: string = "", + parent: any = undefined, +): boolean { + return ( + // Useless data + value === null || + value === undefined || + keyName.startsWith("__") || + (keyName.length > 0 && /^[A-Z_]+$/.test(keyName)) || + // Non-convertible types + typeof value === "function" || + value instanceof CSSStyleSheet || + value instanceof Window || + value instanceof Document || + keyName === "view" || + keyName === "size" || + keyName === "length" || + (parent instanceof CSSStyleDeclaration && value === "") || + // DOM Node Blacklist + (typeof Node !== "undefined" && + parent instanceof Node && + // Recursive properties + (keyName === "parentNode" || + keyName === "parentElement" || + keyName === "ownerDocument" || + keyName === "getRootNode" || + keyName === "childNodes" || + keyName === "children" || + keyName === "firstChild" || + keyName === "lastChild" || + keyName === "previousSibling" || + keyName === "nextSibling" || + keyName === "previousElementSibling" || + keyName === "nextElementSibling" || + // Potentially large data + keyName === "innerHTML" || + keyName === "outerHTML" || + // Reflow triggers + keyName === "offsetParent" || + keyName === "offsetWidth" || + keyName === "offsetHeight" || + keyName === "offsetLeft" || + keyName === "offsetTop" || + keyName === "clientTop" || + keyName === "clientLeft" || + keyName === "clientWidth" || + keyName === "clientHeight" || + keyName === "scrollWidth" || + keyName === "scrollHeight" || + keyName === "scrollTop" || + keyName === "scrollLeft")) + ); } diff --git a/src/js/packages/event-to-object/tests/event-to-object.test.ts b/src/js/packages/event-to-object/tests/event-to-object.test.ts index b7b8c68af..914beddac 100644 --- a/src/js/packages/event-to-object/tests/event-to-object.test.ts +++ b/src/js/packages/event-to-object/tests/event-to-object.test.ts @@ -1,14 +1,10 @@ // @ts-ignore import { window } from "./tooling/setup"; -import { test } from "uvu"; +import { test, expect } from "bun:test"; import { Event } from "happy-dom"; +import convert from "../src/index"; import { checkEventConversion } from "./tooling/check"; -import { - mockElementObject, - mockGamepad, - mockTouch, - mockTouchObject, -} from "./tooling/mock"; +import { mockGamepad, mockTouch, mockTouchObject } from "./tooling/mock"; type SimpleTestCase = { types: string[]; @@ -255,8 +251,8 @@ const simpleTestCases: SimpleTestCase[] = [ pressure: 0, tiltX: 0, tiltY: 0, - width: 0, - height: 0, + width: 1, + height: 1, isPrimary: false, twist: 0, tangentialPressure: 0, @@ -360,14 +356,14 @@ test("adds text of current selection", () => { `; const start = document.getElementById("start"); const end = document.getElementById("end"); - window.getSelection()!.setBaseAndExtent(start!, 0, end!, 0); + window.getSelection()!.setBaseAndExtent(start! as any, 0, end! as any, 0); checkEventConversion(new window.Event("fake"), { type: "fake", selection: { type: "Range", - anchorNode: { ...mockElementObject, tagName: "P" }, + anchorNode: {}, anchorOffset: 0, - focusNode: { ...mockElementObject, tagName: "P" }, + focusNode: {}, focusOffset: 0, isCollapsed: false, rangeCount: 1, @@ -378,4 +374,306 @@ test("adds text of current selection", () => { }); }); -test.run(); +test("includes data-* attributes in dataset", () => { + const div = document.createElement("div"); + div.setAttribute("data-test-value", "123"); + div.setAttribute("data-other", "foo"); + + const event = new window.Event("click"); + Object.defineProperty(event, "target", { + value: div, + enumerable: true, + writable: true, + }); + Object.defineProperty(event, "currentTarget", { + value: div, + enumerable: true, + writable: true, + }); + + checkEventConversion(event, { + target: { + dataset: { + testValue: "123", + other: "foo", + }, + }, + currentTarget: { + dataset: { + testValue: "123", + other: "foo", + }, + }, + }); +}); + +test("includes value and checked for radio and checkbox inputs", () => { + const radio = document.createElement("input"); + radio.type = "radio"; + radio.checked = true; + + const checkbox = document.createElement("input"); + checkbox.type = "checkbox"; + checkbox.checked = true; + + const radioEvent = new window.Event("change"); + Object.defineProperty(radioEvent, "target", { + value: radio, + enumerable: true, + writable: true, + }); + + checkEventConversion(radioEvent, { + target: { + value: "on", + checked: true, + type: "radio", + }, + }); + + const checkboxEvent = new window.Event("change"); + Object.defineProperty(checkboxEvent, "target", { + value: checkbox, + enumerable: true, + writable: true, + }); + + checkEventConversion(checkboxEvent, { + target: { + value: "on", + checked: true, + type: "checkbox", + }, + }); +}); + +test("excludes 'on' properties when missing", () => { + const div = document.createElement("div"); + div.onclick = () => {}; + // @ts-ignore + div.oncustom = null; + + const event = new window.Event("click"); + Object.defineProperty(event, "target", { + value: div, + enumerable: true, + writable: true, + }); + + const converted: any = convert(event); + expect(converted.target.onclick).toBeUndefined(); + expect(converted.target.oncustom).toBeUndefined(); +}); + +test("includes name property for inputs", () => { + const input = document.createElement("input"); + input.name = "test-input"; + input.value = "test-value"; + + const event = new window.Event("change"); + Object.defineProperty(event, "target", { + value: input, + enumerable: true, + writable: true, + }); + + checkEventConversion(event, { + target: { + name: "test-input", + value: "test-value", + }, + }); +}); + +test("includes checked property for checkboxes", () => { + const checkbox = document.createElement("input"); + checkbox.type = "checkbox"; + + // Test checked = true + checkbox.checked = true; + let event = new window.Event("change"); + Object.defineProperty(event, "target", { + value: checkbox, + enumerable: true, + writable: true, + }); + + checkEventConversion(event, { + target: { + checked: true, + type: "checkbox", + }, + }); + + // Test checked = false + checkbox.checked = false; + event = new window.Event("change"); + Object.defineProperty(event, "target", { + value: checkbox, + enumerable: true, + writable: true, + }); + + checkEventConversion(event, { + target: { + checked: false, + type: "checkbox", + }, + }); +}); + +test("converts file input with files", () => { + const input = window.document.createElement("input"); + input.type = "file"; + + // Create a mock file + const file = new window.File(["content"], "test.txt", { + type: "text/plain", + lastModified: 1234567890, + }); + + // Mock the files property + const mockFileList = { + 0: file, + length: 1, + item: (index: number) => (index === 0 ? file : null), + [Symbol.iterator]: function* () { + yield file; + }, + }; + + Object.defineProperty(input, "files", { + value: mockFileList, + writable: true, + }); + + const event = new window.Event("change"); + Object.defineProperty(event, "target", { + value: input, + enumerable: true, + writable: true, + }); + + const converted: any = convert(event); + + expect(converted.target.files).toBeDefined(); + expect(converted.target.files.length).toBe(1); + expect(converted.target.files[0].name).toBe("test.txt"); +}); + +test("converts form submission with file input", () => { + const form = window.document.createElement("form"); + const input = window.document.createElement("input"); + input.type = "file"; + input.name = "myFile"; + + // Create a mock file + const file = new window.File(["content"], "test.txt", { + type: "text/plain", + lastModified: 1234567890, + }); + + // Mock the files property + const mockFileList = { + 0: file, + length: 1, + item: (index: number) => (index === 0 ? file : null), + [Symbol.iterator]: function* () { + yield file; + }, + }; + + Object.defineProperty(input, "files", { + value: mockFileList, + writable: true, + }); + + form.appendChild(input); + + const event = new window.Event("submit"); + Object.defineProperty(event, "target", { + value: form, + enumerable: true, + writable: true, + }); + + const converted: any = convert(event); + + expect(converted.target.myFile).toBeDefined(); + expect(converted.target.myFile.files).toBeDefined(); + expect(converted.target.myFile.files.length).toBe(1); + expect(converted.target.myFile.files[0].name).toBe("test.txt"); +}); + +test("handles recursive structures", () => { + // Direct recursion + const recursive: any = { a: 1 }; + recursive.self = recursive; + + const converted: any = convert(recursive); + expect(converted.a).toBe(1); + expect(converted.self).toBeUndefined(); + + // Indirect recursion + const indirect: any = { name: "root" }; + const child: any = { name: "child" }; + indirect.child = child; + child.parent = indirect; + + const convertedIndirect: any = convert(indirect); + expect(convertedIndirect.name).toBe("root"); + expect(convertedIndirect.child.name).toBe("child"); + expect(convertedIndirect.child.parent).toBeUndefined(); +}); + +test("handles shared references without stopping", () => { + const shared = { name: "shared" }; + const root = { + left: { item: shared }, + right: { item: shared }, + }; + + const converted: any = convert(root); + expect(converted.left.item.name).toBe("shared"); + expect(converted.right.item.name).toBe("shared"); + expect(converted.left.item).not.toEqual({ __stop__: true }); + expect(converted.right.item).not.toEqual({ __stop__: true }); +}); + +test("handles recursive HTML node structures", () => { + const parent = window.document.createElement("div"); + const child = window.document.createElement("span"); + parent.appendChild(child); + + // Add explicit circular references to ensure we test recursion + // even if standard DOM properties are not enumerable in this environment. + (parent as any).circular = parent; + (child as any).parentLink = parent; + (parent as any).childLink = child; + + const converted: any = convert(parent); + + // Verify explicit cycle is handled + expect(converted.circular).toBeUndefined(); + + // Verify child link is handled + if (converted.childLink) { + expect(converted.childLink.parentLink).toBeUndefined(); + } + + // If the DOM implementation enumerates parentNode, it should be handled gracefully + if ( + converted.children && + converted.children.length > 0 && + converted.children[0].parentNode + ) { + expect(converted.children[0].parentNode).toBeUndefined(); + } +}); + +test("pass-through on unexpected non-object inputs", () => { + expect(convert(null as any)).toEqual(null); + expect(convert(undefined as any)).toEqual(undefined); + expect(convert(42 as any)).toEqual(42); + expect(convert("test" as any)).toEqual("test"); +}); diff --git a/src/js/packages/event-to-object/tests/tooling/check.ts b/src/js/packages/event-to-object/tests/tooling/check.ts index 33ff5ed5b..835823ad1 100644 --- a/src/js/packages/event-to-object/tests/tooling/check.ts +++ b/src/js/packages/event-to-object/tests/tooling/check.ts @@ -1,4 +1,4 @@ -import * as assert from "uvu/assert"; +import { expect } from "bun:test"; import { Event } from "happy-dom"; // @ts-ignore import lodash from "lodash"; @@ -8,39 +8,130 @@ export function checkEventConversion( givenEvent: Event, expectedConversion: any, ): void { + // Patch happy-dom event to make standard properties enumerable and defined + const standardProps = [ + "bubbles", + "cancelable", + "composed", + "currentTarget", + "defaultPrevented", + "eventPhase", + "isTrusted", + "target", + "type", + "srcElement", + "returnValue", + "altKey", + "metaKey", + "ctrlKey", + "shiftKey", + "elapsedTime", + "propertyName", + "pseudoElement", + ]; + + for (const prop of standardProps) { + if (prop in givenEvent) { + try { + Object.defineProperty(givenEvent, prop, { + enumerable: true, + value: (givenEvent as any)[prop], + writable: true, + configurable: true, + }); + } catch { + // ignore + } + } + } + + // timeStamp is special + try { + Object.defineProperty(givenEvent, "timeStamp", { + enumerable: true, + value: givenEvent.timeStamp || Date.now(), + writable: true, + configurable: true, + }); + } catch { + // ignore + } + + // Patch undefined properties that are expected to be 0 or null + const defaults: any = { + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0, + pageX: 0, + pageY: 0, + x: 0, + y: 0, + screenX: 0, + screenY: 0, + movementX: 0, + movementY: 0, + detail: 0, + which: 0, + relatedTarget: null, + }; + + for (const [key, value] of Object.entries(defaults)) { + if ((givenEvent as any)[key] === undefined && key in givenEvent) { + try { + Object.defineProperty(givenEvent, key, { + enumerable: true, + value: value, + writable: true, + configurable: true, + }); + } catch { + // ignore + } + } + } + const actualSerializedEvent = convert( // @ts-ignore givenEvent, + 5, ); if (!actualSerializedEvent) { - assert.equal(actualSerializedEvent, expectedConversion); + expect(actualSerializedEvent).toEqual(expectedConversion); return; } // too hard to compare - assert.equal(typeof actualSerializedEvent.timeStamp, "number"); - - assert.equal( - actualSerializedEvent, - lodash.merge( - { timeStamp: actualSerializedEvent.timeStamp, type: givenEvent.type }, - expectedConversionDefaults, - expectedConversion, - ), + // @ts-ignore + expect(typeof actualSerializedEvent.timeStamp).toBe("number"); + + // Remove nulls from expectedConversionDefaults because convert() strips nulls + const comparisonDefaults = { + bubbles: false, + cancelable: false, + composed: false, + defaultPrevented: false, + eventPhase: 0, + }; + + const expected = lodash.merge( + // @ts-ignore + { timeStamp: actualSerializedEvent.timeStamp, type: givenEvent.type }, + comparisonDefaults, + expectedConversion, ); + // Remove keys from expected that are null or undefined, because convert() strips them + for (const key in expected) { + if (expected[key] === null || expected[key] === undefined) { + delete expected[key]; + } + } + + // Use toMatchObject to allow extra properties in actual (like layerX, detail, etc.) + expect(actualSerializedEvent).toMatchObject(expected); + // verify result is JSON serializable JSON.stringify(actualSerializedEvent); } - -const expectedConversionDefaults = { - target: null, - currentTarget: null, - bubbles: false, - composed: false, - defaultPrevented: false, - eventPhase: undefined, - isTrusted: undefined, - selection: null, -}; diff --git a/src/js/packages/event-to-object/tests/tooling/mock.ts b/src/js/packages/event-to-object/tests/tooling/mock.ts index 81e506500..f118003a2 100644 --- a/src/js/packages/event-to-object/tests/tooling/mock.ts +++ b/src/js/packages/event-to-object/tests/tooling/mock.ts @@ -9,11 +9,6 @@ export const mockBoundingRect = { width: 0, }; -export const mockElementObject = { - tagName: null, - boundingClientRect: mockBoundingRect, -}; - export const mockElement = { tagName: null, getBoundingClientRect: () => mockBoundingRect, @@ -32,12 +27,6 @@ export const mockGamepad = { value: 0, }, ], - hapticActuators: [ - { - type: "vibration", - }, - ], - timestamp: undefined, }; export const mockTouch = { @@ -57,5 +46,5 @@ export const mockTouch = { export const mockTouchObject = { ...mockTouch, - target: mockElementObject, + target: {}, }; diff --git a/src/js/packages/event-to-object/tests/tooling/setup.js b/src/js/packages/event-to-object/tests/tooling/setup.js index 213578046..12b99fa41 100644 --- a/src/js/packages/event-to-object/tests/tooling/setup.js +++ b/src/js/packages/event-to-object/tests/tooling/setup.js @@ -1,5 +1,5 @@ -import { test } from "uvu"; import { Window } from "happy-dom"; +import { beforeAll, beforeEach } from "bun:test"; export const window = new Window(); @@ -9,6 +9,13 @@ export function setup() { global.navigator = window.navigator; global.getComputedStyle = window.getComputedStyle; global.requestAnimationFrame = null; + global.CSSStyleSheet = window.CSSStyleSheet; + global.CSSStyleDeclaration = window.CSSStyleDeclaration; + global.Window = window.constructor; + global.Document = window.document.constructor; + global.Node = window.Node; + global.Element = window.Element; + global.HTMLElement = window.HTMLElement; } export function reset() { @@ -18,5 +25,5 @@ export function reset() { window.getSelection().removeAllRanges(); } -test.before(setup); -test.before.each(reset); +beforeAll(setup); +beforeEach(reset); diff --git a/src/js/packages/event-to-object/tsconfig.json b/src/js/packages/event-to-object/tsconfig.json index b9a031fa9..4fec695a9 100644 --- a/src/js/packages/event-to-object/tsconfig.json +++ b/src/js/packages/event-to-object/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../../tsconfig.package.json", "compilerOptions": { + "composite": true, "outDir": "dist", - "rootDir": "src", - "composite": true + "rootDir": "src" }, + "extends": "../../tsconfig.json", "include": ["src"] } diff --git a/src/js/packages/event-to-object/tsconfig.tests.json b/src/js/packages/event-to-object/tsconfig.tests.json deleted file mode 100644 index 33be69a56..000000000 --- a/src/js/packages/event-to-object/tsconfig.tests.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "allowJs": false, - "skipLibCheck": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } -} diff --git a/src/js/packages/event-to-object/vitest.config.ts b/src/js/packages/event-to-object/vitest.config.ts new file mode 100644 index 000000000..c92f3607e --- /dev/null +++ b/src/js/packages/event-to-object/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["tests/**/*.test.ts"], + environment: "happy-dom", + }, +}); diff --git a/src/js/tsconfig.package.json b/src/js/tsconfig.json similarity index 54% rename from src/js/tsconfig.package.json rename to src/js/tsconfig.json index 9e7fe5f74..e3c400628 100644 --- a/src/js/tsconfig.package.json +++ b/src/js/tsconfig.json @@ -1,22 +1,25 @@ { "compilerOptions": { - "allowJs": false, + "allowJs": true, "allowSyntheticDefaultImports": true, "declaration": true, "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, - "jsx": "react", - "lib": ["DOM", "DOM.Iterable", "esnext"], - "module": "esnext", - "moduleResolution": "node", + "jsx": "react-jsx", + "jsxImportSource": "preact", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "module": "Preserve", + "moduleDetection": "force", + "moduleResolution": "bundler", "noEmitOnError": true, "noUnusedLocals": true, "resolveJsonModule": true, - "skipLibCheck": false, + "skipLibCheck": true, "sourceMap": true, "strict": true, - "target": "esnext" + "target": "ESNext", + "verbatimModuleSyntax": true } } diff --git a/src/py/reactpy/.gitignore b/src/py/reactpy/.gitignore deleted file mode 100644 index b4362ae8c..000000000 --- a/src/py/reactpy/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.coverage.* - -# --- Build Artifacts --- -reactpy/_static -js diff --git a/src/py/reactpy/MANIFEST.in b/src/py/reactpy/MANIFEST.in deleted file mode 100644 index b989938fa..000000000 --- a/src/py/reactpy/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -recursive-include src/reactpy/_client * -recursive-include src/reactpy/web/templates * -include src/reactpy/py.typed diff --git a/src/py/reactpy/README.md b/src/py/reactpy/README.md deleted file mode 100644 index 910a573a5..000000000 --- a/src/py/reactpy/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# ReactPy - -

- - - - - - - - - - - - - - - -

- ---- - -[ReactPy](https://reactpy.dev/) is a library for building user interfaces in Python without Javascript. ReactPy interfaces are made from components that look and behave similar to those found in [ReactJS](https://reactjs.org/). Designed with simplicity in mind, ReactPy can be used by those without web development experience while also being powerful enough to grow with your ambitions. diff --git a/src/py/reactpy/pyproject.toml b/src/py/reactpy/pyproject.toml deleted file mode 100644 index 56ad6a7c5..000000000 --- a/src/py/reactpy/pyproject.toml +++ /dev/null @@ -1,158 +0,0 @@ -[build-system] -requires = ["hatchling", "hatch-build-scripts>=0.0.4"] -build-backend = "hatchling.build" - -# --- Project -------------------------------------------------------------------------- - -[project] -name = "reactpy" -dynamic = ["version"] -description = 'Reactive user interfaces with pure Python' -readme = "README.md" -requires-python = ">=3.9" -license = "MIT" -keywords = ["react", "javascript", "reactpy", "component"] -authors = [{ name = "Ryan Morshead", email = "ryan.morshead@gmail.com" }] -classifiers = [ - "Development Status :: 4 - Beta", - "Programming Language :: Python", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", -] -dependencies = [ - "exceptiongroup >=1.0", - "typing-extensions >=3.10", - "mypy-extensions >=0.4.3", - "anyio >=3", - "jsonpatch >=1.32", - "fastjsonschema >=2.14.5", - "requests >=2", - "colorlog >=6", - "asgiref >=3", - "lxml >=4", -] -[project.optional-dependencies] -all = ["reactpy[starlette,sanic,fastapi,flask,tornado,testing]"] - -starlette = ["starlette >=0.13.6", "uvicorn[standard] >=0.19.0"] -sanic = [ - "sanic >=21", - "sanic-cors", - "tracerite>=1.1.1", - "setuptools", - "uvicorn[standard] >=0.19.0", -] -fastapi = ["fastapi >=0.63.0", "uvicorn[standard] >=0.19.0"] -flask = ["flask", "markupsafe>=1.1.1,<2.1", "flask-cors", "flask-sock"] -tornado = ["tornado"] -testing = ["playwright"] - -[project.urls] -Source = "https://github.com/reactive-python/reactpy" -Documentation = "https://github.com/reactive-python/reactpy#readme" -Issues = "https://github.com/reactive-python/reactpy/discussions" - -# --- Hatch ---------------------------------------------------------------------------- - -[tool.hatch.version] -path = "reactpy/__init__.py" - -[tool.hatch.envs.default] -features = ["all"] -pre-install-command = "hatch build --hooks-only" -dependencies = [ - "coverage[toml]>=6.5", - "pytest", - "pytest-asyncio>=0.23", - "pytest-mock", - "pytest-rerunfailures", - "pytest-timeout", - "responses", - "playwright", - # I'm not quite sure why this needs to be installed for tests with Sanic to pass - "sanic-testing", - # Used to generate model changes from layout update messages - "jsonpointer", -] -[tool.hatch.envs.default.scripts] -test = "playwright install && pytest {args:tests}" -test-cov = "playwright install && coverage run -m pytest {args:tests}" -cov-report = [ - # "- coverage combine", - "coverage report", -] -cov = ["test-cov {args}", "cov-report"] - -[tool.hatch.envs.default.env-vars] -REACTPY_DEBUG_MODE = "1" - -[tool.hatch.envs.lint] -features = ["all"] -dependencies = [ - "mypy==1.8", - "types-click", - "types-tornado", - "types-flask", - "types-requests", -] - -[tool.hatch.envs.lint.scripts] -types = "mypy --strict reactpy" -all = ["types"] - -[tool.hatch.build.targets.sdist] -artifacts = ["_static"] -exclude = ["scripts/", "tests/"] - -[tool.hatch.build.targets.wheel] -artifacts = ["_static"] -exclude = ["scripts/", "tests/"] - -[[tool.hatch.build.hooks.build-scripts.scripts]] -commands = [ - "cd .. && cd .. && cd js && npm install && npm run build", - "cd scripts && python copy_js_output.py", -] -artifacts = [] - -# --- Pytest --------------------------------------------------------------------------- - -[tool.pytest.ini_options] -testpaths = "tests" -xfail_strict = true -python_files = "*asserts.py test_*.py" -asyncio_mode = "auto" -log_cli_level = "INFO" - -# --- MyPy ----------------------------------------------------------------------------- - -[tool.mypy] -incremental = false -ignore_missing_imports = true -warn_unused_configs = true -warn_redundant_casts = true -warn_unused_ignores = true - -# --- Coverage ------------------------------------------------------------------------- - -[tool.coverage.run] -source_pkgs = ["reactpy"] -branch = false -parallel = false -omit = ["reactpy/__init__.py"] - -[tool.coverage.report] -fail_under = 100 -show_missing = true -skip_covered = true -sort = "Name" -exclude_lines = [ - "no ?cov", - '\.\.\.', - "if __name__ == .__main__.:", - "if TYPE_CHECKING:", -] -omit = ["reactpy/__main__.py"] diff --git a/src/py/reactpy/reactpy/__main__.py b/src/py/reactpy/reactpy/__main__.py deleted file mode 100644 index d70ddf684..000000000 --- a/src/py/reactpy/reactpy/__main__.py +++ /dev/null @@ -1,19 +0,0 @@ -import click - -import reactpy -from reactpy._console.rewrite_camel_case_props import rewrite_camel_case_props -from reactpy._console.rewrite_keys import rewrite_keys - - -@click.group() -@click.version_option(reactpy.__version__, prog_name=reactpy.__name__) -def app() -> None: - pass - - -app.add_command(rewrite_keys) -app.add_command(rewrite_camel_case_props) - - -if __name__ == "__main__": - app() diff --git a/src/py/reactpy/reactpy/backend/__init__.py b/src/py/reactpy/reactpy/backend/__init__.py deleted file mode 100644 index e08e50649..000000000 --- a/src/py/reactpy/reactpy/backend/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -import mimetypes -from logging import getLogger - -_logger = getLogger(__name__) - -# Fix for missing mime types due to OS corruption/misconfiguration -# Example: https://github.com/encode/starlette/issues/829 -if not mimetypes.inited: - mimetypes.init() -for extension, mime_type in { - ".js": "application/javascript", - ".css": "text/css", - ".json": "application/json", -}.items(): - if not mimetypes.types_map.get(extension): # pragma: no cover - _logger.warning( - "Mime type '%s = %s' is missing. Please research how to " - "fix missing mime types on your operating system.", - extension, - mime_type, - ) - mimetypes.add_type(mime_type, extension) diff --git a/src/py/reactpy/reactpy/backend/_common.py b/src/py/reactpy/reactpy/backend/_common.py deleted file mode 100644 index 0b7179092..000000000 --- a/src/py/reactpy/reactpy/backend/_common.py +++ /dev/null @@ -1,144 +0,0 @@ -from __future__ import annotations - -import asyncio -import os -from collections.abc import Awaitable, Sequence -from dataclasses import dataclass -from pathlib import Path, PurePosixPath -from typing import TYPE_CHECKING, Any, cast - -from reactpy import __file__ as _reactpy_file_path -from reactpy import html -from reactpy.config import REACTPY_WEB_MODULES_DIR -from reactpy.core.types import VdomDict -from reactpy.utils import vdom_to_html - -if TYPE_CHECKING: - import uvicorn - from asgiref.typing import ASGIApplication - -PATH_PREFIX = PurePosixPath("/_reactpy") -MODULES_PATH = PATH_PREFIX / "modules" -ASSETS_PATH = PATH_PREFIX / "assets" -STREAM_PATH = PATH_PREFIX / "stream" -CLIENT_BUILD_DIR = Path(_reactpy_file_path).parent / "_static" - - -async def serve_with_uvicorn( - app: ASGIApplication | Any, - host: str, - port: int, - started: asyncio.Event | None, -) -> None: - """Run a development server for an ASGI application""" - import uvicorn - - server = uvicorn.Server( - uvicorn.Config( - app, - host=host, - port=port, - loop="asyncio", - ) - ) - server.config.setup_event_loop() - coros: list[Awaitable[Any]] = [server.serve()] - - # If a started event is provided, then use it signal based on `server.started` - if started: - coros.append(_check_if_started(server, started)) - - try: - await asyncio.gather(*coros) - finally: - # Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's - # order of operations. So we need to make sure `shutdown()` always has an initialized - # list of `self.servers` to use. - if not hasattr(server, "servers"): # nocov - server.servers = [] - await asyncio.wait_for(server.shutdown(), timeout=3) - - -async def _check_if_started(server: uvicorn.Server, started: asyncio.Event) -> None: - while not server.started: - await asyncio.sleep(0.2) - started.set() - - -def safe_client_build_dir_path(path: str) -> Path: - """Prevent path traversal out of :data:`CLIENT_BUILD_DIR`""" - return traversal_safe_path( - CLIENT_BUILD_DIR, *("index.html" if path in {"", "/"} else path).split("/") - ) - - -def safe_web_modules_dir_path(path: str) -> Path: - """Prevent path traversal out of :data:`reactpy.config.REACTPY_WEB_MODULES_DIR`""" - return traversal_safe_path(REACTPY_WEB_MODULES_DIR.current, *path.split("/")) - - -def traversal_safe_path(root: str | Path, *unsafe: str | Path) -> Path: - """Raise a ``ValueError`` if the ``unsafe`` path resolves outside the root dir.""" - root = os.path.abspath(root) - - # Resolve relative paths but not symlinks - symlinks should be ok since their - # presence and where they point is under the control of the developer. - path = os.path.abspath(os.path.join(root, *unsafe)) - - if os.path.commonprefix([root, path]) != root: - # If the common prefix is not root directory we resolved outside the root dir - msg = "Unsafe path" - raise ValueError(msg) - - return Path(path) - - -def read_client_index_html(options: CommonOptions) -> str: - return ( - (CLIENT_BUILD_DIR / "index.html") - .read_text() - .format(__head__=vdom_head_elements_to_html(options.head)) - ) - - -def vdom_head_elements_to_html(head: Sequence[VdomDict] | VdomDict | str) -> str: - if isinstance(head, str): - return head - elif isinstance(head, dict): - if head.get("tagName") == "head": - head = cast(VdomDict, {**head, "tagName": ""}) - return vdom_to_html(head) - else: - return vdom_to_html(html._(*head)) - - -@dataclass -class CommonOptions: - """Options for ReactPy's built-in backed server implementations""" - - head: Sequence[VdomDict] | VdomDict | str = ( - html.title("ReactPy"), - html.link( - { - "rel": "icon", - "href": "/_reactpy/assets/reactpy-logo.ico", - "type": "image/x-icon", - } - ), - ) - """Add elements to the ```` of the application. - - For example, this can be used to customize the title of the page, link extra - scripts, or load stylesheets. - """ - - url_prefix: str = "" - """The URL prefix where ReactPy resources will be served from""" - - serve_index_route: bool = True - """Automatically generate and serve the index route (``/``)""" - - def __post_init__(self) -> None: - if self.url_prefix and not self.url_prefix.startswith("/"): - msg = "Expected 'url_prefix' to start with '/'" - raise ValueError(msg) diff --git a/src/py/reactpy/reactpy/backend/default.py b/src/py/reactpy/reactpy/backend/default.py deleted file mode 100644 index 37aad31af..000000000 --- a/src/py/reactpy/reactpy/backend/default.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -import asyncio -from logging import getLogger -from sys import exc_info -from typing import Any, NoReturn - -from reactpy.backend.types import BackendType -from reactpy.backend.utils import SUPPORTED_BACKENDS, all_implementations -from reactpy.types import RootComponentConstructor - -logger = getLogger(__name__) -_DEFAULT_IMPLEMENTATION: BackendType[Any] | None = None - - -# BackendType.Options -class Options: # nocov - """Configuration options that can be provided to the backend. - This definition should not be used/instantiated. It exists only for - type hinting purposes.""" - - def __init__(self, *args: Any, **kwds: Any) -> NoReturn: - msg = "Default implementation has no options." - raise ValueError(msg) - - -# BackendType.configure -def configure( - app: Any, component: RootComponentConstructor, options: None = None -) -> None: - """Configure the given app instance to display the given component""" - if options is not None: # nocov - msg = "Default implementation cannot be configured with options" - raise ValueError(msg) - return _default_implementation().configure(app, component) - - -# BackendType.create_development_app -def create_development_app() -> Any: - """Create an application instance for development purposes""" - return _default_implementation().create_development_app() - - -# BackendType.serve_development_app -async def serve_development_app( - app: Any, - host: str, - port: int, - started: asyncio.Event | None = None, -) -> None: - """Run an application using a development server""" - return await _default_implementation().serve_development_app( - app, host, port, started - ) - - -def _default_implementation() -> BackendType[Any]: - """Get the first available server implementation""" - global _DEFAULT_IMPLEMENTATION # noqa: PLW0603 - - if _DEFAULT_IMPLEMENTATION is not None: - return _DEFAULT_IMPLEMENTATION - - try: - implementation = next(all_implementations()) - except StopIteration: # nocov - logger.debug("Backend implementation import failed", exc_info=exc_info()) - supported_backends = ", ".join(SUPPORTED_BACKENDS) - msg = ( - "It seems you haven't installed a backend. To resolve this issue, " - "you can install a backend by running:\n\n" - '\033[1mpip install "reactpy[starlette]"\033[0m\n\n' - f"Other supported backends include: {supported_backends}." - ) - raise RuntimeError(msg) from None - else: - _DEFAULT_IMPLEMENTATION = implementation - return implementation diff --git a/src/py/reactpy/reactpy/backend/fastapi.py b/src/py/reactpy/reactpy/backend/fastapi.py deleted file mode 100644 index a0137a3dc..000000000 --- a/src/py/reactpy/reactpy/backend/fastapi.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -from fastapi import FastAPI - -from reactpy.backend import starlette - -# BackendType.Options -Options = starlette.Options - -# BackendType.configure -configure = starlette.configure - - -# BackendType.create_development_app -def create_development_app() -> FastAPI: - """Create a development ``FastAPI`` application instance.""" - return FastAPI(debug=True) - - -# BackendType.serve_development_app -serve_development_app = starlette.serve_development_app - -use_connection = starlette.use_connection - -use_websocket = starlette.use_websocket diff --git a/src/py/reactpy/reactpy/backend/flask.py b/src/py/reactpy/reactpy/backend/flask.py deleted file mode 100644 index 4401fb6f7..000000000 --- a/src/py/reactpy/reactpy/backend/flask.py +++ /dev/null @@ -1,303 +0,0 @@ -from __future__ import annotations - -import asyncio -import json -import logging -import os -from asyncio import Queue as AsyncQueue -from dataclasses import dataclass -from queue import Queue as ThreadQueue -from threading import Event as ThreadEvent -from threading import Thread -from typing import Any, Callable, NamedTuple, NoReturn, cast - -from flask import ( - Blueprint, - Flask, - Request, - copy_current_request_context, - request, - send_file, -) -from flask_cors import CORS -from flask_sock import Sock -from simple_websocket import Server as WebSocket -from werkzeug.serving import BaseWSGIServer, make_server - -import reactpy -from reactpy.backend._common import ( - ASSETS_PATH, - MODULES_PATH, - PATH_PREFIX, - STREAM_PATH, - CommonOptions, - read_client_index_html, - safe_client_build_dir_path, - safe_web_modules_dir_path, -) -from reactpy.backend.types import Connection, Location -from reactpy.core.hooks import ConnectionContext -from reactpy.core.hooks import use_connection as _use_connection -from reactpy.core.serve import serve_layout -from reactpy.core.types import ComponentType, RootComponentConstructor -from reactpy.utils import Ref - -logger = logging.getLogger(__name__) - - -# BackendType.Options -@dataclass -class Options(CommonOptions): - """Render server config for :func:`reactpy.backend.flask.configure`""" - - cors: bool | dict[str, Any] = False - """Enable or configure Cross Origin Resource Sharing (CORS) - - For more information see docs for ``flask_cors.CORS`` - """ - - -# BackendType.configure -def configure( - app: Flask, component: RootComponentConstructor, options: Options | None = None -) -> None: - """Configure the necessary ReactPy routes on the given app. - - Parameters: - app: An application instance - component: A component constructor - options: Options for configuring server behavior - """ - options = options or Options() - - api_bp = Blueprint(f"reactpy_api_{id(app)}", __name__, url_prefix=str(PATH_PREFIX)) - spa_bp = Blueprint( - f"reactpy_spa_{id(app)}", __name__, url_prefix=options.url_prefix - ) - - _setup_single_view_dispatcher_route(api_bp, options, component) - _setup_common_routes(api_bp, spa_bp, options) - - app.register_blueprint(api_bp) - app.register_blueprint(spa_bp) - - -# BackendType.create_development_app -def create_development_app() -> Flask: - """Create an application instance for development purposes""" - os.environ["FLASK_DEBUG"] = "true" - return Flask(__name__) - - -# BackendType.serve_development_app -async def serve_development_app( - app: Flask, - host: str, - port: int, - started: asyncio.Event | None = None, -) -> None: - """Run a development server for FastAPI""" - loop = asyncio.get_running_loop() - stopped = asyncio.Event() - - server: Ref[BaseWSGIServer] = Ref() - - def run_server() -> None: - server.current = make_server(host, port, app, threaded=True) - if started: - loop.call_soon_threadsafe(started.set) - try: - server.current.serve_forever() # type: ignore - finally: - loop.call_soon_threadsafe(stopped.set) - - thread = Thread(target=run_server, daemon=True) - thread.start() - - if started: - await started.wait() - - try: - await stopped.wait() - finally: - # we may have exited because this task was cancelled - server.current.shutdown() - # the thread should eventually join - thread.join(timeout=3) - # just double check it happened - if thread.is_alive(): # nocov - msg = "Failed to shutdown server." - raise RuntimeError(msg) - - -def use_websocket() -> WebSocket: - """A handle to the current websocket""" - return use_connection().carrier.websocket - - -def use_request() -> Request: - """Get the current ``Request``""" - return use_connection().carrier.request - - -def use_connection() -> Connection[_FlaskCarrier]: - """Get the current :class:`Connection`""" - conn = _use_connection() - if not isinstance(conn.carrier, _FlaskCarrier): # nocov - msg = f"Connection has unexpected carrier {conn.carrier}. Are you running with a Flask server?" - raise TypeError(msg) - return conn - - -def _setup_common_routes( - api_blueprint: Blueprint, - spa_blueprint: Blueprint, - options: Options, -) -> None: - cors_options = options.cors - if cors_options: # nocov - cors_params = cors_options if isinstance(cors_options, dict) else {} - CORS(api_blueprint, **cors_params) - - @api_blueprint.route(f"/{ASSETS_PATH.name}/") - def send_assets_dir(path: str = "") -> Any: - return send_file(safe_client_build_dir_path(f"assets/{path}")) - - @api_blueprint.route(f"/{MODULES_PATH.name}/") - def send_modules_dir(path: str = "") -> Any: - return send_file(safe_web_modules_dir_path(path), mimetype="text/javascript") - - index_html = read_client_index_html(options) - - if options.serve_index_route: - - @spa_blueprint.route("/") - @spa_blueprint.route("/") - def send_client_dir(_: str = "") -> Any: - return index_html - - -def _setup_single_view_dispatcher_route( - api_blueprint: Blueprint, options: Options, constructor: RootComponentConstructor -) -> None: - sock = Sock(api_blueprint) - - def model_stream(ws: WebSocket, path: str = "") -> None: - def send(value: Any) -> None: - ws.send(json.dumps(value)) - - def recv() -> Any: - return json.loads(ws.receive()) - - _dispatch_in_thread( - ws, - # remove any url prefix from path - path[len(options.url_prefix) :], - constructor(), - send, - recv, - ) - - sock.route(STREAM_PATH.name, endpoint="without_path")(model_stream) - sock.route(f"{STREAM_PATH.name}/", endpoint="with_path")(model_stream) - - -def _dispatch_in_thread( - websocket: WebSocket, - path: str, - component: ComponentType, - send: Callable[[Any], None], - recv: Callable[[], Any | None], -) -> NoReturn: - dispatch_thread_info_created = ThreadEvent() - dispatch_thread_info_ref: reactpy.Ref[_DispatcherThreadInfo | None] = reactpy.Ref( - None - ) - - @copy_current_request_context - def run_dispatcher() -> None: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - - thread_send_queue: ThreadQueue[Any] = ThreadQueue() - async_recv_queue: AsyncQueue[Any] = AsyncQueue() - - async def send_coro(value: Any) -> None: - thread_send_queue.put(value) - - async def main() -> None: - search = request.query_string.decode() - await serve_layout( - reactpy.Layout( - ConnectionContext( - component, - value=Connection( - scope=request.environ, - location=Location( - pathname=f"/{path}", - search=f"?{search}" if search else "", - ), - carrier=_FlaskCarrier(request, websocket), - ), - ), - ), - send_coro, - async_recv_queue.get, - ) - - main_future = asyncio.ensure_future(main(), loop=loop) - - dispatch_thread_info_ref.current = _DispatcherThreadInfo( - dispatch_loop=loop, - dispatch_future=main_future, - thread_send_queue=thread_send_queue, - async_recv_queue=async_recv_queue, - ) - dispatch_thread_info_created.set() - - loop.run_until_complete(main_future) - - Thread(target=run_dispatcher, daemon=True).start() - - dispatch_thread_info_created.wait() - dispatch_thread_info = cast(_DispatcherThreadInfo, dispatch_thread_info_ref.current) - - if dispatch_thread_info is None: - raise RuntimeError("Failed to create dispatcher thread") # nocov - - stop = ThreadEvent() - - def run_send() -> None: - while not stop.is_set(): - send(dispatch_thread_info.thread_send_queue.get()) - - Thread(target=run_send, daemon=True).start() - - try: - while True: - value = recv() - dispatch_thread_info.dispatch_loop.call_soon_threadsafe( - dispatch_thread_info.async_recv_queue.put_nowait, value - ) - finally: # nocov - dispatch_thread_info.dispatch_loop.call_soon_threadsafe( - dispatch_thread_info.dispatch_future.cancel - ) - - -class _DispatcherThreadInfo(NamedTuple): - dispatch_loop: asyncio.AbstractEventLoop - dispatch_future: asyncio.Future[Any] - thread_send_queue: ThreadQueue[Any] - async_recv_queue: AsyncQueue[Any] - - -@dataclass -class _FlaskCarrier: - """A simple wrapper for holding a Flask request and WebSocket""" - - request: Request - """The current request object""" - - websocket: WebSocket - """A handle to the current websocket""" diff --git a/src/py/reactpy/reactpy/backend/hooks.py b/src/py/reactpy/reactpy/backend/hooks.py deleted file mode 100644 index ec761ef0f..000000000 --- a/src/py/reactpy/reactpy/backend/hooks.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations # nocov - -from collections.abc import MutableMapping # nocov -from typing import Any # nocov - -from reactpy._warnings import warn # nocov -from reactpy.backend.types import Connection, Location # nocov -from reactpy.core.hooks import ConnectionContext, use_context # nocov - - -def use_connection() -> Connection[Any]: # nocov - """Get the current :class:`~reactpy.backend.types.Connection`.""" - warn( - "The module reactpy.backend.hooks has been deprecated and will be deleted in the future. " - "Call reactpy.use_connection instead.", - DeprecationWarning, - ) - - conn = use_context(ConnectionContext) - if conn is None: - msg = "No backend established a connection." - raise RuntimeError(msg) - return conn - - -def use_scope() -> MutableMapping[str, Any]: # nocov - """Get the current :class:`~reactpy.backend.types.Connection`'s scope.""" - warn( - "The module reactpy.backend.hooks has been deprecated and will be deleted in the future. " - "Call reactpy.use_scope instead.", - DeprecationWarning, - ) - - return use_connection().scope - - -def use_location() -> Location: # nocov - """Get the current :class:`~reactpy.backend.types.Connection`'s location.""" - warn( - "The module reactpy.backend.hooks has been deprecated and will be deleted in the future. " - "Call reactpy.use_location instead.", - DeprecationWarning, - ) - - return use_connection().location diff --git a/src/py/reactpy/reactpy/backend/sanic.py b/src/py/reactpy/reactpy/backend/sanic.py deleted file mode 100644 index d272fb4cf..000000000 --- a/src/py/reactpy/reactpy/backend/sanic.py +++ /dev/null @@ -1,231 +0,0 @@ -from __future__ import annotations - -import asyncio -import json -import logging -from dataclasses import dataclass -from typing import Any -from urllib import parse as urllib_parse -from uuid import uuid4 - -from sanic import Blueprint, Sanic, request, response -from sanic.config import Config -from sanic.server.websockets.connection import WebSocketConnection -from sanic_cors import CORS - -from reactpy.backend._common import ( - ASSETS_PATH, - MODULES_PATH, - PATH_PREFIX, - STREAM_PATH, - CommonOptions, - read_client_index_html, - safe_client_build_dir_path, - safe_web_modules_dir_path, - serve_with_uvicorn, -) -from reactpy.backend.types import Connection, Location -from reactpy.core.hooks import ConnectionContext -from reactpy.core.hooks import use_connection as _use_connection -from reactpy.core.layout import Layout -from reactpy.core.serve import RecvCoroutine, SendCoroutine, Stop, serve_layout -from reactpy.core.types import RootComponentConstructor - -logger = logging.getLogger(__name__) - - -# BackendType.Options -@dataclass -class Options(CommonOptions): - """Render server config for :func:`reactpy.backend.sanic.configure`""" - - cors: bool | dict[str, Any] = False - """Enable or configure Cross Origin Resource Sharing (CORS) - - For more information see docs for ``sanic_cors.CORS`` - """ - - -# BackendType.configure -def configure( - app: Sanic[Any, Any], - component: RootComponentConstructor, - options: Options | None = None, -) -> None: - """Configure an application instance to display the given component""" - options = options or Options() - - spa_bp = Blueprint(f"reactpy_spa_{id(app)}", url_prefix=options.url_prefix) - api_bp = Blueprint(f"reactpy_api_{id(app)}", url_prefix=str(PATH_PREFIX)) - - _setup_common_routes(api_bp, spa_bp, options) - _setup_single_view_dispatcher_route(api_bp, component, options) - - app.blueprint([spa_bp, api_bp]) - - -# BackendType.create_development_app -def create_development_app() -> Sanic[Any, Any]: - """Return a :class:`Sanic` app instance in test mode""" - Sanic.test_mode = True - logger.warning("Sanic.test_mode is now active") - return Sanic(f"reactpy_development_app_{uuid4().hex}", Config()) - - -# BackendType.serve_development_app -async def serve_development_app( - app: Sanic[Any, Any], - host: str, - port: int, - started: asyncio.Event | None = None, -) -> None: - """Run a development server for :mod:`sanic`""" - await serve_with_uvicorn(app, host, port, started) - - -def use_request() -> request.Request[Any, Any]: - """Get the current ``Request``""" - return use_connection().carrier.request - - -def use_websocket() -> WebSocketConnection: - """Get the current websocket""" - return use_connection().carrier.websocket - - -def use_connection() -> Connection[_SanicCarrier]: - """Get the current :class:`Connection`""" - conn = _use_connection() - if not isinstance(conn.carrier, _SanicCarrier): # nocov - msg = f"Connection has unexpected carrier {conn.carrier}. Are you running with a Sanic server?" - raise TypeError(msg) - return conn - - -def _setup_common_routes( - api_blueprint: Blueprint, - spa_blueprint: Blueprint, - options: Options, -) -> None: - cors_options = options.cors - if cors_options: # nocov - cors_params = cors_options if isinstance(cors_options, dict) else {} - CORS(api_blueprint, **cors_params) - - index_html = read_client_index_html(options) - - async def single_page_app_files( - request: request.Request[Any, Any], - _: str = "", - ) -> response.HTTPResponse: - return response.html(index_html) - - if options.serve_index_route: - spa_blueprint.add_route( - single_page_app_files, - "/", - name="single_page_app_files_root", - ) - spa_blueprint.add_route( - single_page_app_files, - "/<_:path>", - name="single_page_app_files_path", - ) - - async def asset_files( - request: request.Request[Any, Any], - path: str = "", - ) -> response.HTTPResponse: - path = urllib_parse.unquote(path) - return await response.file(safe_client_build_dir_path(f"assets/{path}")) - - api_blueprint.add_route(asset_files, f"/{ASSETS_PATH.name}/") - - async def web_module_files( - request: request.Request[Any, Any], - path: str, - _: str = "", # this is not used - ) -> response.HTTPResponse: - path = urllib_parse.unquote(path) - return await response.file( - safe_web_modules_dir_path(path), - mime_type="text/javascript", - ) - - api_blueprint.add_route(web_module_files, f"/{MODULES_PATH.name}/") - - -def _setup_single_view_dispatcher_route( - api_blueprint: Blueprint, - constructor: RootComponentConstructor, - options: Options, -) -> None: - async def model_stream( - request: request.Request[Any, Any], - socket: WebSocketConnection, - path: str = "", - ) -> None: - asgi_app = getattr(request.app, "_asgi_app", None) - scope = asgi_app.transport.scope if asgi_app else {} - if not scope: # nocov - logger.warning("No scope. Sanic may not be running with an ASGI server") - - send, recv = _make_send_recv_callbacks(socket) - await serve_layout( - Layout( - ConnectionContext( - constructor(), - value=Connection( - scope=scope, - location=Location( - pathname=f"/{path[len(options.url_prefix):]}", - search=( - f"?{request.query_string}" - if request.query_string - else "" - ), - ), - carrier=_SanicCarrier(request, socket), - ), - ) - ), - send, - recv, - ) - - api_blueprint.add_websocket_route( - model_stream, - f"/{STREAM_PATH.name}", - name="model_stream_root", - ) - api_blueprint.add_websocket_route( - model_stream, - f"/{STREAM_PATH.name}//", - name="model_stream_path", - ) - - -def _make_send_recv_callbacks( - socket: WebSocketConnection, -) -> tuple[SendCoroutine, RecvCoroutine]: - async def sock_send(value: Any) -> None: - await socket.send(json.dumps(value)) - - async def sock_recv() -> Any: - data = await socket.recv() - if data is None: - raise Stop() - return json.loads(data) - - return sock_send, sock_recv - - -@dataclass -class _SanicCarrier: - """A simple wrapper for holding connection information""" - - request: request.Request[Sanic[Any, Any], Any] - """The current request object""" - - websocket: WebSocketConnection - """A handle to the current websocket""" diff --git a/src/py/reactpy/reactpy/backend/starlette.py b/src/py/reactpy/reactpy/backend/starlette.py deleted file mode 100644 index 20e2b4478..000000000 --- a/src/py/reactpy/reactpy/backend/starlette.py +++ /dev/null @@ -1,185 +0,0 @@ -from __future__ import annotations - -import asyncio -import json -import logging -from collections.abc import Awaitable -from dataclasses import dataclass -from typing import Any, Callable - -from exceptiongroup import BaseExceptionGroup -from starlette.applications import Starlette -from starlette.middleware.cors import CORSMiddleware -from starlette.requests import Request -from starlette.responses import HTMLResponse -from starlette.staticfiles import StaticFiles -from starlette.websockets import WebSocket, WebSocketDisconnect - -from reactpy.backend._common import ( - ASSETS_PATH, - CLIENT_BUILD_DIR, - MODULES_PATH, - STREAM_PATH, - CommonOptions, - read_client_index_html, - serve_with_uvicorn, -) -from reactpy.backend.types import Connection, Location -from reactpy.config import REACTPY_WEB_MODULES_DIR -from reactpy.core.hooks import ConnectionContext -from reactpy.core.hooks import use_connection as _use_connection -from reactpy.core.layout import Layout -from reactpy.core.serve import RecvCoroutine, SendCoroutine, serve_layout -from reactpy.core.types import RootComponentConstructor - -logger = logging.getLogger(__name__) - - -# BackendType.Options -@dataclass -class Options(CommonOptions): - """Render server config for :func:`reactpy.backend.starlette.configure`""" - - cors: bool | dict[str, Any] = False - """Enable or configure Cross Origin Resource Sharing (CORS) - - For more information see docs for ``starlette.middleware.cors.CORSMiddleware`` - """ - - -# BackendType.configure -def configure( - app: Starlette, - component: RootComponentConstructor, - options: Options | None = None, -) -> None: - """Configure the necessary ReactPy routes on the given app. - - Parameters: - app: An application instance - component: A component constructor - options: Options for configuring server behavior - """ - options = options or Options() - - # this route should take priority so set up it up first - _setup_single_view_dispatcher_route(options, app, component) - - _setup_common_routes(options, app) - - -# BackendType.create_development_app -def create_development_app() -> Starlette: - """Return a :class:`Starlette` app instance in debug mode""" - return Starlette(debug=True) - - -# BackendType.serve_development_app -async def serve_development_app( - app: Starlette, - host: str, - port: int, - started: asyncio.Event | None = None, -) -> None: - """Run a development server for starlette""" - await serve_with_uvicorn(app, host, port, started) - - -def use_websocket() -> WebSocket: - """Get the current WebSocket object""" - return use_connection().carrier - - -def use_connection() -> Connection[WebSocket]: - conn = _use_connection() - if not isinstance(conn.carrier, WebSocket): # nocov - msg = f"Connection has unexpected carrier {conn.carrier}. Are you running with a Flask server?" - raise TypeError(msg) - return conn - - -def _setup_common_routes(options: Options, app: Starlette) -> None: - cors_options = options.cors - if cors_options: # nocov - cors_params = ( - cors_options if isinstance(cors_options, dict) else {"allow_origins": ["*"]} - ) - app.add_middleware(CORSMiddleware, **cors_params) - - # This really should be added to the APIRouter, but there's a bug in Starlette - # BUG: https://github.com/tiangolo/fastapi/issues/1469 - url_prefix = options.url_prefix - - app.mount( - str(MODULES_PATH), - StaticFiles(directory=REACTPY_WEB_MODULES_DIR.current, check_dir=False), - ) - app.mount( - str(ASSETS_PATH), - StaticFiles(directory=CLIENT_BUILD_DIR / "assets", check_dir=False), - ) - # register this last so it takes least priority - index_route = _make_index_route(options) - - if options.serve_index_route: - app.add_route(f"{url_prefix}/", index_route) - app.add_route(url_prefix + "/{path:path}", index_route) - - -def _make_index_route(options: Options) -> Callable[[Request], Awaitable[HTMLResponse]]: - index_html = read_client_index_html(options) - - async def serve_index(request: Request) -> HTMLResponse: - return HTMLResponse(index_html) - - return serve_index - - -def _setup_single_view_dispatcher_route( - options: Options, app: Starlette, component: RootComponentConstructor -) -> None: - async def model_stream(socket: WebSocket) -> None: - await socket.accept() - send, recv = _make_send_recv_callbacks(socket) - - pathname = "/" + socket.scope["path_params"].get("path", "") - pathname = pathname[len(options.url_prefix) :] or "/" - search = socket.scope["query_string"].decode() - - try: - await serve_layout( - Layout( - ConnectionContext( - component(), - value=Connection( - scope=socket.scope, - location=Location(pathname, f"?{search}" if search else ""), - carrier=socket, - ), - ) - ), - send, - recv, - ) - except BaseExceptionGroup as egroup: - for e in egroup.exceptions: - if isinstance(e, WebSocketDisconnect): - logger.info(f"WebSocket disconnect: {e.code}") - break - else: # nocov - raise - - app.add_websocket_route(str(STREAM_PATH), model_stream) - app.add_websocket_route(f"{STREAM_PATH}/{{path:path}}", model_stream) - - -def _make_send_recv_callbacks( - socket: WebSocket, -) -> tuple[SendCoroutine, RecvCoroutine]: - async def sock_send(value: Any) -> None: - await socket.send_text(json.dumps(value)) - - async def sock_recv() -> Any: - return json.loads(await socket.receive_text()) - - return sock_send, sock_recv diff --git a/src/py/reactpy/reactpy/backend/tornado.py b/src/py/reactpy/reactpy/backend/tornado.py deleted file mode 100644 index bd339c5b9..000000000 --- a/src/py/reactpy/reactpy/backend/tornado.py +++ /dev/null @@ -1,235 +0,0 @@ -from __future__ import annotations - -import asyncio -import json -from asyncio import Queue as AsyncQueue -from asyncio.futures import Future -from typing import Any -from urllib.parse import urljoin - -from tornado.httpserver import HTTPServer -from tornado.httputil import HTTPServerRequest -from tornado.log import enable_pretty_logging -from tornado.platform.asyncio import AsyncIOMainLoop -from tornado.web import Application, RequestHandler, StaticFileHandler -from tornado.websocket import WebSocketHandler -from tornado.wsgi import WSGIContainer -from typing_extensions import TypeAlias - -from reactpy.backend._common import ( - ASSETS_PATH, - CLIENT_BUILD_DIR, - MODULES_PATH, - STREAM_PATH, - CommonOptions, - read_client_index_html, -) -from reactpy.backend.types import Connection, Location -from reactpy.config import REACTPY_WEB_MODULES_DIR -from reactpy.core.hooks import ConnectionContext -from reactpy.core.hooks import use_connection as _use_connection -from reactpy.core.layout import Layout -from reactpy.core.serve import serve_layout -from reactpy.core.types import ComponentConstructor - -# BackendType.Options -Options = CommonOptions - - -# BackendType.configure -def configure( - app: Application, - component: ComponentConstructor, - options: CommonOptions | None = None, -) -> None: - """Configure the necessary ReactPy routes on the given app. - - Parameters: - app: An application instance - component: A component constructor - options: Options for configuring server behavior - """ - options = options or Options() - _add_handler( - app, - options, - ( - # this route should take priority so set up it up first - _setup_single_view_dispatcher_route(component, options) - + _setup_common_routes(options) - ), - ) - - -# BackendType.create_development_app -def create_development_app() -> Application: - return Application(debug=True) - - -# BackendType.serve_development_app -async def serve_development_app( - app: Application, - host: str, - port: int, - started: asyncio.Event | None = None, -) -> None: - enable_pretty_logging() - - AsyncIOMainLoop.current().install() - - server = HTTPServer(app) - server.listen(port, host) - - if started: - # at this point the server is accepting connection - started.set() - - try: - # block forever - tornado has already set up its own background tasks - await asyncio.get_running_loop().create_future() - finally: - # stop accepting new connections - server.stop() - # wait for existing connections to complete - await server.close_all_connections() - - -def use_request() -> HTTPServerRequest: - """Get the current ``HTTPServerRequest``""" - return use_connection().carrier - - -def use_connection() -> Connection[HTTPServerRequest]: - conn = _use_connection() - if not isinstance(conn.carrier, HTTPServerRequest): # nocov - msg = f"Connection has unexpected carrier {conn.carrier}. Are you running with a Flask server?" - raise TypeError(msg) - return conn - - -_RouteHandlerSpecs: TypeAlias = "list[tuple[str, type[RequestHandler], Any]]" - - -def _setup_common_routes(options: Options) -> _RouteHandlerSpecs: - return [ - ( - rf"{MODULES_PATH}/(.*)", - StaticFileHandler, - {"path": str(REACTPY_WEB_MODULES_DIR.current)}, - ), - ( - rf"{ASSETS_PATH}/(.*)", - StaticFileHandler, - {"path": str(CLIENT_BUILD_DIR / "assets")}, - ), - ] + ( - [ - ( - r"/(.*)", - IndexHandler, - {"index_html": read_client_index_html(options)}, - ), - ] - if options.serve_index_route - else [] - ) - - -def _add_handler( - app: Application, options: Options, handlers: _RouteHandlerSpecs -) -> None: - prefixed_handlers: list[Any] = [ - (urljoin(options.url_prefix, route_pattern), *tuple(handler_info)) - for route_pattern, *handler_info in handlers - ] - app.add_handlers(r".*", prefixed_handlers) - - -def _setup_single_view_dispatcher_route( - constructor: ComponentConstructor, options: Options -) -> _RouteHandlerSpecs: - return [ - ( - rf"{STREAM_PATH}/(.*)", - ModelStreamHandler, - {"component_constructor": constructor, "url_prefix": options.url_prefix}, - ), - ( - str(STREAM_PATH), - ModelStreamHandler, - {"component_constructor": constructor, "url_prefix": options.url_prefix}, - ), - ] - - -class IndexHandler(RequestHandler): - _index_html: str - - def initialize(self, index_html: str) -> None: - self._index_html = index_html - - async def get(self, _: str) -> None: - self.finish(self._index_html) - - -class ModelStreamHandler(WebSocketHandler): - """A web-socket handler that serves up a new model stream to each new client""" - - _dispatch_future: Future[None] - _message_queue: AsyncQueue[str] - - def initialize( - self, component_constructor: ComponentConstructor, url_prefix: str - ) -> None: - self._component_constructor = component_constructor - self._url_prefix = url_prefix - - async def open(self, path: str = "", *args: Any, **kwargs: Any) -> None: - message_queue: AsyncQueue[str] = AsyncQueue() - - async def send(value: Any) -> None: - await self.write_message(json.dumps(value)) - - async def recv() -> Any: - return json.loads(await message_queue.get()) - - self._message_queue = message_queue - self._dispatch_future = asyncio.ensure_future( - serve_layout( - Layout( - ConnectionContext( - self._component_constructor(), - value=Connection( - scope=_FAKE_WSGI_CONTAINER.environ(self.request), - location=Location( - pathname=f"/{path[len(self._url_prefix):]}", - search=( - f"?{self.request.query}" - if self.request.query - else "" - ), - ), - carrier=self.request, - ), - ) - ), - send, - recv, - ) - ) - - async def on_message(self, message: str | bytes) -> None: - await self._message_queue.put( - message if isinstance(message, str) else message.decode() - ) - - def on_close(self) -> None: - if not self._dispatch_future.done(): - self._dispatch_future.cancel() - - -# The interface for WSGIContainer.environ changed in Tornado version 6.3 from -# a staticmethod to an instance method. Since we're not that concerned with -# the details of the WSGI app itself, we can just use a fake one. -# see: https://github.com/tornadoweb/tornado/pull/3231#issuecomment-1518957578 -_FAKE_WSGI_CONTAINER = WSGIContainer(lambda *a, **kw: iter([])) diff --git a/src/py/reactpy/reactpy/backend/types.py b/src/py/reactpy/reactpy/backend/types.py deleted file mode 100644 index 51e7bef04..000000000 --- a/src/py/reactpy/reactpy/backend/types.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -import asyncio -from collections.abc import MutableMapping -from dataclasses import dataclass -from typing import Any, Callable, Generic, Protocol, TypeVar, runtime_checkable - -from reactpy.core.types import RootComponentConstructor - -_App = TypeVar("_App") - - -@runtime_checkable -class BackendType(Protocol[_App]): - """Common interface for built-in web server/framework integrations""" - - Options: Callable[..., Any] - """A constructor for options passed to :meth:`BackendType.configure`""" - - def configure( - self, - app: _App, - component: RootComponentConstructor, - options: Any | None = None, - ) -> None: - """Configure the given app instance to display the given component""" - - def create_development_app(self) -> _App: - """Create an application instance for development purposes""" - - async def serve_development_app( - self, - app: _App, - host: str, - port: int, - started: asyncio.Event | None = None, - ) -> None: - """Run an application using a development server""" - - -_Carrier = TypeVar("_Carrier") - - -@dataclass -class Connection(Generic[_Carrier]): - """Represents a connection with a client""" - - scope: MutableMapping[str, Any] - """An ASGI scope or WSGI environment dictionary""" - - location: Location - """The current location (URL)""" - - carrier: _Carrier - """How the connection is mediated. For example, a request or websocket. - - This typically depends on the backend implementation. - """ - - -@dataclass -class Location: - """Represents the current location (URL) - - Analogous to, but not necessarily identical to, the client-side - ``document.location`` object. - """ - - pathname: str - """the path of the URL for the location""" - - search: str - """A search or query string - a '?' followed by the parameters of the URL. - - If there are no search parameters this should be an empty string - """ diff --git a/src/py/reactpy/reactpy/backend/utils.py b/src/py/reactpy/reactpy/backend/utils.py deleted file mode 100644 index 74e87bb7b..000000000 --- a/src/py/reactpy/reactpy/backend/utils.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -import asyncio -import logging -import socket -import sys -from collections.abc import Iterator -from contextlib import closing -from importlib import import_module -from typing import Any - -from reactpy.backend.types import BackendType -from reactpy.types import RootComponentConstructor - -logger = logging.getLogger(__name__) - -SUPPORTED_BACKENDS = ( - "fastapi", - "sanic", - "tornado", - "flask", - "starlette", -) - - -def run( - component: RootComponentConstructor, - host: str = "127.0.0.1", - port: int | None = None, - implementation: BackendType[Any] | None = None, -) -> None: - """Run a component with a development server""" - logger.warning(_DEVELOPMENT_RUN_FUNC_WARNING) - - implementation = implementation or import_module("reactpy.backend.default") - app = implementation.create_development_app() - implementation.configure(app, component) - port = port or find_available_port(host) - app_cls = type(app) - - logger.info( - "ReactPy is running with '%s.%s' at http://%s:%s", - app_cls.__module__, - app_cls.__name__, - host, - port, - ) - asyncio.run(implementation.serve_development_app(app, host, port)) - - -def find_available_port(host: str, port_min: int = 8000, port_max: int = 9000) -> int: - """Get a port that's available for the given host and port range""" - for port in range(port_min, port_max): - with closing(socket.socket()) as sock: - try: - if sys.platform in ("linux", "darwin"): - # Fixes bug on Unix-like systems where every time you restart the - # server you'll get a different port on Linux. This cannot be set - # on Windows otherwise address will always be reused. - # Ref: https://stackoverflow.com/a/19247688/3159288 - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((host, port)) - except OSError: - pass - else: - return port - msg = f"Host {host!r} has no available port in range {port_max}-{port_max}" - raise RuntimeError(msg) - - -def all_implementations() -> Iterator[BackendType[Any]]: - """Yield all available server implementations""" - for name in SUPPORTED_BACKENDS: - try: - import_module(name) - except ImportError: # nocov - logger.debug("Failed to import %s", name, exc_info=True) - continue - - reactpy_backend_name = f"{__name__.rsplit('.', 1)[0]}.{name}" - yield import_module(reactpy_backend_name) - - -_DEVELOPMENT_RUN_FUNC_WARNING = """\ -The `run()` function is only intended for testing during development! To run \ -in production, refer to the docs on how to use reactpy.backend.*.configure.\ -""" diff --git a/src/py/reactpy/reactpy/core/component.py b/src/py/reactpy/reactpy/core/component.py deleted file mode 100644 index f825aac71..000000000 --- a/src/py/reactpy/reactpy/core/component.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -import inspect -from functools import wraps -from typing import Any, Callable - -from reactpy.core.types import ComponentType, VdomDict - - -def component( - function: Callable[..., ComponentType | VdomDict | str | None] -) -> Callable[..., Component]: - """A decorator for defining a new component. - - Parameters: - function: The component's :meth:`reactpy.core.proto.ComponentType.render` function. - """ - sig = inspect.signature(function) - - if "key" in sig.parameters and sig.parameters["key"].kind in ( - inspect.Parameter.KEYWORD_ONLY, - inspect.Parameter.POSITIONAL_OR_KEYWORD, - ): - msg = f"Component render function {function} uses reserved parameter 'key'" - raise TypeError(msg) - - @wraps(function) - def constructor(*args: Any, key: Any | None = None, **kwargs: Any) -> Component: - return Component(function, key, args, kwargs, sig) - - return constructor - - -class Component: - """An object for rending component models.""" - - __slots__ = "__weakref__", "_func", "_args", "_kwargs", "_sig", "key", "type" - - def __init__( - self, - function: Callable[..., ComponentType | VdomDict | str | None], - key: Any | None, - args: tuple[Any, ...], - kwargs: dict[str, Any], - sig: inspect.Signature, - ) -> None: - self.key = key - self.type = function - self._args = args - self._kwargs = kwargs - self._sig = sig - - def render(self) -> ComponentType | VdomDict | str | None: - return self.type(*self._args, **self._kwargs) - - def __repr__(self) -> str: - try: - args = self._sig.bind(*self._args, **self._kwargs).arguments - except TypeError: - return f"{self.type.__name__}(...)" - else: - items = ", ".join(f"{k}={v!r}" for k, v in args.items()) - if items: - return f"{self.type.__name__}({id(self):02x}, {items})" - else: - return f"{self.type.__name__}({id(self):02x})" diff --git a/src/py/reactpy/reactpy/core/serve.py b/src/py/reactpy/reactpy/core/serve.py deleted file mode 100644 index 3a540af59..000000000 --- a/src/py/reactpy/reactpy/core/serve.py +++ /dev/null @@ -1,83 +0,0 @@ -from __future__ import annotations - -from collections.abc import Awaitable -from logging import getLogger -from typing import Callable -from warnings import warn - -from anyio import create_task_group -from anyio.abc import TaskGroup - -from reactpy.config import REACTPY_DEBUG_MODE -from reactpy.core.types import LayoutEventMessage, LayoutType, LayoutUpdateMessage - -logger = getLogger(__name__) - - -SendCoroutine = Callable[[LayoutUpdateMessage], Awaitable[None]] -"""Send model patches given by a dispatcher""" - -RecvCoroutine = Callable[[], Awaitable[LayoutEventMessage]] -"""Called by a dispatcher to return a :class:`reactpy.core.layout.LayoutEventMessage` - -The event will then trigger an :class:`reactpy.core.proto.EventHandlerType` in a layout. -""" - - -class Stop(BaseException): - """Deprecated - - Stop serving changes and events - - Raising this error will tell dispatchers to gracefully exit. Typically this is - called by code running inside a layout to tell it to stop rendering. - """ - - -async def serve_layout( - layout: LayoutType[LayoutUpdateMessage, LayoutEventMessage], - send: SendCoroutine, - recv: RecvCoroutine, -) -> None: - """Run a dispatch loop for a single view instance""" - async with layout: - try: - async with create_task_group() as task_group: - task_group.start_soon(_single_outgoing_loop, layout, send) - task_group.start_soon(_single_incoming_loop, task_group, layout, recv) - except Stop: # nocov - warn( - "The Stop exception is deprecated and will be removed in a future version", - UserWarning, - stacklevel=1, - ) - logger.info(f"Stopped serving {layout}") - - -async def _single_outgoing_loop( - layout: LayoutType[LayoutUpdateMessage, LayoutEventMessage], send: SendCoroutine -) -> None: - while True: - update = await layout.render() - try: - await send(update) - except Exception: # nocov - if not REACTPY_DEBUG_MODE.current: - msg = ( - "Failed to send update. More info may be available " - "if you enabling debug mode by setting " - "`reactpy.config.REACTPY_DEBUG_MODE.current = True`." - ) - logger.error(msg) - raise - - -async def _single_incoming_loop( - task_group: TaskGroup, - layout: LayoutType[LayoutUpdateMessage, LayoutEventMessage], - recv: RecvCoroutine, -) -> None: - while True: - # We need to fire and forget here so that we avoid waiting on the completion - # of this event handler before receiving and running the next one. - task_group.start_soon(layout.deliver, await recv()) diff --git a/src/py/reactpy/reactpy/core/types.py b/src/py/reactpy/reactpy/core/types.py deleted file mode 100644 index b451be30a..000000000 --- a/src/py/reactpy/reactpy/core/types.py +++ /dev/null @@ -1,248 +0,0 @@ -from __future__ import annotations - -import sys -from collections import namedtuple -from collections.abc import Mapping, Sequence -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generic, - Literal, - NamedTuple, - Protocol, - TypeVar, - overload, - runtime_checkable, -) - -from typing_extensions import TypeAlias, TypedDict - -_Type = TypeVar("_Type") - - -if TYPE_CHECKING or sys.version_info < (3, 9) or sys.version_info >= (3, 11): - - class State(NamedTuple, Generic[_Type]): - value: _Type - set_value: Callable[[_Type | Callable[[_Type], _Type]], None] - -else: # nocov - State = namedtuple("State", ("value", "set_value")) - - -ComponentConstructor = Callable[..., "ComponentType"] -"""Simple function returning a new component""" - -RootComponentConstructor = Callable[[], "ComponentType"] -"""The root component should be constructed by a function accepting no arguments.""" - - -Key: TypeAlias = "str | int" - - -_OwnType = TypeVar("_OwnType") - - -@runtime_checkable -class ComponentType(Protocol): - """The expected interface for all component-like objects""" - - key: Key | None - """An identifier which is unique amongst a component's immediate siblings""" - - type: Any - """The function or class defining the behavior of this component - - This is used to see if two component instances share the same definition. - """ - - def render(self) -> VdomDict | ComponentType | str | None: - """Render the component's view model.""" - - -_Render_co = TypeVar("_Render_co", covariant=True) -_Event_contra = TypeVar("_Event_contra", contravariant=True) - - -@runtime_checkable -class LayoutType(Protocol[_Render_co, _Event_contra]): - """Renders and delivers, updates to views and events to handlers, respectively""" - - async def render(self) -> _Render_co: - """Render an update to a view""" - - async def deliver(self, event: _Event_contra) -> None: - """Relay an event to its respective handler""" - - async def __aenter__(self) -> LayoutType[_Render_co, _Event_contra]: - """Prepare the layout for its first render""" - - async def __aexit__( - self, - exc_type: type[Exception], - exc_value: Exception, - traceback: TracebackType, - ) -> bool | None: - """Clean up the view after its final render""" - - -VdomAttributes = Mapping[str, Any] -"""Describes the attributes of a :class:`VdomDict`""" - -VdomChild: TypeAlias = "ComponentType | VdomDict | str | None | Any" -"""A single child element of a :class:`VdomDict`""" - -VdomChildren: TypeAlias = "Sequence[VdomChild] | VdomChild" -"""Describes a series of :class:`VdomChild` elements""" - - -class _VdomDictOptional(TypedDict, total=False): - key: Key | None - children: Sequence[ComponentType | VdomChild] - attributes: VdomAttributes - eventHandlers: EventHandlerDict - importSource: ImportSourceDict - - -class _VdomDictRequired(TypedDict, total=True): - tagName: str - - -class VdomDict(_VdomDictRequired, _VdomDictOptional): - """A :ref:`VDOM` dictionary""" - - -class ImportSourceDict(TypedDict): - source: str - fallback: Any - sourceType: str - unmountBeforeUpdate: bool - - -class _OptionalVdomJson(TypedDict, total=False): - key: Key - error: str - children: list[Any] - attributes: dict[str, Any] - eventHandlers: dict[str, _JsonEventTarget] - importSource: _JsonImportSource - - -class _RequiredVdomJson(TypedDict, total=True): - tagName: str - - -class VdomJson(_RequiredVdomJson, _OptionalVdomJson): - """A JSON serializable form of :class:`VdomDict` matching the :data:`VDOM_JSON_SCHEMA`""" - - -class _JsonEventTarget(TypedDict): - target: str - preventDefault: bool - stopPropagation: bool - - -class _JsonImportSource(TypedDict): - source: str - fallback: Any - - -EventHandlerMapping = Mapping[str, "EventHandlerType"] -"""A generic mapping between event names to their handlers""" - -EventHandlerDict: TypeAlias = "dict[str, EventHandlerType]" -"""A dict mapping between event names to their handlers""" - - -class EventHandlerFunc(Protocol): - """A coroutine which can handle event data""" - - async def __call__(self, data: Sequence[Any]) -> None: ... - - -@runtime_checkable -class EventHandlerType(Protocol): - """Defines a handler for some event""" - - prevent_default: bool - """Whether to block the event from propagating further up the DOM""" - - stop_propagation: bool - """Stops the default action associate with the event from taking place.""" - - function: EventHandlerFunc - """A coroutine which can respond to an event and its data""" - - target: str | None - """Typically left as ``None`` except when a static target is useful. - - When testing, it may be useful to specify a static target ID so events can be - triggered programmatically. - - .. note:: - - When ``None``, it is left to a :class:`LayoutType` to auto generate a unique ID. - """ - - -class VdomDictConstructor(Protocol): - """Standard function for constructing a :class:`VdomDict`""" - - @overload - def __call__( - self, attributes: VdomAttributes, *children: VdomChildren - ) -> VdomDict: ... - - @overload - def __call__(self, *children: VdomChildren) -> VdomDict: ... - - @overload - def __call__( - self, *attributes_and_children: VdomAttributes | VdomChildren - ) -> VdomDict: ... - - -class LayoutUpdateMessage(TypedDict): - """A message describing an update to a layout""" - - type: Literal["layout-update"] - """The type of message""" - path: str - """JSON Pointer path to the model element being updated""" - model: VdomJson - """The model to assign at the given JSON Pointer path""" - - -class LayoutEventMessage(TypedDict): - """Message describing an event originating from an element in the layout""" - - type: Literal["layout-event"] - """The type of message""" - target: str - """The ID of the event handler.""" - data: Sequence[Any] - """A list of event data passed to the event handler.""" - - -class Context(Protocol[_Type]): - """Returns a :class:`ContextProvider` component""" - - def __call__( - self, - *children: Any, - value: _Type = ..., - key: Key | None = ..., - ) -> ContextProviderType[_Type]: ... - - -class ContextProviderType(ComponentType, Protocol[_Type]): - """A component which provides a context value to its children""" - - type: Context[_Type] - """The context type""" - - @property - def value(self) -> _Type: - "Current context value" diff --git a/src/py/reactpy/reactpy/core/vdom.py b/src/py/reactpy/reactpy/core/vdom.py deleted file mode 100644 index e494b5269..000000000 --- a/src/py/reactpy/reactpy/core/vdom.py +++ /dev/null @@ -1,351 +0,0 @@ -from __future__ import annotations - -import json -from collections.abc import Mapping, Sequence -from functools import wraps -from typing import Any, Protocol, cast, overload - -from fastjsonschema import compile as compile_json_schema - -from reactpy._warnings import warn -from reactpy.config import REACTPY_CHECK_JSON_ATTRS, REACTPY_DEBUG_MODE -from reactpy.core._f_back import f_module_name -from reactpy.core.events import EventHandler, to_event_handler_function -from reactpy.core.types import ( - ComponentType, - EventHandlerDict, - EventHandlerType, - ImportSourceDict, - Key, - VdomAttributes, - VdomChild, - VdomChildren, - VdomDict, - VdomDictConstructor, - VdomJson, -) - -VDOM_JSON_SCHEMA = { - "$schema": "http://json-schema.org/draft-07/schema", - "$ref": "#/definitions/element", - "definitions": { - "element": { - "type": "object", - "properties": { - "tagName": {"type": "string"}, - "key": {"type": ["string", "number", "null"]}, - "error": {"type": "string"}, - "children": {"$ref": "#/definitions/elementChildren"}, - "attributes": {"type": "object"}, - "eventHandlers": {"$ref": "#/definitions/elementEventHandlers"}, - "importSource": {"$ref": "#/definitions/importSource"}, - }, - # The 'tagName' is required because its presence is a useful indicator of - # whether a dictionary describes a VDOM model or not. - "required": ["tagName"], - "dependentSchemas": { - # When 'error' is given, the 'tagName' should be empty. - "error": {"properties": {"tagName": {"maxLength": 0}}} - }, - }, - "elementChildren": { - "type": "array", - "items": {"$ref": "#/definitions/elementOrString"}, - }, - "elementEventHandlers": { - "type": "object", - "patternProperties": { - ".*": {"$ref": "#/definitions/eventHandler"}, - }, - }, - "eventHandler": { - "type": "object", - "properties": { - "target": {"type": "string"}, - "preventDefault": {"type": "boolean"}, - "stopPropagation": {"type": "boolean"}, - }, - "required": ["target"], - }, - "importSource": { - "type": "object", - "properties": { - "source": {"type": "string"}, - "sourceType": {"enum": ["URL", "NAME"]}, - "fallback": { - "type": ["object", "string", "null"], - "if": {"not": {"type": "null"}}, - "then": {"$ref": "#/definitions/elementOrString"}, - }, - "unmountBeforeUpdate": {"type": "boolean"}, - }, - "required": ["source"], - }, - "elementOrString": { - "type": ["object", "string"], - "if": {"type": "object"}, - "then": {"$ref": "#/definitions/element"}, - }, - }, -} -"""JSON Schema describing serialized VDOM - see :ref:`VDOM` for more info""" - - -# we can't add a docstring to this because Sphinx doesn't know how to find its source -_COMPILED_VDOM_VALIDATOR = compile_json_schema(VDOM_JSON_SCHEMA) - - -def validate_vdom_json(value: Any) -> VdomJson: - """Validate serialized VDOM - see :attr:`VDOM_JSON_SCHEMA` for more info""" - _COMPILED_VDOM_VALIDATOR(value) - return cast(VdomJson, value) - - -def is_vdom(value: Any) -> bool: - """Return whether a value is a :class:`VdomDict` - - This employs a very simple heuristic - something is VDOM if: - - 1. It is a ``dict`` instance - 2. It contains the key ``"tagName"`` - 3. The value of the key ``"tagName"`` is a string - - .. note:: - - Performing an ``isinstance(value, VdomDict)`` check is too restrictive since the - user would be forced to import ``VdomDict`` every time they needed to declare a - VDOM element. Giving the user more flexibility, at the cost of this check's - accuracy, is worth it. - """ - return ( - isinstance(value, dict) - and "tagName" in value - and isinstance(value["tagName"], str) - ) - - -@overload -def vdom(tag: str, *children: VdomChildren) -> VdomDict: ... - - -@overload -def vdom(tag: str, attributes: VdomAttributes, *children: VdomChildren) -> VdomDict: ... - - -def vdom( - tag: str, - *attributes_and_children: Any, - **kwargs: Any, -) -> VdomDict: - """A helper function for creating VDOM elements. - - Parameters: - tag: - The type of element (e.g. 'div', 'h1', 'img') - attributes_and_children: - An optional attribute mapping followed by any number of children or - iterables of children. The attribute mapping **must** precede the children, - or children which will be merged into their respective parts of the model. - key: - A string indicating the identity of a particular element. This is significant - to preserve event handlers across updates - without a key, a re-render would - cause these handlers to be deleted, but with a key, they would be redirected - to any newly defined handlers. - event_handlers: - Maps event types to coroutines that are responsible for handling those events. - import_source: - (subject to change) specifies javascript that, when evaluated returns a - React component. - """ - if kwargs: # nocov - if "key" in kwargs: - if attributes_and_children: - maybe_attributes, *children = attributes_and_children - if _is_attributes(maybe_attributes): - attributes_and_children = ( - {**maybe_attributes, "key": kwargs.pop("key")}, - *children, - ) - else: - attributes_and_children = ( - {"key": kwargs.pop("key")}, - maybe_attributes, - *children, - ) - else: - attributes_and_children = ({"key": kwargs.pop("key")},) - warn( - "An element's 'key' must be declared in an attribute dict instead " - "of as a keyword argument. This will error in a future version.", - DeprecationWarning, - ) - - if kwargs: - msg = f"Extra keyword arguments {kwargs}" - raise ValueError(msg) - - model: VdomDict = {"tagName": tag} - - if not attributes_and_children: - return model - - attributes, children = separate_attributes_and_children(attributes_and_children) - key = attributes.pop("key", None) - attributes, event_handlers = separate_attributes_and_event_handlers(attributes) - - if attributes: - if REACTPY_CHECK_JSON_ATTRS.current: - json.dumps(attributes) - model["attributes"] = attributes - - if children: - model["children"] = children - - if key is not None: - model["key"] = key - - if event_handlers: - model["eventHandlers"] = event_handlers - - return model - - -def make_vdom_constructor( - tag: str, allow_children: bool = True, import_source: ImportSourceDict | None = None -) -> VdomDictConstructor: - """Return a constructor for VDOM dictionaries with the given tag name. - - The resulting callable will have the same interface as :func:`vdom` but without its - first ``tag`` argument. - """ - - def constructor(*attributes_and_children: Any, **kwargs: Any) -> VdomDict: - model = vdom(tag, *attributes_and_children, **kwargs) - if not allow_children and "children" in model: - msg = f"{tag!r} nodes cannot have children." - raise TypeError(msg) - if import_source: - model["importSource"] = import_source - return model - - # replicate common function attributes - constructor.__name__ = tag - constructor.__doc__ = ( - "Return a new " - f"`<{tag}> `__ " - "element represented by a :class:`VdomDict`." - ) - - module_name = f_module_name(1) - if module_name: - constructor.__module__ = module_name - constructor.__qualname__ = f"{module_name}.{tag}" - - return cast(VdomDictConstructor, constructor) - - -def custom_vdom_constructor(func: _CustomVdomDictConstructor) -> VdomDictConstructor: - """Cast function to VdomDictConstructor""" - - @wraps(func) - def wrapper(*attributes_and_children: Any) -> VdomDict: - attributes, children = separate_attributes_and_children(attributes_and_children) - key = attributes.pop("key", None) - attributes, event_handlers = separate_attributes_and_event_handlers(attributes) - return func(attributes, children, key, event_handlers) - - return cast(VdomDictConstructor, wrapper) - - -def separate_attributes_and_children( - values: Sequence[Any], -) -> tuple[dict[str, Any], list[Any]]: - if not values: - return {}, [] - - attributes: dict[str, Any] - children_or_iterables: Sequence[Any] - if _is_attributes(values[0]): - attributes, *children_or_iterables = values - else: - attributes = {} - children_or_iterables = values - - children: list[Any] = [] - for child in children_or_iterables: - if _is_single_child(child): - children.append(child) - else: - children.extend(child) - - return attributes, children - - -def separate_attributes_and_event_handlers( - attributes: Mapping[str, Any] -) -> tuple[dict[str, Any], EventHandlerDict]: - separated_attributes = {} - separated_event_handlers: dict[str, EventHandlerType] = {} - - for k, v in attributes.items(): - handler: EventHandlerType - - if callable(v): - handler = EventHandler(to_event_handler_function(v)) - elif ( - # isinstance check on protocols is slow - use function attr pre-check as a - # quick filter before actually performing slow EventHandlerType type check - hasattr(v, "function") - and isinstance(v, EventHandlerType) - ): - handler = v - else: - separated_attributes[k] = v - continue - - separated_event_handlers[k] = handler - - return separated_attributes, dict(separated_event_handlers.items()) - - -def _is_attributes(value: Any) -> bool: - return isinstance(value, Mapping) and "tagName" not in value - - -def _is_single_child(value: Any) -> bool: - if isinstance(value, (str, Mapping)) or not hasattr(value, "__iter__"): - return True - if REACTPY_DEBUG_MODE.current: - _validate_child_key_integrity(value) - return False - - -def _validate_child_key_integrity(value: Any) -> None: - if hasattr(value, "__iter__") and not hasattr(value, "__len__"): - warn( - f"Did not verify key-path integrity of children in generator {value} " - "- pass a sequence (i.e. list of finite length) in order to verify" - ) - else: - for child in value: - if isinstance(child, ComponentType) and child.key is None: - warn(f"Key not specified for child in list {child}", UserWarning) - elif isinstance(child, Mapping) and "key" not in child: - # remove 'children' to reduce log spam - child_copy = {**child, "children": _EllipsisRepr()} - warn(f"Key not specified for child in list {child_copy}", UserWarning) - - -class _CustomVdomDictConstructor(Protocol): - def __call__( - self, - attributes: VdomAttributes, - children: Sequence[VdomChild], - key: Key | None, - event_handlers: EventHandlerDict, - ) -> VdomDict: ... - - -class _EllipsisRepr: - def __repr__(self) -> str: - return "..." diff --git a/src/py/reactpy/reactpy/html.py b/src/py/reactpy/reactpy/html.py deleted file mode 100644 index 22d318639..000000000 --- a/src/py/reactpy/reactpy/html.py +++ /dev/null @@ -1,544 +0,0 @@ -""" - -**Fragment** - -- :func:`_` - -**Document metadata** - -- :func:`base` -- :func:`head` -- :func:`link` -- :func:`meta` -- :func:`style` -- :func:`title` - -**Content sectioning** - -- :func:`address` -- :func:`article` -- :func:`aside` -- :func:`footer` -- :func:`header` -- :func:`h1` -- :func:`h2` -- :func:`h3` -- :func:`h4` -- :func:`h5` -- :func:`h6` -- :func:`main` -- :func:`nav` -- :func:`section` - -**Text content** - -- :func:`blockquote` -- :func:`dd` -- :func:`div` -- :func:`dl` -- :func:`dt` -- :func:`figcaption` -- :func:`figure` -- :func:`hr` -- :func:`li` -- :func:`ol` -- :func:`p` -- :func:`pre` -- :func:`ul` - -**Inline text semantics** - -- :func:`a` -- :func:`abbr` -- :func:`b` -- :func:`bdi` -- :func:`bdo` -- :func:`br` -- :func:`cite` -- :func:`code` -- :func:`data` -- :func:`em` -- :func:`i` -- :func:`kbd` -- :func:`mark` -- :func:`q` -- :func:`rp` -- :func:`rt` -- :func:`ruby` -- :func:`s` -- :func:`samp` -- :func:`small` -- :func:`span` -- :func:`strong` -- :func:`sub` -- :func:`sup` -- :func:`time` -- :func:`u` -- :func:`var` -- :func:`wbr` - -**Image and video** - -- :func:`area` -- :func:`audio` -- :func:`img` -- :func:`map` -- :func:`track` -- :func:`video` - -**Embedded content** - -- :func:`embed` -- :func:`iframe` -- :func:`object` -- :func:`param` -- :func:`picture` -- :func:`portal` -- :func:`source` - -**SVG and MathML** - -- :func:`svg` -- :func:`math` - -**Scripting** - -- :func:`canvas` -- :func:`noscript` -- :func:`script` - -**Demarcating edits** - -- :func:`del_` -- :func:`ins` - -**Table content** - -- :func:`caption` -- :func:`col` -- :func:`colgroup` -- :func:`table` -- :func:`tbody` -- :func:`td` -- :func:`tfoot` -- :func:`th` -- :func:`thead` -- :func:`tr` - -**Forms** - -- :func:`button` -- :func:`fieldset` -- :func:`form` -- :func:`input` -- :func:`label` -- :func:`legend` -- :func:`meter` -- :func:`option` -- :func:`output` -- :func:`progress` -- :func:`select` -- :func:`textarea` - -**Interactive elements** - -- :func:`details` -- :func:`dialog` -- :func:`menu` -- :func:`menuitem` -- :func:`summary` - -**Web components** - -- :func:`slot` -- :func:`template` - -.. autofunction:: _ -""" - -from __future__ import annotations - -from collections.abc import Sequence - -from reactpy.core.types import ( - EventHandlerDict, - Key, - VdomAttributes, - VdomChild, - VdomDict, -) -from reactpy.core.vdom import custom_vdom_constructor, make_vdom_constructor - -__all__ = ( - "_", - "a", - "abbr", - "address", - "area", - "article", - "aside", - "audio", - "b", - "base", - "bdi", - "bdo", - "blockquote", - "br", - "button", - "canvas", - "caption", - "cite", - "code", - "col", - "colgroup", - "data", - "dd", - "del_", - "details", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "label", - "legend", - "li", - "link", - "main", - "map", - "mark", - "math", - "menu", - "menuitem", - "meta", - "meter", - "nav", - "noscript", - "object", - "ol", - "option", - "output", - "p", - "param", - "picture", - "portal", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "script", - "section", - "select", - "slot", - "small", - "source", - "span", - "strong", - "style", - "sub", - "summary", - "sup", - "svg", - "table", - "tbody", - "td", - "template", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "track", - "u", - "ul", - "var", - "video", - "wbr", -) - - -def _fragment( - attributes: VdomAttributes, - children: Sequence[VdomChild], - key: Key | None, - event_handlers: EventHandlerDict, -) -> VdomDict: - """An HTML fragment - this element will not appear in the DOM""" - if attributes or event_handlers: - msg = "Fragments cannot have attributes besides 'key'" - raise TypeError(msg) - model: VdomDict = {"tagName": ""} - - if children: - model["children"] = children - - if key is not None: - model["key"] = key - - return model - - -# FIXME: https://github.com/PyCQA/pylint/issues/5784 -_ = custom_vdom_constructor(_fragment) - - -# Document metadata -base = make_vdom_constructor("base") -head = make_vdom_constructor("head") -link = make_vdom_constructor("link") -meta = make_vdom_constructor("meta") -style = make_vdom_constructor("style") -title = make_vdom_constructor("title") - -# Content sectioning -address = make_vdom_constructor("address") -article = make_vdom_constructor("article") -aside = make_vdom_constructor("aside") -footer = make_vdom_constructor("footer") -header = make_vdom_constructor("header") -h1 = make_vdom_constructor("h1") -h2 = make_vdom_constructor("h2") -h3 = make_vdom_constructor("h3") -h4 = make_vdom_constructor("h4") -h5 = make_vdom_constructor("h5") -h6 = make_vdom_constructor("h6") -main = make_vdom_constructor("main") -nav = make_vdom_constructor("nav") -section = make_vdom_constructor("section") - -# Text content -blockquote = make_vdom_constructor("blockquote") -dd = make_vdom_constructor("dd") -div = make_vdom_constructor("div") -dl = make_vdom_constructor("dl") -dt = make_vdom_constructor("dt") -figcaption = make_vdom_constructor("figcaption") -figure = make_vdom_constructor("figure") -hr = make_vdom_constructor("hr", allow_children=False) -li = make_vdom_constructor("li") -ol = make_vdom_constructor("ol") -p = make_vdom_constructor("p") -pre = make_vdom_constructor("pre") -ul = make_vdom_constructor("ul") - -# Inline text semantics -a = make_vdom_constructor("a") -abbr = make_vdom_constructor("abbr") -b = make_vdom_constructor("b") -bdi = make_vdom_constructor("bdi") -bdo = make_vdom_constructor("bdo") -br = make_vdom_constructor("br", allow_children=False) -cite = make_vdom_constructor("cite") -code = make_vdom_constructor("code") -data = make_vdom_constructor("data") -em = make_vdom_constructor("em") -i = make_vdom_constructor("i") -kbd = make_vdom_constructor("kbd") -mark = make_vdom_constructor("mark") -q = make_vdom_constructor("q") -rp = make_vdom_constructor("rp") -rt = make_vdom_constructor("rt") -ruby = make_vdom_constructor("ruby") -s = make_vdom_constructor("s") -samp = make_vdom_constructor("samp") -small = make_vdom_constructor("small") -span = make_vdom_constructor("span") -strong = make_vdom_constructor("strong") -sub = make_vdom_constructor("sub") -sup = make_vdom_constructor("sup") -time = make_vdom_constructor("time") -u = make_vdom_constructor("u") -var = make_vdom_constructor("var") -wbr = make_vdom_constructor("wbr") - -# Image and video -area = make_vdom_constructor("area", allow_children=False) -audio = make_vdom_constructor("audio") -img = make_vdom_constructor("img", allow_children=False) -map = make_vdom_constructor("map") # noqa: A001 -track = make_vdom_constructor("track") -video = make_vdom_constructor("video") - -# Embedded content -embed = make_vdom_constructor("embed", allow_children=False) -iframe = make_vdom_constructor("iframe", allow_children=False) -object = make_vdom_constructor("object") # noqa: A001 -param = make_vdom_constructor("param") -picture = make_vdom_constructor("picture") -portal = make_vdom_constructor("portal", allow_children=False) -source = make_vdom_constructor("source", allow_children=False) - -# SVG and MathML -svg = make_vdom_constructor("svg") -math = make_vdom_constructor("math") - -# Scripting -canvas = make_vdom_constructor("canvas") -noscript = make_vdom_constructor("noscript") - - -def _script( - attributes: VdomAttributes, - children: Sequence[VdomChild], - key: Key | None, - event_handlers: EventHandlerDict, -) -> VdomDict: - """Create a new `" + ) + + +def pyscript_setup_html( + extra_py: Sequence[str], + extra_js: dict[str, Any] | str, + config: dict[str, Any] | str, +) -> str: + """Renders the PyScript setup code.""" + hide_pyscript_debugger = f'' + pyscript_config = extend_pyscript_config(extra_py, extra_js, config) + + return ( + f'' + f"{'' if REACTPY_DEBUG.current else hide_pyscript_debugger}" + f'" + f"" + ) + + +def extend_pyscript_config( + extra_py: Sequence[str], + extra_js: dict[str, str] | str, + config: dict[str, Any] | str, +) -> str: + # Extends ReactPy's default PyScript config with user provided values. + pyscript_config: dict[str, Any] = { + "packages": [reactpy_version_string(), "jsonpointer==3.*", "ssl"], + "js_modules": { + "main": { + f"{REACTPY_PATH_PREFIX.current}static/morphdom/morphdom-esm.js": "morphdom" + } + }, + } + pyscript_config["packages"].extend(extra_py) + + # FIXME: https://github.com/pyscript/pyscript/issues/2282 + if any(pkg.endswith(".whl") for pkg in pyscript_config["packages"]): # nocov + pyscript_config["packages_cache"] = "never" + + # Extend the JavaScript dependency list + if extra_js and isinstance(extra_js, str): + pyscript_config["js_modules"]["main"].update(json.loads(extra_js)) + elif extra_js and isinstance(extra_js, dict): + pyscript_config["js_modules"]["main"].update(extra_js) + + # Update other config attributes + if config and isinstance(config, str): + pyscript_config.update(json.loads(config)) + elif config and isinstance(config, dict): + pyscript_config.update(config) + return json.dumps(pyscript_config) + + +def reactpy_version_string() -> str: # nocov + from reactpy.testing.common import GITHUB_ACTIONS + + local_version = reactpy.__version__ + + # Get a list of all versions via `pip index versions` + result = get_reactpy_versions() + + # Check if the command failed + if not result: + _logger.warning( + "Failed to verify what versions of ReactPy exist on PyPi. " + "PyScript functionality may not work as expected.", + ) + return f"reactpy=={local_version}" + + # Have `pip` tell us what versions are available + known_versions: list[str] = result.get("versions", []) + latest_version: str = result.get("latest", "") + + # Return early if the version is available on PyPi and we're not in a CI environment + if local_version in known_versions and not GITHUB_ACTIONS: + return f"reactpy=={local_version}" + + # We are now determining an alternative method of installing ReactPy for PyScript + if not GITHUB_ACTIONS: + _logger.warning( + "Your ReactPy version isn't available on PyPi. " + "Attempting to find an alternative installation method for PyScript...", + ) + + # Build a local wheel for ReactPy, if needed + dist_dir = Path(reactpy.__file__).parent.parent.parent / "dist" + wheel_glob = glob(str(dist_dir / f"reactpy-{local_version}-*.whl")) + if not wheel_glob: + _logger.warning("Attempting to build a local wheel for ReactPy...") + subprocess.run( + ["hatch", "build", "-t", "wheel"], + capture_output=True, + text=True, + check=False, + cwd=Path(reactpy.__file__).parent.parent.parent, + ) + wheel_glob = glob(str(dist_dir / f"reactpy-{local_version}-*.whl")) + + # Move the local wheel to the web modules directory, if it exists + if wheel_glob: + wheel_file = Path(wheel_glob[0]) + new_path = REACTPY_WEB_MODULES_DIR.current / wheel_file.name + if not new_path.exists(): + _logger.warning( + "PyScript will utilize local wheel '%s'.", + wheel_file.name, + ) + shutil.copy(wheel_file, new_path) + return f"{REACTPY_PATH_PREFIX.current}modules/{wheel_file.name}" + + # Building a local wheel failed, try our best to give the user any version. + if latest_version: + _logger.warning( + "Failed to build a local wheel for ReactPy, likely due to missing build dependencies. " + "PyScript will default to using the latest ReactPy version on PyPi." + ) + return f"reactpy=={latest_version}" + _logger.error( + "Failed to build a local wheel for ReactPy, and could not determine the latest version on PyPi. " + "PyScript functionality may not work as expected.", + ) + return f"reactpy=={local_version}" + + +@functools.cache +def get_reactpy_versions() -> dict[Any, Any]: + """Fetches the available versions of a package from PyPI.""" + try: + try: + response = request.urlopen("https://pypi.org/pypi/reactpy/json", timeout=5) + except Exception: + response = request.urlopen("http://pypi.org/pypi/reactpy/json", timeout=5) + if response.status == 200: # noqa: PLR2004 + data = json.load(response) + versions = list(data.get("releases", {}).keys()) + latest = data.get("info", {}).get("version", "") + if versions and latest: + return {"versions": versions, "latest": latest} + except Exception: + _logger.exception("Error fetching ReactPy package versions from PyPI!") + return {} + + +@functools.cache +def cached_file_read(file_path: str, minifiy: bool = True) -> str: + content = Path(file_path).read_text(encoding="utf-8").strip() + return minify_python(content) if minifiy else content diff --git a/src/reactpy/executors/utils.py b/src/reactpy/executors/utils.py new file mode 100644 index 000000000..291674a8a --- /dev/null +++ b/src/reactpy/executors/utils.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import logging +from collections.abc import Iterable +from typing import Any + +from reactpy._option import Option +from reactpy.config import ( + REACTPY_PATH_PREFIX, + REACTPY_RECONNECT_BACKOFF_MULTIPLIER, + REACTPY_RECONNECT_INTERVAL, + REACTPY_RECONNECT_MAX_INTERVAL, + REACTPY_RECONNECT_MAX_RETRIES, +) +from reactpy.types import ReactPyConfig, VdomDict +from reactpy.utils import import_dotted_path, reactpy_to_string + +logger = logging.getLogger(__name__) + + +def import_components(dotted_paths: Iterable[str]) -> dict[str, Any]: + """Imports a list of dotted paths and returns the callables.""" + return { + dotted_path: import_dotted_path(dotted_path) for dotted_path in dotted_paths + } + + +def check_path(url_path: str) -> str: # nocov + """Check that a path is valid URL path.""" + if not url_path: + return "URL path must not be empty." + if not isinstance(url_path, str): + return "URL path is must be a string." + if not url_path.startswith("/"): + return "URL path must start with a forward slash." + if not url_path.endswith("/"): + return "URL path must end with a forward slash." + + return "" + + +def vdom_head_to_html(head: VdomDict) -> str: + if isinstance(head, dict) and head.get("tagName") == "head": + return reactpy_to_string(head) + + raise ValueError("Head element must be constructed with `html.head`.") + + +def process_settings(settings: ReactPyConfig) -> None: + """Process the settings and return the final configuration.""" + from reactpy import config + + for setting in settings: + config_name = f"REACTPY_{setting.upper()}" + config_object: Option[Any] | None = getattr(config, config_name, None) + if config_object: + config_object.set_current(settings[setting]) # type: ignore + else: + raise ValueError(f'Unknown ReactPy setting "{setting}".') + + +def server_side_component_html( + element_id: str, class_: str, component_path: str +) -> str: + return ( + f'
' + "" + '" + ) + + +def default_import_map() -> str: + path_prefix = REACTPY_PATH_PREFIX.current.strip("/") + return f"""{{ + "imports": {{ + "react": "/{path_prefix}/static/preact.js", + "react-dom": "/{path_prefix}/static/preact-dom.js", + "react-dom/client": "/{path_prefix}/static/preact-dom.js", + "react/jsx-runtime": "/{path_prefix}/static/preact-jsx-runtime.js" + }} + }}""".replace("\n", "").replace(" ", "") diff --git a/src/py/reactpy/reactpy/logging.py b/src/reactpy/logging.py similarity index 67% rename from src/py/reactpy/reactpy/logging.py rename to src/reactpy/logging.py index f10414cb6..160141c09 100644 --- a/src/py/reactpy/reactpy/logging.py +++ b/src/reactpy/logging.py @@ -2,7 +2,7 @@ import sys from logging.config import dictConfig -from reactpy.config import REACTPY_DEBUG_MODE +from reactpy.config import REACTPY_DEBUG dictConfig( { @@ -18,13 +18,7 @@ "stream": sys.stdout, } }, - "formatters": { - "generic": { - "format": "%(asctime)s | %(log_color)s%(levelname)s%(reset)s | %(message)s", - "datefmt": r"%Y-%m-%dT%H:%M:%S%z", - "class": "colorlog.ColoredFormatter", - } - }, + "formatters": {"generic": {"datefmt": r"%Y-%m-%dT%H:%M:%S%z"}}, } ) @@ -33,7 +27,7 @@ """ReactPy's root logger instance""" -@REACTPY_DEBUG_MODE.subscribe +@REACTPY_DEBUG.subscribe def _set_debug_level(debug: bool) -> None: if debug: ROOT_LOGGER.setLevel("DEBUG") diff --git a/src/py/reactpy/reactpy/py.typed b/src/reactpy/py.typed similarity index 100% rename from src/py/reactpy/reactpy/py.typed rename to src/reactpy/py.typed diff --git a/src/reactpy/reactjs/__init__.py b/src/reactpy/reactjs/__init__.py new file mode 100644 index 000000000..f0fac3611 --- /dev/null +++ b/src/reactpy/reactjs/__init__.py @@ -0,0 +1,351 @@ +from __future__ import annotations + +import hashlib +from pathlib import Path +from typing import Any, overload + +from reactpy.reactjs.module import ( + file_to_module, + import_reactjs, + module_to_vdom, + string_to_module, + url_to_module, +) +from reactpy.reactjs.types import ( + NAME_SOURCE, + URL_SOURCE, +) +from reactpy.types import JavaScriptModule, VdomConstructor + +__all__ = [ + "NAME_SOURCE", + "URL_SOURCE", + "component_from_file", + "component_from_npm", + "component_from_string", + "component_from_url", + "import_reactjs", +] + +_URL_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {} +_FILE_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {} +_STRING_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {} + + +@overload +def component_from_url( + url: str, + import_names: str, + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> VdomConstructor: ... + + +@overload +def component_from_url( + url: str, + import_names: list[str] | tuple[str, ...], + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> list[VdomConstructor]: ... + + +def component_from_url( + url: str, + import_names: str | list[str] | tuple[str, ...], + resolve_imports: bool = False, + resolve_imports_depth: int = 5, + fallback: Any | None = None, + unmount_before_update: bool = False, + allow_children: bool = True, +) -> VdomConstructor | list[VdomConstructor]: + """Import a component from a URL. + + Parameters: + url: + The URL to import the component from. + import_names: + One or more component names to import. If given as a string, a single component + will be returned. If a list is given, then a list of components will be + returned. + resolve_imports: + Whether to try and find all the named imports of this module. + resolve_imports_depth: + How deeply to search for those imports. + fallback: + What to temporarily display while the module is being loaded. + unmount_before_update: + Cause the component to be unmounted before each update. This option should + only be used if the imported package fails to re-render when props change. + Using this option has negative performance consequences since all DOM + elements must be changed on each render. See :issue:`461` for more info. + allow_children: + Whether or not these components can have children. + """ + key = f"{url}{resolve_imports}{resolve_imports_depth}{unmount_before_update}" + if key in _URL_JS_MODULE_CACHE: + module = _URL_JS_MODULE_CACHE[key] + else: + module = url_to_module( + url, + fallback=fallback, + resolve_imports=resolve_imports, + resolve_imports_depth=resolve_imports_depth, + unmount_before_update=unmount_before_update, + ) + _URL_JS_MODULE_CACHE[key] = module + return module_to_vdom(module, import_names, fallback, allow_children) + + +@overload +def component_from_npm( + package: str, + import_names: str, + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + version: str = "latest", + cdn: str = "https://esm.sh", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> VdomConstructor: ... + + +@overload +def component_from_npm( + package: str, + import_names: list[str] | tuple[str, ...], + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + version: str = "latest", + cdn: str = "https://esm.sh", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> list[VdomConstructor]: ... + + +def component_from_npm( + package: str, + import_names: str | list[str] | tuple[str, ...], + resolve_imports: bool = False, + resolve_imports_depth: int = 5, + version: str = "latest", + cdn: str = "https://esm.sh", + fallback: Any | None = None, + unmount_before_update: bool = False, + allow_children: bool = True, +) -> VdomConstructor | list[VdomConstructor]: + """Import a component from an NPM package. + + Is is mandatory to load `reactpy.reactjs.import_reactjs()` on your page before using this + function. It is recommended to put this within your HTML content. + + Parameters: + package: + The name of the NPM package. + import_names: + One or more component names to import. If given as a string, a single component + will be returned. If a list is given, then a list of components will be + returned. + resolve_imports: + Whether to try and find all the named imports of this module. + resolve_imports_depth: + How deeply to search for those imports. + version: + The version of the package to use. Defaults to "latest". + cdn: + The CDN to use. Defaults to "https://esm.sh". + fallback: + What to temporarily display while the module is being loaded. + unmount_before_update: + Cause the component to be unmounted before each update. This option should + only be used if the imported package fails to re-render when props change. + Using this option has negative performance consequences since all DOM + elements must be changed on each render. See :issue:`461` for more info. + allow_children: + Whether or not these components can have children. + """ + url = f"{cdn}/{package}@{version}" + + if "esm.sh" in cdn: + url += "&" if "?" in url else "?" + url += "external=react,react-dom,react/jsx-runtime&bundle&target=es2020" + + return component_from_url( + url, + import_names, + fallback=fallback, + resolve_imports=resolve_imports, + resolve_imports_depth=resolve_imports_depth, + unmount_before_update=unmount_before_update, + allow_children=allow_children, + ) + + +@overload +def component_from_file( + file: str | Path, + import_names: str, + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + name: str = "", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + symlink: bool = ..., + allow_children: bool = ..., +) -> VdomConstructor: ... + + +@overload +def component_from_file( + file: str | Path, + import_names: list[str] | tuple[str, ...], + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + name: str = "", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + symlink: bool = ..., + allow_children: bool = ..., +) -> list[VdomConstructor]: ... + + +def component_from_file( + file: str | Path, + import_names: str | list[str] | tuple[str, ...], + resolve_imports: bool = False, + resolve_imports_depth: int = 5, + name: str = "", + fallback: Any | None = None, + unmount_before_update: bool = False, + symlink: bool = False, + allow_children: bool = True, +) -> VdomConstructor | list[VdomConstructor]: + """Import a component from a file. + + Parameters: + file: + The file from which the content of the web module will be created. + import_names: + One or more component names to import. If given as a string, a single component + will be returned. If a list is given, then a list of components will be + returned. + resolve_imports: + Whether to try and find all the named imports of this module. + resolve_imports_depth: + How deeply to search for those imports. + name: + The human-readable name of the ReactJS package + fallback: + What to temporarily display while the module is being loaded. + unmount_before_update: + Cause the component to be unmounted before each update. This option should + only be used if the imported package fails to re-render when props change. + Using this option has negative performance consequences since all DOM + elements must be changed on each render. See :issue:`461` for more info. + symlink: + Whether the web module should be saved as a symlink to the given ``file``. + allow_children: + Whether or not these components can have children. + """ + name = name or hashlib.sha256(str(file).encode()).hexdigest()[:10] + key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}" + if key in _FILE_JS_MODULE_CACHE: + module = _FILE_JS_MODULE_CACHE[key] + else: + module = file_to_module( + name, + file, + fallback=fallback, + resolve_imports=resolve_imports, + resolve_imports_depth=resolve_imports_depth, + unmount_before_update=unmount_before_update, + symlink=symlink, + ) + _FILE_JS_MODULE_CACHE[key] = module + return module_to_vdom(module, import_names, fallback, allow_children) + + +@overload +def component_from_string( + content: str, + import_names: str, + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + name: str = "", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> VdomConstructor: ... + + +@overload +def component_from_string( + content: str, + import_names: list[str] | tuple[str, ...], + resolve_imports: bool = ..., + resolve_imports_depth: int = ..., + name: str = "", + fallback: Any | None = ..., + unmount_before_update: bool = ..., + allow_children: bool = ..., +) -> list[VdomConstructor]: ... + + +def component_from_string( + content: str, + import_names: str | list[str] | tuple[str, ...], + resolve_imports: bool = False, + resolve_imports_depth: int = 5, + name: str = "", + fallback: Any | None = None, + unmount_before_update: bool = False, + allow_children: bool = True, +) -> VdomConstructor | list[VdomConstructor]: + """Import a component from a string. + + Parameters: + content: + The contents of the web module + import_names: + One or more component names to import. If given as a string, a single component + will be returned. If a list is given, then a list of components will be + returned. + resolve_imports: + Whether to try and find all the named imports of this module. + resolve_imports_depth: + How deeply to search for those imports. + name: + The human-readable name of the ReactJS package + fallback: + What to temporarily display while the module is being loaded. + unmount_before_update: + Cause the component to be unmounted before each update. This option should + only be used if the imported package fails to re-render when props change. + Using this option has negative performance consequences since all DOM + elements must be changed on each render. See :issue:`461` for more info. + allow_children: + Whether or not these components can have children. + """ + name = name or hashlib.sha256(content.encode()).hexdigest()[:10] + key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}" + if key in _STRING_JS_MODULE_CACHE: + module = _STRING_JS_MODULE_CACHE[key] + else: + module = string_to_module( + name, + content, + fallback=fallback, + resolve_imports=resolve_imports, + resolve_imports_depth=resolve_imports_depth, + unmount_before_update=unmount_before_update, + ) + _STRING_JS_MODULE_CACHE[key] = module + return module_to_vdom(module, import_names, fallback, allow_children) diff --git a/src/reactpy/reactjs/module.py b/src/reactpy/reactjs/module.py new file mode 100644 index 000000000..d9ce6758d --- /dev/null +++ b/src/reactpy/reactjs/module.py @@ -0,0 +1,267 @@ +from __future__ import annotations + +import logging +from pathlib import Path, PurePosixPath +from typing import Any, Literal + +from reactpy.config import REACTPY_DEBUG, REACTPY_WEB_MODULES_DIR +from reactpy.core.vdom import Vdom +from reactpy.reactjs.types import NAME_SOURCE, URL_SOURCE +from reactpy.reactjs.utils import ( + are_files_identical, + copy_file, + file_lock, + resolve_names_from_file, + resolve_names_from_url, +) +from reactpy.types import ImportSourceDict, JavaScriptModule, VdomConstructor, VdomDict + +logger = logging.getLogger(__name__) + + +def url_to_module( + url: str, + fallback: Any | None = None, + resolve_imports: bool = True, + resolve_imports_depth: int = 5, + unmount_before_update: bool = False, +) -> JavaScriptModule: + return JavaScriptModule( + source=url, + source_type=URL_SOURCE, + default_fallback=fallback, + file=None, + import_names=( + resolve_names_from_url(url, resolve_imports_depth) + if resolve_imports + else None + ), + unmount_before_update=unmount_before_update, + ) + + +def file_to_module( + name: str, + file: str | Path, + fallback: Any | None = None, + resolve_imports: bool = True, + resolve_imports_depth: int = 5, + unmount_before_update: bool = False, + symlink: bool = False, +) -> JavaScriptModule: + name += module_name_suffix(name) + + source_file = Path(file).resolve() + target_file = get_module_path(name) + + with file_lock(target_file.with_name(f"{target_file.name}.lock")): + if not source_file.exists(): + msg = f"Source file does not exist: {source_file}" + raise FileNotFoundError(msg) + + if not target_file.exists(): + copy_file(target_file, source_file, symlink) + elif not are_files_identical(source_file, target_file): + logger.info( + f"Existing web module {name!r} will " + f"be replaced with {target_file.resolve()}" + ) + copy_file(target_file, source_file, symlink) + + return JavaScriptModule( + source=name, + source_type=NAME_SOURCE, + default_fallback=fallback, + file=target_file, + import_names=( + resolve_names_from_file(source_file, resolve_imports_depth) + if resolve_imports + else None + ), + unmount_before_update=unmount_before_update, + ) + + +def string_to_module( + name: str, + content: str, + fallback: Any | None = None, + resolve_imports: bool = True, + resolve_imports_depth: int = 5, + unmount_before_update: bool = False, +) -> JavaScriptModule: + name += module_name_suffix(name) + + target_file = get_module_path(name) + + if target_file.exists() and target_file.read_text(encoding="utf-8") != content: + logger.info( + f"Existing web module {name!r} will " + f"be replaced with {target_file.resolve()}" + ) + target_file.unlink() + + target_file.parent.mkdir(parents=True, exist_ok=True) + target_file.write_text(content) + + return JavaScriptModule( + source=name, + source_type=NAME_SOURCE, + default_fallback=fallback, + file=target_file, + import_names=( + resolve_names_from_file(target_file, resolve_imports_depth) + if resolve_imports + else None + ), + unmount_before_update=unmount_before_update, + ) + + +def module_to_vdom( + web_module: JavaScriptModule, + import_names: str | list[str] | tuple[str, ...], + fallback: Any | None = None, + allow_children: bool = True, +) -> VdomConstructor | list[VdomConstructor]: + """Return one or more VDOM constructors from a :class:`JavaScriptModule` + + Parameters: + import_names: + One or more names to import. If given as a string, a single component + will be returned. If a list is given, then a list of components will be + returned. + fallback: + What to temporarily display while the module is being loaded. + allow_children: + Whether or not these components can have children. + """ + if isinstance(import_names, str): + if ( + web_module.import_names is not None + and import_names.split(".")[0] not in web_module.import_names + ): + msg = f"{web_module.source!r} does not contain {import_names!r}" + raise ValueError(msg) + return make_module(web_module, import_names, fallback, allow_children) + else: + if web_module.import_names is not None: + missing = sorted( + {e.split(".")[0] for e in import_names}.difference( + web_module.import_names + ) + ) + if missing: + msg = f"{web_module.source!r} does not contain {missing!r}" + raise ValueError(msg) + return [ + make_module(web_module, name, fallback, allow_children) + for name in import_names + ] + + +def make_module( + web_module: JavaScriptModule, + name: str, + fallback: Any | None, + allow_children: bool, +) -> VdomConstructor: + return Vdom( + name, + allow_children=allow_children, + import_source=ImportSourceDict( + source=web_module.source, + sourceType=web_module.source_type, + fallback=(fallback or web_module.default_fallback), + unmountBeforeUpdate=web_module.unmount_before_update, + ), + ) + + +def import_reactjs( + framework: Literal["preact", "react"] | None = None, + version: str | None = None, + use_local: bool = False, +) -> VdomDict: + """ + Return an import map script tag for ReactJS or Preact. + Parameters: + framework: + The framework to use, either "preact" or "react". Defaults to "preact" for + performance reasons. Set this to `react` if you are experiencing compatibility + issues with your component library. + version: + The version of the framework to use. Example values include "18", "10.2.4", + or "latest". If left as `None`, a default version will be used depending on the + selected framework. + use_local: + Whether to use the local framework ReactPy is bundled with (Preact). + Raises: + ValueError: + If both `framework` and `react_url_prefix` are provided, or if + `framework` is not one of "preact" or "react". + Returns: + A VDOM script tag containing the import map. + """ + from reactpy import html + from reactpy.executors.utils import default_import_map + + if use_local and (framework or version): # nocov + raise ValueError("use_local cannot be used with framework or version") + + framework = framework or "preact" + if framework and framework not in {"preact", "react"}: # nocov + raise ValueError("framework must be 'preact' or 'react'") + + # Import map for ReactPy's local framework (re-exported/bundled/minified version of Preact) + if use_local: + return html.script( + {"type": "importmap", "id": "reactpy-importmap"}, + default_import_map(), + ) + + # Import map for ReactJS from esm.sh + if framework == "react": + version = version or "19" + postfix = "?dev" if REACTPY_DEBUG.current else "" + return html.script( + {"type": "importmap", "id": "reactpy-importmap"}, + f"""{{ + "imports": {{ + "react": "https://esm.sh/react@{version}{postfix}", + "react-dom": "https://esm.sh/react-dom@{version}{postfix}", + "react-dom/client": "https://esm.sh/react-dom@{version}/client{postfix}", + "react/jsx-runtime": "https://esm.sh/react@{version}/jsx-runtime{postfix}" + }} + }}""".replace("\n", "").replace(" ", ""), + ) + + # Import map for Preact from esm.sh + if framework == "preact": + version = version or "10" + postfix = "?dev" if REACTPY_DEBUG.current else "" + return html.script( + {"type": "importmap", "id": "reactpy-importmap"}, + f"""{{ + "imports": {{ + "react": "https://esm.sh/preact@{version}/compat{postfix}", + "react-dom": "https://esm.sh/preact@{version}/compat{postfix}", + "react-dom/client": "https://esm.sh/preact@{version}/compat/client{postfix}", + "react/jsx-runtime": "https://esm.sh/preact@{version}/compat/jsx-runtime{postfix}" + }} + }}""".replace("\n", "").replace(" ", ""), + ) + + +def module_name_suffix(name: str) -> str: + if name.startswith("@"): + name = name[1:] + head, _, tail = name.partition("@") # handle version identifier + _, _, tail = tail.partition("/") # get section after version + return PurePosixPath(tail or head).suffix or ".js" + + +def get_module_path(name: str) -> Path: + directory = REACTPY_WEB_MODULES_DIR.current + path = directory.joinpath(*name.split("/")) + return path.with_suffix(path.suffix) diff --git a/src/reactpy/reactjs/types.py b/src/reactpy/reactjs/types.py new file mode 100644 index 000000000..b465cf734 --- /dev/null +++ b/src/reactpy/reactjs/types.py @@ -0,0 +1,7 @@ +from reactpy.types import SourceType + +NAME_SOURCE = SourceType("NAME") +"""A named source - usually a Javascript package name""" + +URL_SOURCE = SourceType("URL") +"""A source loaded from a URL, usually a CDN""" diff --git a/src/reactpy/reactjs/utils.py b/src/reactpy/reactjs/utils.py new file mode 100644 index 000000000..7c1331cd6 --- /dev/null +++ b/src/reactpy/reactjs/utils.py @@ -0,0 +1,212 @@ +import filecmp +import logging +import os +import re +import shutil +import time +from contextlib import contextmanager, suppress +from pathlib import Path +from urllib.parse import urlparse, urlunparse + +import requests + +logger = logging.getLogger(__name__) + + +def resolve_names_from_file( + file: Path, + max_depth: int, + is_regex_import: bool = False, +) -> set[str]: + if max_depth == 0: + logger.warning(f"Did not resolve all imports for {file} - max depth reached") + return set() + elif not file.exists(): + logger.warning(f"Did not resolve imports for unknown file {file}") + return set() + + names, references = resolve_names_from_source( + file.read_text(encoding="utf-8"), exclude_default=is_regex_import + ) + + for ref in references: + if urlparse(ref).scheme: # is an absolute URL + names.update( + resolve_names_from_url(ref, max_depth - 1, is_regex_import=True) + ) + else: + path = file.parent.joinpath(*ref.split("/")) + names.update( + resolve_names_from_file(path, max_depth - 1, is_regex_import=True) + ) + + return names + + +def resolve_names_from_url( + url: str, + max_depth: int, + is_regex_import: bool = False, +) -> set[str]: + if max_depth == 0: + logger.warning(f"Did not resolve all imports for {url} - max depth reached") + return set() + + try: + text = requests.get(url, timeout=5).text + except requests.exceptions.ConnectionError as error: + reason = "" if error is None else " - {error.errno}" + logger.warning(f"Did not resolve imports for url {url} {reason}") + return set() + + names, references = resolve_names_from_source(text, exclude_default=is_regex_import) + + for ref in references: + url = normalize_url_path(url, ref) + names.update(resolve_names_from_url(url, max_depth - 1, is_regex_import=True)) + + return names + + +def resolve_names_from_source( + content: str, exclude_default: bool +) -> tuple[set[str], set[str]]: + """Find names exported by the given JavaScript module content to assist with ReactPy import resolution. + + Parmeters: + content: The content of the JavaScript module. + Returns: + A tuple where the first item is a set of exported names and the second item is a set of + referenced module paths. + """ + all_names: set[str] = set() + references: set[str] = set() + + if _JS_DEFAULT_EXPORT_PATTERN.search(content): + all_names.add("default") + + # Exporting functions and classes + all_names.update(_JS_FUNC_OR_CLS_EXPORT_PATTERN.findall(content)) + + for name in _JS_GENERAL_EXPORT_PATTERN.findall(content): + name = name.rstrip(";").strip() + # Exporting individual features + if name.startswith("let "): + all_names.update(let.split("=", 1)[0] for let in name[4:].split(",")) + # Renaming exports and export list + elif name.startswith("{") and name.endswith("}"): + all_names.update( + item.split(" as ", 1)[-1] for item in name.strip("{}").split(",") + ) + # Exporting destructured assignments with renaming + elif name.startswith("const "): + all_names.update( + item.split(":", 1)[0] + for item in name[6:].split("=", 1)[0].strip("{}").split(",") + ) + # Default exports + elif name.startswith("default "): + all_names.add("default") + # Aggregating modules + elif name.startswith("* as "): + all_names.add(name[5:].split(" from ", 1)[0]) + elif name.startswith("* "): + references.add(name[2:].split("from ", 1)[-1].strip("'\"")) + elif name.startswith("{") and " from " in name: + all_names.update( + item.split(" as ", 1)[-1] + for item in name.split(" from ")[0].strip("{}").split(",") + ) + elif not (name.startswith("function ") or name.startswith("class ")): + logger.warning(f"Found unknown export type {name!r}") + + all_names = {n.strip() for n in all_names} + references = {r.strip() for r in references} + + if exclude_default and "default" in all_names: + all_names.remove("default") + + return all_names, references + + +def normalize_url_path(base_url: str, rel_url: str) -> str: + if not rel_url.startswith("."): + if rel_url.startswith("/"): + # copy scheme and hostname from base_url + return urlunparse(urlparse(base_url)[:2] + urlparse(rel_url)[2:]) + else: + return rel_url + + base_url = base_url.rsplit("/", 1)[0] + + if rel_url.startswith("./"): + return base_url + rel_url[1:] + + while rel_url.startswith("../"): + base_url = base_url.rsplit("/", 1)[0] + rel_url = rel_url[3:] + + return f"{base_url}/{rel_url}" + + +def are_files_identical(f1: Path, f2: Path) -> bool: + f1 = f1.resolve() + f2 = f2.resolve() + return ( + (f1.is_symlink() or f2.is_symlink()) and (f1.resolve() == f2.resolve()) + ) or filecmp.cmp(str(f1), str(f2), shallow=False) + + +def copy_file(target: Path, source: Path, symlink: bool) -> None: + target.parent.mkdir(parents=True, exist_ok=True) + if symlink: + if target.exists(): + target.unlink() + target.symlink_to(source) + else: + temp_target = target.with_suffix(f"{target.suffix}.tmp") + shutil.copy(source, temp_target) + try: + temp_target.replace(target) + except OSError: + # On Windows, replace might fail if the file is open + # Retry once after a short delay + time.sleep(0.1) + try: + temp_target.replace(target) + except OSError: + # If it still fails, try to unlink and rename + # This is not atomic, but it's a fallback + if target.exists(): + target.unlink() + temp_target.rename(target) + + +_JS_DEFAULT_EXPORT_PATTERN = re.compile( + r";?\s*export\s+default\s", +) +_JS_FUNC_OR_CLS_EXPORT_PATTERN = re.compile( + r";?\s*export\s+(?:function|class)\s+([a-zA-Z_$][0-9a-zA-Z_$]*)" +) +_JS_GENERAL_EXPORT_PATTERN = re.compile( + r"(?:^|;|})\s*export(?=\s+|{)(.*?)(?=;|$)", re.MULTILINE +) + + +@contextmanager +def file_lock(lock_file: Path, timeout: float = 10.0): + start_time = time.time() + while True: + try: + fd = os.open(lock_file, os.O_CREAT | os.O_EXCL | os.O_RDWR) + os.close(fd) + break + except OSError as e: + if time.time() - start_time > timeout: + raise TimeoutError(f"Could not acquire lock {lock_file}") from e + time.sleep(0.1) + try: + yield + finally: + with suppress(OSError): + os.unlink(lock_file) diff --git a/src/reactpy/static/pyscript-hide-debug.css b/src/reactpy/static/pyscript-hide-debug.css new file mode 100644 index 000000000..9cd8541e4 --- /dev/null +++ b/src/reactpy/static/pyscript-hide-debug.css @@ -0,0 +1,3 @@ +.py-error { + display: none; +} diff --git a/src/reactpy/templatetags/__init__.py b/src/reactpy/templatetags/__init__.py new file mode 100644 index 000000000..c9e5f28bc --- /dev/null +++ b/src/reactpy/templatetags/__init__.py @@ -0,0 +1,3 @@ +from reactpy.templatetags.jinja import ReactPyJinja + +__all__ = ["ReactPyJinja"] diff --git a/src/reactpy/templatetags/jinja.py b/src/reactpy/templatetags/jinja.py new file mode 100644 index 000000000..e7f980dcb --- /dev/null +++ b/src/reactpy/templatetags/jinja.py @@ -0,0 +1,45 @@ +from typing import ClassVar +from uuid import uuid4 + +from jinja2_simple_tags import StandaloneTag + +from reactpy.executors.pyscript.utils import ( + pyscript_component_html, + pyscript_setup_html, +) +from reactpy.executors.utils import server_side_component_html + + +class ReactPyJinja(StandaloneTag): # type: ignore + safe_output = True + tags: ClassVar[set[str]] = {"component", "pyscript_component", "pyscript_setup"} + + def render(self, *args: str, **kwargs: str) -> str: + if self.tag_name == "component": + return component(*args, **kwargs) + + if self.tag_name == "pyscript_component": + return pyscript_component(*args, **kwargs) + + if self.tag_name == "pyscript_setup": + return pyscript_setup(*args, **kwargs) + + # This should never happen, but we validate it for safety. + raise ValueError(f"Unknown tag: {self.tag_name}") # nocov + + +def component(dotted_path: str, **kwargs: str) -> str: + class_ = kwargs.pop("class", "") + if kwargs: + raise ValueError(f"Unexpected keyword arguments: {', '.join(kwargs)}") + return server_side_component_html( + element_id=uuid4().hex, class_=class_, component_path=f"{dotted_path}/" + ) + + +def pyscript_component(*file_paths: str, initial: str = "", root: str = "root") -> str: + return pyscript_component_html(file_paths=file_paths, initial=initial, root=root) + + +def pyscript_setup(*extra_py: str, extra_js: str = "", config: str = "") -> str: + return pyscript_setup_html(extra_py=extra_py, extra_js=extra_js, config=config) diff --git a/src/py/reactpy/reactpy/testing/__init__.py b/src/reactpy/testing/__init__.py similarity index 74% rename from src/py/reactpy/reactpy/testing/__init__.py rename to src/reactpy/testing/__init__.py index 9f61cec57..67439ea36 100644 --- a/src/py/reactpy/reactpy/testing/__init__.py +++ b/src/reactpy/testing/__init__.py @@ -1,10 +1,5 @@ from reactpy.testing.backend import BackendFixture -from reactpy.testing.common import ( - HookCatcher, - StaticEventHandler, - clear_reactpy_web_modules_dir, - poll, -) +from reactpy.testing.common import GITHUB_ACTIONS, HookCatcher, StaticEventHandler, poll from reactpy.testing.display import DisplayFixture from reactpy.testing.logs import ( LogAssertionError, @@ -14,14 +9,14 @@ ) __all__ = [ - "assert_reactpy_did_not_log", - "assert_reactpy_did_log", - "capture_reactpy_logs", - "clear_reactpy_web_modules_dir", + "GITHUB_ACTIONS", + "BackendFixture", "DisplayFixture", "HookCatcher", "LogAssertionError", - "poll", - "BackendFixture", "StaticEventHandler", + "assert_reactpy_did_log", + "assert_reactpy_did_not_log", + "capture_reactpy_logs", + "poll", ] diff --git a/src/py/reactpy/reactpy/testing/backend.py b/src/reactpy/testing/backend.py similarity index 68% rename from src/py/reactpy/reactpy/testing/backend.py rename to src/reactpy/testing/backend.py index b699f3071..ca311ceed 100644 --- a/src/py/reactpy/reactpy/testing/backend.py +++ b/src/reactpy/testing/backend.py @@ -2,23 +2,26 @@ import asyncio import logging -from contextlib import AsyncExitStack, suppress +import socket +from collections.abc import Callable +from contextlib import AsyncExitStack from types import TracebackType -from typing import Any, Callable +from typing import Any from urllib.parse import urlencode, urlunparse -from reactpy.backend import default as default_server -from reactpy.backend.types import BackendType -from reactpy.backend.utils import find_available_port -from reactpy.config import REACTPY_TESTING_DEFAULT_TIMEOUT +import uvicorn + from reactpy.core.component import component from reactpy.core.hooks import use_callback, use_effect, use_state -from reactpy.core.types import ComponentConstructor +from reactpy.executors.asgi.middleware import ReactPyMiddleware +from reactpy.executors.asgi.standalone import ReactPy +from reactpy.executors.asgi.types import AsgiApp from reactpy.testing.logs import ( LogAssertionError, capture_reactpy_logs, list_logged_exceptions, ) +from reactpy.types import ComponentConstructor from reactpy.utils import Ref @@ -34,39 +37,39 @@ class BackendFixture: server.mount(MyComponent) """ - _records: list[logging.LogRecord] + log_records: list[logging.LogRecord] _server_future: asyncio.Task[Any] _exit_stack = AsyncExitStack() def __init__( self, + app: AsgiApp | None = None, host: str = "127.0.0.1", port: int | None = None, - app: Any | None = None, - implementation: BackendType[Any] | None = None, - options: Any | None = None, - timeout: float | None = None, + **reactpy_config: Any, ) -> None: self.host = host - self.port = port or find_available_port(host) - self.mount, self._root_component = _hotswap() - self.timeout = ( - REACTPY_TESTING_DEFAULT_TIMEOUT.current if timeout is None else timeout + self.port = port or 0 + self.mount = mount_to_hotswap + if isinstance(app, (ReactPyMiddleware, ReactPy)): + self._app = app + elif app: + self._app = ReactPyMiddleware( + app, + root_components=["reactpy.testing.backend.root_hotswap_component"], + **reactpy_config, + ) + else: + self._app = ReactPy( + root_hotswap_component, + **reactpy_config, + ) + self.webserver = uvicorn.Server( + uvicorn.Config( + app=self._app, host=self.host, port=self.port, loop="asyncio" + ) ) - if app is not None and implementation is None: - msg = "If an application instance its corresponding server implementation must be provided too." - raise ValueError(msg) - - self._app = app - self.implementation = implementation or default_server - self._options = options - - @property - def log_records(self) -> list[logging.LogRecord]: - """A list of captured log records""" - return self._records - def url(self, path: str = "", query: Any | None = None) -> str: """Return a URL string pointing to the host and point of the server @@ -109,31 +112,29 @@ def list_logged_exceptions( async def __aenter__(self) -> BackendFixture: self._exit_stack = AsyncExitStack() - self._records = self._exit_stack.enter_context(capture_reactpy_logs()) - - app = self._app or self.implementation.create_development_app() - self.implementation.configure(app, self._root_component, self._options) - - started = asyncio.Event() - server_future = asyncio.create_task( - self.implementation.serve_development_app( - app, self.host, self.port, started - ) - ) - - async def stop_server() -> None: - server_future.cancel() - with suppress(asyncio.CancelledError): - await asyncio.wait_for(server_future, timeout=self.timeout) - - self._exit_stack.push_async_callback(stop_server) - - try: - await asyncio.wait_for(started.wait(), timeout=self.timeout) - except Exception: # nocov - # see if we can await the future for a more helpful error - await asyncio.wait_for(server_future, timeout=self.timeout) - raise + self.log_records = self._exit_stack.enter_context(capture_reactpy_logs()) + + # Wait for the server to start + self.webserver.config.get_loop_factory() + self.webserver_task = asyncio.create_task(self.webserver.serve()) + for _ in range(100): + if self.webserver.started and self.webserver.servers: + break + await asyncio.sleep(0.1) + else: + msg = "Server failed to start" + raise RuntimeError(msg) + + # Determine the port if it was set to 0 (auto-select port) + if self.port == 0: + for server in self.webserver.servers: + for sock in server.sockets: + if sock.family == socket.AF_INET: + self.port = sock.getsockname()[1] + self.webserver.config.port = self.port + break + if self.port != 0: + break return self @@ -145,13 +146,19 @@ async def __aexit__( ) -> None: await self._exit_stack.aclose() - self.mount(None) # reset the view - logged_errors = self.list_logged_exceptions(del_log_records=False) if logged_errors: # nocov msg = "Unexpected logged exception" raise LogAssertionError(msg) from logged_errors[0] + await self.webserver.shutdown() + self.webserver_task.cancel() + + async def restart(self) -> None: + """Restart the server""" + await self.__aexit__(None, None, None) + await self.__aenter__() + _MountFunc = Callable[["Callable[[], Any] | None"], None] @@ -174,18 +181,22 @@ def _hotswap(update_on_change: bool = False) -> tuple[_MountFunc, ComponentConst show, root = reactpy.hotswap() PerClientStateServer(root).run_in_thread("localhost", 8765) + @reactpy.component def DivOne(self): return {"tagName": "div", "children": [1]} + show(DivOne) # displaying the output now will show DivOne + @reactpy.component def DivTwo(self): return {"tagName": "div", "children": [2]} + show(DivTwo) # displaying the output now will show DivTwo @@ -225,3 +236,6 @@ def swap(constructor: Callable[[], Any] | None) -> None: constructor_ref.current = constructor or (lambda: None) return swap, HotSwap + + +mount_to_hotswap, root_hotswap_component = _hotswap() diff --git a/src/py/reactpy/reactpy/testing/common.py b/src/reactpy/testing/common.py similarity index 86% rename from src/py/reactpy/reactpy/testing/common.py rename to src/reactpy/testing/common.py index c1eb18ba5..bcfce2ebd 100644 --- a/src/py/reactpy/reactpy/testing/common.py +++ b/src/reactpy/testing/common.py @@ -2,32 +2,25 @@ import asyncio import inspect -import shutil +import os import time -from collections.abc import Awaitable +from collections.abc import Awaitable, Callable, Coroutine from functools import wraps -from typing import Any, Callable, Generic, TypeVar, cast +from typing import Any, Generic, ParamSpec, TypeVar, cast from uuid import uuid4 from weakref import ref -from typing_extensions import ParamSpec - -from reactpy.config import REACTPY_TESTING_DEFAULT_TIMEOUT, REACTPY_WEB_MODULES_DIR -from reactpy.core._life_cycle_hook import LifeCycleHook, current_hook +from reactpy.config import REACTPY_TESTS_DEFAULT_TIMEOUT +from reactpy.core._life_cycle_hook import HOOK_STACK, LifeCycleHook from reactpy.core.events import EventHandler, to_event_handler_function - - -def clear_reactpy_web_modules_dir() -> None: - """Clear the directory where ReactPy stores registered web modules""" - for path in REACTPY_WEB_MODULES_DIR.current.iterdir(): - shutil.rmtree(path) if path.is_dir() else path.unlink() - +from reactpy.utils import str_to_bool _P = ParamSpec("_P") _R = TypeVar("_R") _DEFAULT_POLL_DELAY = 0.1 +GITHUB_ACTIONS = str_to_bool(os.getenv("GITHUB_ACTIONS", "")) class poll(Generic[_R]): # noqa: N801 @@ -42,11 +35,12 @@ def __init__( coro: Callable[_P, Awaitable[_R]] if not inspect.iscoroutinefunction(function): - async def coro(*args: _P.args, **kwargs: _P.kwargs) -> _R: + async def async_func(*args: _P.args, **kwargs: _P.kwargs) -> _R: return cast(_R, function(*args, **kwargs)) + coro = async_func else: - coro = cast(Callable[_P, Awaitable[_R]], function) + coro = cast(Callable[_P, Coroutine[Any, Any, _R]], function) self._func = coro self._args = args self._kwargs = kwargs @@ -54,7 +48,7 @@ async def coro(*args: _P.args, **kwargs: _P.kwargs) -> _R: async def until( self, condition: Callable[[_R], bool], - timeout: float = REACTPY_TESTING_DEFAULT_TIMEOUT.current, + timeout: float = REACTPY_TESTS_DEFAULT_TIMEOUT.current, delay: float = _DEFAULT_POLL_DELAY, description: str = "condition to be true", ) -> None: @@ -67,12 +61,12 @@ async def until( break elif (time.time() - started_at) > timeout: # nocov msg = f"Expected {description} after {timeout} seconds - last value was {result!r}" - raise asyncio.TimeoutError(msg) + raise TimeoutError(msg) async def until_is( self, right: _R, - timeout: float = REACTPY_TESTING_DEFAULT_TIMEOUT.current, + timeout: float = REACTPY_TESTS_DEFAULT_TIMEOUT.current, delay: float = _DEFAULT_POLL_DELAY, ) -> None: """Wait until the result is identical to the given value""" @@ -86,7 +80,7 @@ async def until_is( async def until_equals( self, right: _R, - timeout: float = REACTPY_TESTING_DEFAULT_TIMEOUT.current, + timeout: float = REACTPY_TESTS_DEFAULT_TIMEOUT.current, delay: float = _DEFAULT_POLL_DELAY, ) -> None: """Wait until the result is equal to the given value""" @@ -143,7 +137,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if self is None: raise RuntimeError("Hook catcher has been garbage collected") - hook = current_hook() + hook = HOOK_STACK.current_hook() if self.index_by_kwarg is not None: self.index[kwargs[self.index_by_kwarg]] = hook self.latest = hook diff --git a/src/reactpy/testing/display.py b/src/reactpy/testing/display.py new file mode 100644 index 000000000..4dc4c53cb --- /dev/null +++ b/src/reactpy/testing/display.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import os +from contextlib import AsyncExitStack +from logging import getLogger +from types import TracebackType +from typing import TYPE_CHECKING, Any + +from playwright.async_api import Browser, Page, async_playwright, expect + +from reactpy.config import REACTPY_TESTS_DEFAULT_TIMEOUT as DEFAULT_TIMEOUT +from reactpy.testing.backend import BackendFixture +from reactpy.types import RootComponentConstructor + +if TYPE_CHECKING: + import pytest + +_logger = getLogger(__name__) + + +class DisplayFixture: + """A fixture for running web-based tests using ``playwright``""" + + page: Page + browser_is_external: bool = False + backend_is_external: bool = False + + def __init__( + self, + backend: BackendFixture | None = None, + browser: Browser | None = None, + headless: bool = False, + timeout: float | None = None, + ) -> None: + if backend: + self.backend_is_external = True + self.backend = backend + + if browser: + self.browser_is_external = True + self.browser = browser + + self.timeout = DEFAULT_TIMEOUT.current if timeout is None else timeout + self.headless = headless + + async def show( + self, + component: RootComponentConstructor, + ) -> None: + self.backend.mount(component) + await self.goto("/") + + async def goto(self, path: str, query: Any | None = None) -> None: + await self.configure_page() + await self.page.goto(self.backend.url(path, query)) + + async def __aenter__(self) -> DisplayFixture: + self.exit_stack = AsyncExitStack() + + if not hasattr(self, "browser"): + pw = await self.exit_stack.enter_async_context(async_playwright()) + self.browser = await self.exit_stack.enter_async_context( + await pw.chromium.launch(headless=not _playwright_visible()) + ) + + expect.set_options(timeout=self.timeout * 1000) + await self.configure_page() + + if not hasattr(self, "backend"): # nocov + self.backend = BackendFixture() + await self.exit_stack.enter_async_context(self.backend) + + return self + + async def configure_page(self) -> None: + if getattr(self, "page", None) is None: + self.page = await self.browser.new_page() + self.page = await self.exit_stack.enter_async_context(self.page) + self.page.set_default_navigation_timeout(self.timeout * 1000) + self.page.set_default_timeout(self.timeout * 1000) + self.page.on( + "requestfailed", + lambda x: _logger.error(f"BROWSER LOAD ERROR: {x.url}\n{x.failure}"), + ) + self.page.on( + "console", lambda x: _logger.info(f"BROWSER CONSOLE: {x.text}") + ) + self.page.on( + "pageerror", + lambda x: _logger.error( + f"BROWSER ERROR: {x.name} - {x.message}\n{x.stack}" + ), + ) + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: + self.backend.mount(None) + await self.exit_stack.aclose() + + +def _playwright_visible(pytestconfig: pytest.Config | None = None) -> bool: + if (pytestconfig and pytestconfig.getoption("visible")) or os.environ.get( + "PLAYWRIGHT_VISIBLE" + ) == "1": + os.environ.setdefault("PLAYWRIGHT_VISIBLE", "1") + return True + return False diff --git a/src/py/reactpy/reactpy/testing/logs.py b/src/reactpy/testing/logs.py similarity index 98% rename from src/py/reactpy/reactpy/testing/logs.py rename to src/reactpy/testing/logs.py index e9337b19c..38470ea4f 100644 --- a/src/py/reactpy/reactpy/testing/logs.py +++ b/src/reactpy/testing/logs.py @@ -175,4 +175,4 @@ def _raise_log_message_error( conditions.append(f"exception type {error_type}") if match_error: conditions.append(f"error message pattern {match_error!r}") - raise LogAssertionError(prefix + " " + " and ".join(conditions)) + raise LogAssertionError(f"{prefix} " + " and ".join(conditions)) diff --git a/src/reactpy/transforms.py b/src/reactpy/transforms.py new file mode 100644 index 000000000..f1896c831 --- /dev/null +++ b/src/reactpy/transforms.py @@ -0,0 +1,409 @@ +from __future__ import annotations + +from typing import Any, cast + +from reactpy.core.events import EventHandler, to_event_handler_function +from reactpy.types import VdomAttributes, VdomDict + + +def attributes_to_reactjs(attributes: VdomAttributes): + """Convert HTML attribute names to their ReactJS equivalents.""" + attrs = cast(VdomAttributes, attributes.items()) + attrs = cast( + VdomAttributes, + {REACT_PROP_SUBSTITUTIONS.get(k, k): v for k, v in attrs}, + ) + return attrs + + +class RequiredTransforms: + """Performs any necessary transformations related to `string_to_reactpy` to automatically prevent + issues with React's rendering engine. + """ + + def __init__(self, vdom: VdomDict, intercept_links: bool = True) -> None: + self._intercept_links = intercept_links + + # Run every transform in this class. + for name in dir(self): + # Any method that doesn't start with an underscore is assumed to be a transform. + if not name.startswith("_"): + getattr(self, name)(vdom) + + def normalize_style_attributes(self, vdom: dict[str, Any]) -> None: + """Convert style attribute from str -> dict with camelCase keys""" + if ( + "attributes" in vdom + and "style" in vdom["attributes"] + and isinstance(vdom["attributes"]["style"], str) + ): + vdom["attributes"]["style"] = { + self._kebab_to_camel_case(key.strip()): value.strip() + for key, value in ( + part.split(":", 1) + for part in vdom["attributes"]["style"].split(";") + if ":" in part + ) + } + + @staticmethod + def textarea_children_to_prop(vdom: VdomDict) -> None: + """Transformation that converts the text content of a ", + "model": { + "tagName": "textarea", + "attributes": {"defaultValue": "Hello World."}, + }, + }, + # 3: Convert ", + "model": { + "tagName": "select", + "attributes": {"defaultValue": "Option 1"}, + "children": [ + { + "children": ["Option 1"], + "tagName": "option", + "attributes": {"value": "Option 1"}, + } + ], + }, + }, + # 4: Convert ", + "model": { + "tagName": "select", + "attributes": { + "defaultValue": ["Option 1", "Option 2"], + "multiple": True, + }, + "children": [ + { + "children": ["Option 1"], + "tagName": "option", + "attributes": {"value": "Option 1"}, + }, + { + "children": ["Option 2"], + "tagName": "option", + "attributes": {"value": "Option 2"}, + }, + ], + }, + }, + # 5: Convert value attribute into `defaultValue` + { + "source": '', + "model": { + "tagName": "input", + "attributes": {"defaultValue": "Hello World.", "type": "text"}, + }, + }, + # 6: Infer ReactJS `key` from the `id` attribute + { + "source": '
', + "model": { + "tagName": "div", + "attributes": {"id": "my-key", "key": "my-key"}, + }, + }, + # 7: Infer ReactJS `key` from the `name` attribute + { + "source": '', + "model": { + "tagName": "input", + "attributes": {"type": "text", "name": "my-input", "key": "my-input"}, + }, + }, + # 8: Infer ReactJS `key` from the `key` attribute + { + "source": '
', + "model": { + "tagName": "div", + "attributes": {"key": "my-key"}, + }, + }, + # 9: Includes `inlineJavaScript` attribue + { + "source": """""", + "model": { + "tagName": "button", + "inlineJavaScript": {"onClick": "this.innerText = 'CLICKED'"}, + "children": ["Click Me"], + }, + }, + ], +) +def test_string_to_reactpy_default_transforms(case): + assert utils.string_to_reactpy(case["source"]) == case["model"] + + +def test_string_to_reactpy_intercept_links(): + source = 'Hello World' + expected = { + "tagName": "a", + "children": ["Hello World"], + "attributes": {"href": "https://example.com"}, + } + result = utils.string_to_reactpy(source, intercept_links=True) + + # Check if the result equals expected when removing `eventHandlers` from the result dict + event_handlers = result.pop("eventHandlers", {}) + assert result == expected + + # Make sure the event handlers dict contains an `onClick` key + assert "onClick" in event_handlers + + +def test_string_to_reactpy_custom_transform(): + source = "

hello world and universelmao

" + + def make_links_blue(node): + if node["tagName"] == "a": + node["attributes"] = {"style": {"color": "blue"}} + return node + + expected = { + "tagName": "p", + "children": [ + "hello ", + { + "tagName": "a", + "children": ["world"], + "attributes": {"style": {"color": "blue"}}, + }, + " and ", + { + "tagName": "a", + "children": ["universe"], + "attributes": {"style": {"color": "blue"}}, + }, + "lmao", + ], + } + + assert ( + utils.string_to_reactpy(source, make_links_blue, intercept_links=False) + == expected + ) + + +def test_non_html_tag_behavior(): + source = ( + " " + ) + + expected = { + "tagName": "my-tag", + "attributes": {"data-x": "something"}, + "children": [ + {"tagName": "my-other-tag", "attributes": {"key": "a-key"}}, + ], + } + + assert utils.string_to_reactpy(source, strict=False) == expected + + with pytest.raises(utils.HTMLParseError): + utils.string_to_reactpy(source, strict=True) + + +class StableReprObject: + def __repr__(self): + return "StableReprObject" + + +SOME_OBJECT = StableReprObject() + + +@component +def example_parent(): + return example_middle() + + +@component +def example_middle(): + return html.div({"id": "sample", "style": {"padding": "15px"}}, example_child()) + + +@component +def example_child(): + return html.h1("Example") + + +@component +def example_str_return(): + return "Example" + + +@component +def example_none_return(): + return None + + +@pytest.mark.parametrize( + "vdom_in, html_out", + [ + ( + html.div("hello"), + "
hello
", + ), + ( + html.div(SOME_OBJECT), + f"
{html_escape(str(SOME_OBJECT))}
", + ), + ( + html.div( + "hello", html.a({"href": "https://example.com"}, "example"), "world" + ), + '
helloexampleworld
', + ), + ( + html.button({"onClick": lambda event: None}), + "", + ), + ( + html("hello ", html("world")), + "hello world", + ), + ( + html(html.div("hello"), html("world")), + "
hello
world", + ), + ( + html.div({"style": {"backgroundColor": "blue", "marginLeft": "10px"}}), + '
', + ), + ( + html.div({"style": "background-color:blue;margin-left:10px"}), + '
', + ), + ( + html( + html.div("hello"), + html.a({"href": "https://example.com"}, "example"), + ), + '
hello
example', + ), + ( + html.div( + html( + html.div("hello"), + html.a({"href": "https://example.com"}, "example"), + ), + html.button(), + ), + '
hello
example
', + ), + ( + html.div({"data-Something": 1, "dataCamelCase": 2, "datalowercase": 3}), + '
', + ), + ( + html.div(example_parent()), + '

Example

', + ), + ( + example_parent(), + '

Example

', + ), + ( + html.form({"acceptCharset": "utf-8"}), + '
', + ), + ( + example_str_return(), + "
Example
", + ), + ( + example_none_return(), + "", + ), + ], +) +def test_reactpy_to_string(vdom_in, html_out): + assert utils.reactpy_to_string(vdom_in) == html_out + + +def test_reactpy_to_string_error(): + with pytest.raises(TypeError, match=r"Expected a VDOM dict"): + utils.reactpy_to_string({"notVdom": True}) + + +def test_invalid_dotted_path(): + with pytest.raises(ValueError, match=r'"abc" is not a valid dotted path.'): + utils.import_dotted_path("abc") + + +def test_invalid_component(): + with pytest.raises( + AttributeError, match=r'ReactPy failed to import "foobar" from "reactpy"' + ): + utils.import_dotted_path("reactpy.foobar") + + +def test_invalid_module(): + with pytest.raises(ImportError, match=r'ReactPy failed to import "foo"'): + utils.import_dotted_path("foo.bar") diff --git a/tests/test_web/__init__.py b/tests/test_web/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_web/js_fixtures/callable-prop.js b/tests/test_web/js_fixtures/callable-prop.js new file mode 100644 index 000000000..d16dd333a --- /dev/null +++ b/tests/test_web/js_fixtures/callable-prop.js @@ -0,0 +1,24 @@ +import { h, render } from "https://unpkg.com/preact?module"; +import htm from "https://unpkg.com/htm?module"; + +const html = htm.bind(h); + +export function bind(node, config) { + return { + create: (type, props, children) => h(type, props, ...children), + render: (element) => render(element, node), + unmount: () => render(null, node), + }; +} + +export function Component(props) { + var text = "DEFAULT"; + if (props.setText && typeof props.setText === "function") { + text = props.setText("PREFIX TEXT: "); + } + return html` +
+ ${text} +
+ `; +} diff --git a/tests/test_web/js_fixtures/component-can-have-child.js b/tests/test_web/js_fixtures/component-can-have-child.js new file mode 100644 index 000000000..fd443b164 --- /dev/null +++ b/tests/test_web/js_fixtures/component-can-have-child.js @@ -0,0 +1,27 @@ +import { h, render } from "https://unpkg.com/preact?module"; +import htm from "https://unpkg.com/htm?module"; + +const html = htm.bind(h); + +export function bind(node, config) { + return { + create: (type, props, children) => h(type, props, ...children), + render: (element) => render(element, node), + unmount: () => render(null, node), + }; +} + +// The intention here is that Child components are passed in here so we check that the +// children of "the-parent" are "child-1" through "child-N" +export function Parent(props) { + return html` +
+

the parent

+
    ${props.children}
+
+ `; +} + +export function Child({ index }) { + return html`
  • child ${index}
  • `; +} diff --git a/tests/test_web/js_fixtures/export-resolution/index.js b/tests/test_web/js_fixtures/export-resolution/index.js new file mode 100644 index 000000000..372f108bd --- /dev/null +++ b/tests/test_web/js_fixtures/export-resolution/index.js @@ -0,0 +1,2 @@ +export { index as Index }; +export * from "./one.js"; diff --git a/tests/test_web/js_fixtures/export-resolution/one.js b/tests/test_web/js_fixtures/export-resolution/one.js new file mode 100644 index 000000000..ddea9d2cb --- /dev/null +++ b/tests/test_web/js_fixtures/export-resolution/one.js @@ -0,0 +1,5 @@ +export { one as One }; +// use ../ just to check that it works +export * from "../export-resolution/two.js"; +// this default should not be exported by the * re-export in index.js +export default 0; diff --git a/tests/test_web/js_fixtures/export-resolution/two.js b/tests/test_web/js_fixtures/export-resolution/two.js new file mode 100644 index 000000000..f01389d2e --- /dev/null +++ b/tests/test_web/js_fixtures/export-resolution/two.js @@ -0,0 +1,2 @@ +export { two as Two }; +export * from "https://some.external.url"; diff --git a/tests/test_web/js_fixtures/exports-syntax.js b/tests/test_web/js_fixtures/exports-syntax.js new file mode 100644 index 000000000..8f9b0e612 --- /dev/null +++ b/tests/test_web/js_fixtures/exports-syntax.js @@ -0,0 +1,23 @@ +// Copied from: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export + +// Exporting individual features +export let name1, name2, name3; // also var, const +export let name4 = 4, name5 = 5, name6; // also var, const +export function functionName(){...} +export class ClassName {...} + +// Export list +export { name7, name8, name9 }; + +// Renaming exports +export { variable1 as name10, variable2 as name11, name12 }; + +// Exporting destructured assignments with renaming +export const { name13, name14: bar } = o; + +// Aggregating modules +export * from "https://source1.com"; // does not set the default export +export * from "https://source2.com"; // does not set the default export +export * as name15 from "https://source3.com"; // Draft ECMAScript® 2O21 +export { name16, name17 } from "https://source4.com"; +export { import1 as name18, import2 as name19, name20 } from "https://source5.com"; diff --git a/tests/test_web/js_fixtures/exports-two-components.js b/tests/test_web/js_fixtures/exports-two-components.js new file mode 100644 index 000000000..10aa7fdbe --- /dev/null +++ b/tests/test_web/js_fixtures/exports-two-components.js @@ -0,0 +1,20 @@ +import { h, render } from "https://unpkg.com/preact?module"; +import htm from "https://unpkg.com/htm?module"; + +const html = htm.bind(h); + +export function bind(node, config) { + return { + create: (type, props, children) => h(type, props, ...children), + render: (element) => render(element, node), + unmount: () => render(null, node), + }; +} + +export function Header1(props) { + return h("h1", { id: props.id }, props.text); +} + +export function Header2(props) { + return h("h2", { id: props.id }, props.text); +} diff --git a/tests/test_web/js_fixtures/generic-module.js b/tests/test_web/js_fixtures/generic-module.js new file mode 100644 index 000000000..634b057cf --- /dev/null +++ b/tests/test_web/js_fixtures/generic-module.js @@ -0,0 +1,5 @@ +import { h } from "https://unpkg.com/preact?module"; + +export function GenericComponent(props) { + return h("div", { id: props.id }, props.text); +} diff --git a/tests/test_web/js_fixtures/keys-properly-propagated.js b/tests/test_web/js_fixtures/keys-properly-propagated.js new file mode 100644 index 000000000..8d700397e --- /dev/null +++ b/tests/test_web/js_fixtures/keys-properly-propagated.js @@ -0,0 +1,14 @@ +import React from "https://esm.sh/react@19.0" +import ReactDOM from "https://esm.sh/react-dom@19.0/client" +import GridLayout from "https://esm.sh/react-grid-layout@1.5.0"; +export {GridLayout}; + +export function bind(node, config) { + const root = ReactDOM.createRoot(node); + return { + create: (type, props, children) => + React.createElement(type, props, children), + render: (element) => root.render(element, node), + unmount: () => root.unmount() + }; +} diff --git a/tests/test_web/js_fixtures/set-flag-when-unmount-is-called.js b/tests/test_web/js_fixtures/set-flag-when-unmount-is-called.js new file mode 100644 index 000000000..dbb1a1c99 --- /dev/null +++ b/tests/test_web/js_fixtures/set-flag-when-unmount-is-called.js @@ -0,0 +1,31 @@ +export function bind(node, config) { + return { + create: (type, props, children) => type(props), + render: (element) => renderElement(element, node), + unmount: () => unmountElement(node), + }; +} + +export function renderElement(element, container) { + if (container.firstChild) { + container.removeChild(container.firstChild); + } + container.appendChild(element); +} + +export function unmountElement(container) { + // We add an element to the document.body to indicate that this function was called. + // Thus allowing Selenium to see communicate to server-side code that this effect + // did indeed occur. + const unmountFlag = document.createElement("h1"); + unmountFlag.setAttribute("id", "unmount-flag"); + document.body.appendChild(unmountFlag); + container.innerHTML = ""; +} + +export function SomeComponent(props) { + const element = document.createElement("h1"); + element.appendChild(document.createTextNode(props.text)); + element.setAttribute("id", props.id); + return element; +} diff --git a/tests/test_web/js_fixtures/simple-button.js b/tests/test_web/js_fixtures/simple-button.js new file mode 100644 index 000000000..2b49f505b --- /dev/null +++ b/tests/test_web/js_fixtures/simple-button.js @@ -0,0 +1,25 @@ +import { h, render } from "https://unpkg.com/preact?module"; +import htm from "https://unpkg.com/htm?module"; + +const html = htm.bind(h); + +export function bind(node, config) { + return { + create: (type, props, children) => h(type, props, ...children), + render: (element) => render(element, node), + unmount: () => render(null, node), + }; +} + +export function SimpleButton(props) { + return h( + "button", + { + id: props.id, + onClick(event) { + props.onClick({ data: props.eventResponseData }); + }, + }, + "simple button", + ); +} diff --git a/tests/test_web/js_fixtures/subcomponent-notation.js b/tests/test_web/js_fixtures/subcomponent-notation.js new file mode 100644 index 000000000..85c8d709f --- /dev/null +++ b/tests/test_web/js_fixtures/subcomponent-notation.js @@ -0,0 +1,10 @@ +import React from "react"; + +const InputGroup = ({ children }) => React.createElement("div", { className: "input-group" }, children); +InputGroup.Text = ({ children, ...props }) => React.createElement("span", { className: "input-group-text", ...props }, children); + +const Form = ({ children }) => React.createElement("form", {}, children); +Form.Control = ({ children, ...props }) => React.createElement("input", { className: "form-control", ...props }, children); +Form.Label = ({ children, ...props }) => React.createElement("label", { className: "form-label", ...props }, children); + +export { InputGroup, Form }; diff --git a/tests/test_web/test_module.py b/tests/test_web/test_module.py new file mode 100644 index 000000000..cddcc86dc --- /dev/null +++ b/tests/test_web/test_module.py @@ -0,0 +1,565 @@ +# THESE ARE TESTS FOR THE LEGACY API. SEE tests/test_reactjs/* FOR THE NEW API TESTS. +# THIS MODULE WILL BE MIGRATED OR DELETED ONCE THE LEGACY API IS REMOVED. +from pathlib import Path + +import pytest +from servestatic import ServeStaticASGI + +import reactpy +import reactpy.reactjs +from reactpy.executors.asgi.standalone import ReactPy +from reactpy.reactjs import NAME_SOURCE, JavaScriptModule, import_reactjs +from reactpy.testing import ( + BackendFixture, + DisplayFixture, + assert_reactpy_did_log, + assert_reactpy_did_not_log, + poll, +) +from reactpy.types import InlineJavaScript + +JS_FIXTURES_DIR = Path(__file__).parent / "js_fixtures" + + +@pytest.fixture(scope="module") +async def display(browser): + """Override for the display fixture that includes ReactJS.""" + async with BackendFixture(html_head=reactpy.html.head(import_reactjs())) as backend: + async with DisplayFixture(backend=backend, browser=browser) as new_display: + yield new_display + + +async def test_that_js_module_unmount_is_called(display: DisplayFixture): + SomeComponent = reactpy.reactjs.module_to_vdom( + reactpy.reactjs.file_to_module( + "set-flag-when-unmount-is-called", + JS_FIXTURES_DIR / "set-flag-when-unmount-is-called.js", + ), + "SomeComponent", + ) + + set_current_component = reactpy.Ref(None) + + @reactpy.component + def ShowCurrentComponent(): + current_component, set_current_component.current = reactpy.hooks.use_state( + lambda: SomeComponent({"id": "some-component", "text": "initial component"}) + ) + return current_component + + await display.show(ShowCurrentComponent) + + await display.page.wait_for_selector("#some-component", state="attached") + + set_current_component.current( + reactpy.html.h1({"id": "some-other-component"}, "some other component") + ) + + # the new component has been displayed + await display.page.wait_for_selector("#some-other-component", state="attached") + + # the unmount callback for the old component was called + await display.page.wait_for_selector("#unmount-flag", state="attached") + + +async def test_module_from_url(browser): + SimpleButton = reactpy.reactjs.module_to_vdom( + reactpy.reactjs.url_to_module( + "/static/simple-button.js", resolve_imports=False + ), + "SimpleButton", + ) + + @reactpy.component + def ShowSimpleButton(): + return SimpleButton({"id": "my-button"}) + + app = ReactPy(ShowSimpleButton) + app = ServeStaticASGI(app, JS_FIXTURES_DIR, "/static/") + + async with BackendFixture(app) as server: + async with DisplayFixture(server, browser=browser) as display: + await display.show(ShowSimpleButton) + + await display.page.wait_for_selector("#my-button") + + +async def test_module_from_file(display: DisplayFixture): + SimpleButton = reactpy.reactjs.module_to_vdom( + reactpy.reactjs.file_to_module( + "simple-button", JS_FIXTURES_DIR / "simple-button.js" + ), + "SimpleButton", + ) + + is_clicked = reactpy.Ref(False) + + @reactpy.component + def ShowSimpleButton(): + return SimpleButton( + {"id": "my-button", "onClick": lambda event: is_clicked.set_current(True)} + ) + + await display.show(ShowSimpleButton) + + button = await display.page.wait_for_selector("#my-button") + await button.click() + await poll(lambda: is_clicked.current).until_is(True) + + +def test_module_from_file_source_conflict(tmp_path): + first_file = tmp_path / "first.js" + + with pytest.raises(FileNotFoundError, match=r"does not exist"): + reactpy.reactjs.file_to_module( + "test-module-from-file-source-conflict", first_file + ) + + first_file.touch() + + reactpy.reactjs.file_to_module("test-module-from-file-source-conflict", first_file) + + second_file = tmp_path / "second.js" + second_file.touch() + + # ok, same content + reactpy.reactjs.file_to_module("test-module-from-file-source-conflict", second_file) + + third_file = tmp_path / "third.js" + third_file.write_text("something-different") + + with assert_reactpy_did_log(r"Existing web module .* will be replaced with"): + reactpy.reactjs.file_to_module( + "test-module-from-file-source-conflict", third_file + ) + + +def test_web_module_from_file_symlink(tmp_path): + file = tmp_path / "temp.js" + file.touch() + + module = reactpy.reactjs.file_to_module( + "test-web-module-from-file-symlink", file, symlink=True + ) + + assert module.file.resolve().read_text() == "" + + file.write_text("hello world!") + + assert module.file.resolve().read_text() == "hello world!" + + +def test_web_module_from_file_symlink_twice(tmp_path): + file_1 = tmp_path / "temp_1.js" + file_1.touch() + + reactpy.reactjs.file_to_module( + "test-web-module-from-file-symlink-twice", file_1, symlink=True + ) + with assert_reactpy_did_not_log( + r"Existing web module 'test-web-module-from-file-symlink-twice.js' will be replaced with" + ): + reactpy.reactjs.file_to_module( + "test-web-module-from-file-symlink-twice", file_1, symlink=True + ) + file_2 = tmp_path / "temp_2.js" + file_2.write_text("something") + with assert_reactpy_did_log( + r"Existing web module 'test-web-module-from-file-symlink-twice.js' will be replaced with" + ): + reactpy.reactjs.file_to_module( + "test-web-module-from-file-symlink-twice", file_2, symlink=True + ) + + +def test_web_module_from_file_replace_existing(tmp_path): + file1 = tmp_path / "temp1.js" + file1.touch() + + reactpy.reactjs.file_to_module("test-web-module-from-file-replace-existing", file1) + + file2 = tmp_path / "temp2.js" + file2.write_text("something") + + with assert_reactpy_did_log(r"Existing web module .* will be replaced with"): + reactpy.reactjs.file_to_module( + "test-web-module-from-file-replace-existing", file2 + ) + + +def test_module_missing_exports(): + module = JavaScriptModule("test", NAME_SOURCE, None, {"a", "b", "c"}, None, False) + + with pytest.raises(ValueError, match=r"does not contain 'x'"): + reactpy.reactjs.module_to_vdom(module, "x") + + with pytest.raises(ValueError, match=r"does not contain \['x', 'y'\]"): + reactpy.reactjs.module_to_vdom(module, ["x", "y"]) + + +async def test_module_exports_multiple_components(display: DisplayFixture): + Header1, Header2 = reactpy.reactjs.module_to_vdom( + reactpy.reactjs.file_to_module( + "exports-two-components", JS_FIXTURES_DIR / "exports-two-components.js" + ), + ["Header1", "Header2"], + ) + + await display.show(lambda: Header1({"id": "my-h1"}, "My Header 1")) + + await display.page.wait_for_selector("#my-h1", state="attached") + + await display.show(lambda: Header2({"id": "my-h2"}, "My Header 2")) + + await display.page.wait_for_selector("#my-h2", state="attached") + + +async def test_imported_components_can_render_children(display: DisplayFixture): + module = reactpy.reactjs.file_to_module( + "component-can-have-child", JS_FIXTURES_DIR / "component-can-have-child.js" + ) + Parent, Child = reactpy.reactjs.module_to_vdom(module, ["Parent", "Child"]) + + await display.show( + lambda: Parent( + Child({"index": 1}), + Child({"index": 2}), + Child({"index": 3}), + ) + ) + + parent = await display.page.wait_for_selector("#the-parent", state="attached") + children = await parent.query_selector_all("li") + + assert len(children) == 3 + + for index, child in enumerate(children): + assert (await child.get_attribute("id")) == f"child-{index + 1}" + + +async def test_keys_properly_propagated(display: DisplayFixture): + """ + Fix https://github.com/reactive-python/reactpy/issues/1275 + + The `key` property was being lost in its propagation from the server-side ReactPy + definition to the front-end JavaScript. + + This property is required for certain JS components, such as the GridLayout from + react-grid-layout. + """ + module = reactpy.reactjs.file_to_module( + "keys-properly-propagated", JS_FIXTURES_DIR / "keys-properly-propagated.js" + ) + GridLayout = reactpy.reactjs.module_to_vdom(module, "GridLayout") + + await display.show( + lambda: GridLayout( + { + "layout": [ + { + "i": "a", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "static": True, + }, + { + "i": "b", + "x": 1, + "y": 0, + "w": 3, + "h": 2, + "minW": 2, + "maxW": 4, + }, + { + "i": "c", + "x": 4, + "y": 0, + "w": 1, + "h": 2, + }, + ], + "cols": 12, + "rowHeight": 30, + "width": 1200, + }, + reactpy.html.div({"key": "a"}, "a"), + reactpy.html.div({"key": "b"}, "b"), + reactpy.html.div({"key": "c"}, "c"), + ) + ) + + parent = await display.page.wait_for_selector( + ".react-grid-layout", state="attached" + ) + children = await parent.query_selector_all("div") + + # The children simply will not render unless they receive the key prop + assert len(children) == 3 + + +async def test_subcomponent_notation_as_str_attrs(display: DisplayFixture): + module = reactpy.reactjs.file_to_module( + "subcomponent-notation", + JS_FIXTURES_DIR / "subcomponent-notation.js", + ) + InputGroup, InputGroupText, FormControl, FormLabel = reactpy.reactjs.module_to_vdom( + module, ["InputGroup", "InputGroup.Text", "Form.Control", "Form.Label"] + ) + + content = reactpy.html.div( + {"id": "the-parent"}, + InputGroup( + InputGroupText({"id": "basic-addon1"}, "@"), + FormControl( + { + "placeholder": "Username", + "aria-label": "Username", + "aria-describedby": "basic-addon1", + } + ), + ), + InputGroup( + FormControl( + { + "placeholder": "Recipient's username", + "aria-label": "Recipient's username", + "aria-describedby": "basic-addon2", + } + ), + InputGroupText({"id": "basic-addon2"}, "@example.com"), + ), + FormLabel({"htmlFor": "basic-url"}, "Your vanity URL"), + InputGroup( + InputGroupText({"id": "basic-addon3"}, "https://example.com/users/"), + FormControl({"id": "basic-url", "aria-describedby": "basic-addon3"}), + ), + InputGroup( + InputGroupText("$"), + FormControl({"aria-label": "Amount (to the nearest dollar)"}), + InputGroupText(".00"), + ), + InputGroup( + InputGroupText("With textarea"), + FormControl({"as": "textarea", "aria-label": "With textarea"}), + ), + ) + + await display.show(lambda: content) + await display.page.wait_for_selector("#basic-addon3", state="attached") + parent = await display.page.wait_for_selector("#the-parent", state="attached") + input_group_text = await parent.query_selector_all(".input-group-text") + form_control = await parent.query_selector_all(".form-control") + form_label = await parent.query_selector_all(".form-label") + + assert len(input_group_text) == 6 + assert len(form_control) == 5 + assert len(form_label) == 1 + + +async def test_subcomponent_notation_as_obj_attrs(display: DisplayFixture): + module = reactpy.reactjs.file_to_module( + "subcomponent-notation", + JS_FIXTURES_DIR / "subcomponent-notation.js", + ) + InputGroup, Form = reactpy.reactjs.module_to_vdom(module, ["InputGroup", "Form"]) + + content = reactpy.html.div( + {"id": "the-parent"}, + InputGroup( + InputGroup.Text({"id": "basic-addon1"}, "@"), + Form.Control( + { + "placeholder": "Username", + "aria-label": "Username", + "aria-describedby": "basic-addon1", + } + ), + ), + InputGroup( + Form.Control( + { + "placeholder": "Recipient's username", + "aria-label": "Recipient's username", + "aria-describedby": "basic-addon2", + } + ), + InputGroup.Text({"id": "basic-addon2"}, "@example.com"), + ), + Form.Label({"htmlFor": "basic-url"}, "Your vanity URL"), + InputGroup( + InputGroup.Text({"id": "basic-addon3"}, "https://example.com/users/"), + Form.Control({"id": "basic-url", "aria-describedby": "basic-addon3"}), + ), + InputGroup( + InputGroup.Text("$"), + Form.Control({"aria-label": "Amount (to the nearest dollar)"}), + InputGroup.Text(".00"), + ), + InputGroup( + InputGroup.Text("With textarea"), + Form.Control({"as": "textarea", "aria-label": "With textarea"}), + ), + ) + + await display.show(lambda: content) + + await display.page.wait_for_selector("#basic-addon3", state="attached") + parent = await display.page.wait_for_selector("#the-parent", state="attached") + input_group_text = await parent.query_selector_all(".input-group-text") + form_control = await parent.query_selector_all(".form-control") + form_label = await parent.query_selector_all(".form-label") + + assert len(input_group_text) == 6 + assert len(form_control) == 5 + assert len(form_label) == 1 + + +async def test_callable_prop_with_javacript(display: DisplayFixture): + module = reactpy.reactjs.file_to_module( + "callable-prop", JS_FIXTURES_DIR / "callable-prop.js" + ) + Component = reactpy.reactjs.module_to_vdom(module, "Component") + + @reactpy.component + def App(): + return Component( + { + "id": "my-div", + "setText": InlineJavaScript('(prefixText) => prefixText + "TEST 123"'), + } + ) + + await display.show(lambda: App()) + + my_div = await display.page.wait_for_selector("#my-div", state="attached") + assert await my_div.inner_text() == "PREFIX TEXT: TEST 123" + + +def test_component_from_string(): + reactpy.reactjs.component_from_string( + "old", "Component", resolve_imports=False, name="test-component-from-string" + ) + reactpy.reactjs._STRING_JS_MODULE_CACHE.clear() + with assert_reactpy_did_log(r"Existing web module .* will be replaced with"): + reactpy.reactjs.component_from_string( + "new", "Component", resolve_imports=False, name="test-component-from-string" + ) + + +async def test_component_from_url(browser): + SimpleButton = reactpy.reactjs.component_from_url( + "/static/simple-button.js", "SimpleButton", resolve_imports=False + ) + + @reactpy.component + def ShowSimpleButton(): + return SimpleButton({"id": "my-button"}) + + app = ReactPy(ShowSimpleButton) + app = ServeStaticASGI(app, JS_FIXTURES_DIR, "/static/") + + async with BackendFixture(app) as server: + async with DisplayFixture(server, browser=browser) as display: + await display.show(ShowSimpleButton) + + await display.page.wait_for_selector("#my-button") + + +async def test_component_from_file(display: DisplayFixture): + SimpleButton = reactpy.reactjs.component_from_file( + JS_FIXTURES_DIR / "simple-button.js", "SimpleButton", name="simple-button" + ) + + is_clicked = reactpy.Ref(False) + + @reactpy.component + def ShowSimpleButton(): + return SimpleButton( + {"id": "my-button", "onClick": lambda event: is_clicked.set_current(True)} + ) + + await display.show(ShowSimpleButton) + + button = await display.page.wait_for_selector("#my-button") + await button.click() + await poll(lambda: is_clicked.current).until_is(True) + + +def test_component_from_url_caching(): + url = "https://example.com/module.js" + reactpy.reactjs._URL_JS_MODULE_CACHE.clear() + + # First import + reactpy.reactjs.component_from_url(url, "Component", resolve_imports=False) + # Find the key that contains the 'url' substring + key = next(x for x in reactpy.reactjs._URL_JS_MODULE_CACHE.keys() if url in x) + module1 = reactpy.reactjs._URL_JS_MODULE_CACHE[key] + assert module1 + initial_length = len(reactpy.reactjs._URL_JS_MODULE_CACHE) + + # Second import + reactpy.reactjs.component_from_url(url, "Component", resolve_imports=False) + assert len(reactpy.reactjs._URL_JS_MODULE_CACHE) == initial_length + + +def test_component_from_file_caching(tmp_path): + file = tmp_path / "test.js" + file.write_text("export function Component() {}") + name = "test-file-module" + reactpy.reactjs._FILE_JS_MODULE_CACHE.clear() + + reactpy.reactjs.component_from_file(file, "Component", name=name) + key = next(x for x in reactpy.reactjs._FILE_JS_MODULE_CACHE.keys() if name in x) + module1 = reactpy.reactjs._FILE_JS_MODULE_CACHE[key] + assert module1 + initial_length = len(reactpy.reactjs._FILE_JS_MODULE_CACHE) + + reactpy.reactjs.component_from_file(file, "Component", name=name) + assert len(reactpy.reactjs._FILE_JS_MODULE_CACHE) == initial_length + + +def test_component_from_string_caching(): + name = "test-string-module" + content = "export function Component() {}" + reactpy.reactjs._STRING_JS_MODULE_CACHE.clear() + + reactpy.reactjs.component_from_string(content, "Component", name=name) + key = next(x for x in reactpy.reactjs._STRING_JS_MODULE_CACHE.keys() if name in x) + module1 = reactpy.reactjs._STRING_JS_MODULE_CACHE[key] + assert module1 + initial_length = len(reactpy.reactjs._STRING_JS_MODULE_CACHE) + + reactpy.reactjs.component_from_string(content, "Component", name=name) + assert len(reactpy.reactjs._STRING_JS_MODULE_CACHE) == initial_length + + +def test_component_from_string_with_no_name(): + content = "export function Component() {}" + reactpy.reactjs._STRING_JS_MODULE_CACHE.clear() + + reactpy.reactjs.component_from_string(content, "Component") + initial_length = len(reactpy.reactjs._STRING_JS_MODULE_CACHE) + + reactpy.reactjs.component_from_string(content, "Component") + assert len(reactpy.reactjs._STRING_JS_MODULE_CACHE) == initial_length + + +async def test_module_without_bind(display: DisplayFixture): + GenericComponent = reactpy.reactjs.module_to_vdom( + reactpy.reactjs.file_to_module( + "generic-module", JS_FIXTURES_DIR / "generic-module.js" + ), + "GenericComponent", + ) + + await display.show( + lambda: GenericComponent({"id": "my-generic-component", "text": "Hello World"}) + ) + + element = await display.page.wait_for_selector( + "#my-generic-component", state="attached" + ) + assert await element.inner_text() == "Hello World" diff --git a/src/py/reactpy/tests/test_widgets.py b/tests/test_widgets.py similarity index 94% rename from src/py/reactpy/tests/test_widgets.py rename to tests/test_widgets.py index d786fded0..fd44bd9f4 100644 --- a/src/py/reactpy/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -96,14 +96,14 @@ def SomeComponent(): input_1 = await display.page.wait_for_selector("#i_1") input_2 = await display.page.wait_for_selector("#i_2") - await input_1.type("1") + await input_1.type("1", delay=DEFAULT_TYPE_DELAY) poll_value = poll(lambda: value.current) await poll_value.until_equals(1) await input_2.focus() - await input_2.type("2") + await input_2.type("2", delay=DEFAULT_TYPE_DELAY) await poll_value.until_equals(12) @@ -125,7 +125,7 @@ def SomeComponent(): input_1 = await display.page.wait_for_selector("#i_1") input_2 = await display.page.wait_for_selector("#i_2") - await input_1.type("1") + await input_1.type("1", delay=DEFAULT_TYPE_DELAY) poll_value = poll(lambda: value.current) @@ -136,6 +136,6 @@ def SomeComponent(): await poll_value.until_equals("1") - await input_2.type("2") + await input_2.type("2", delay=DEFAULT_TYPE_DELAY) await poll_value.until_equals("2") diff --git a/tests/tooling/__init__.py b/tests/tooling/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/py/reactpy/tests/tooling/aio.py b/tests/tooling/aio.py similarity index 69% rename from src/py/reactpy/tests/tooling/aio.py rename to tests/tooling/aio.py index b0f719400..7fe8f03b2 100644 --- a/src/py/reactpy/tests/tooling/aio.py +++ b/tests/tooling/aio.py @@ -3,7 +3,7 @@ from asyncio import Event as _Event from asyncio import wait_for -from reactpy.config import REACTPY_TESTING_DEFAULT_TIMEOUT +from reactpy.config import REACTPY_TESTS_DEFAULT_TIMEOUT class Event(_Event): @@ -12,5 +12,5 @@ class Event(_Event): async def wait(self, timeout: float | None = None): return await wait_for( super().wait(), - timeout=timeout or REACTPY_TESTING_DEFAULT_TIMEOUT.current, + timeout=timeout or REACTPY_TESTS_DEFAULT_TIMEOUT.current, ) diff --git a/src/py/reactpy/tests/tooling/common.py b/tests/tooling/common.py similarity index 62% rename from src/py/reactpy/tests/tooling/common.py rename to tests/tooling/common.py index c0191bd4e..75495db0c 100644 --- a/src/py/reactpy/tests/tooling/common.py +++ b/tests/tooling/common.py @@ -1,9 +1,9 @@ from typing import Any -from reactpy.core.types import LayoutEventMessage, LayoutUpdateMessage +from reactpy.testing.common import GITHUB_ACTIONS +from reactpy.types import LayoutEventMessage, LayoutUpdateMessage -# see: https://github.com/microsoft/playwright-python/issues/1614 -DEFAULT_TYPE_DELAY = 100 # milliseconds +DEFAULT_TYPE_DELAY = 250 if GITHUB_ACTIONS else 50 def event_message(target: str, *data: Any) -> LayoutEventMessage: diff --git a/src/py/reactpy/tests/tooling/hooks.py b/tests/tooling/hooks.py similarity index 73% rename from src/py/reactpy/tests/tooling/hooks.py rename to tests/tooling/hooks.py index 1926a93bc..37035215a 100644 --- a/src/py/reactpy/tests/tooling/hooks.py +++ b/tests/tooling/hooks.py @@ -1,8 +1,8 @@ -from reactpy.core.hooks import current_hook, use_state +from reactpy.core.hooks import HOOK_STACK, use_state def use_force_render(): - return current_hook().schedule_render + return HOOK_STACK.current_hook().schedule_render def use_toggle(init=False): diff --git a/src/py/reactpy/tests/tooling/layout.py b/tests/tooling/layout.py similarity index 97% rename from src/py/reactpy/tests/tooling/layout.py rename to tests/tooling/layout.py index fe78684fe..034770bf6 100644 --- a/src/py/reactpy/tests/tooling/layout.py +++ b/tests/tooling/layout.py @@ -8,7 +8,7 @@ from jsonpointer import set_pointer from reactpy.core.layout import Layout -from reactpy.core.types import VdomJson +from reactpy.types import VdomJson from tests.tooling.common import event_message logger = logging.getLogger(__name__) diff --git a/src/py/reactpy/tests/tooling/select.py b/tests/tooling/select.py similarity index 95% rename from src/py/reactpy/tests/tooling/select.py rename to tests/tooling/select.py index cf7a9c004..7e93f7c4b 100644 --- a/src/py/reactpy/tests/tooling/select.py +++ b/tests/tooling/select.py @@ -1,10 +1,9 @@ from __future__ import annotations -from collections.abc import Iterator, Sequence +from collections.abc import Callable, Iterator, Sequence from dataclasses import dataclass -from typing import Callable -from reactpy.core.types import VdomJson +from reactpy.types import VdomJson Selector = Callable[[VdomJson, "ElementInfo"], bool]