diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d5bf9b2d..3d816e97 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,5 +11,5 @@ - [ ] All tests pass locally -- [ ] I have updated `docs/changelog.md` +- [ ] I have updated `CHANGELOG.md` - [ ] I have created documentation for this(if applicable) diff --git a/.github/workflows/build-unstable.yml b/.github/workflows/build-unstable.yml deleted file mode 100644 index 73b0ba35..00000000 --- a/.github/workflows/build-unstable.yml +++ /dev/null @@ -1,142 +0,0 @@ -name: "[CI] Build Unstable" - -on: - push: # Only run on merges into main that modify files under pyscriptjs/ and examples/ - branches: - - main - paths: - - pyscriptjs/** - - examples/** - - .github/workflows/build-unstable.yml # Test that workflow works when changed - - pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/ - branches: - - main - paths: - - pyscriptjs/** - - examples/** - - .github/workflows/build-unstable.yml # Test that workflow works when changed - workflow_dispatch: - -jobs: - BuildAndTest: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscriptjs - env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - - name: Cache node modules - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 - - - name: Setup Environment - run: make setup - - - name: Build - run: make build - - - name: TypeScript Tests - run: make test-ts - - - name: Python Tests - run: make test-py - - - name: Integration Tests - run: make test-integration-parallel - - - name: Examples Tests - run: make test-examples - - - uses: actions/upload-artifact@v3 - with: - name: pyscript - path: | - pyscriptjs/build/ - if-no-files-found: error - retention-days: 7 - - - uses: actions/upload-artifact@v3 - if: success() || failure() - with: - name: test_results - path: pyscriptjs/test_results - if-no-files-found: error - eslint: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscriptjs - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - - name: Cache node modules - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - name: npm install - run: npm install - - - name: Eslint - run: npx eslint src -c .eslintrc.js - - Deploy: - runs-on: ubuntu-latest - needs: BuildAndTest - if: github.ref == 'refs/heads/main' # Only deploy on merge into main - permissions: - contents: read - id-token: write - - steps: - - uses: actions/download-artifact@v3 - with: - name: pyscript - path: ./build/ - - # Deploy to S3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - - name: Sync to S3 - run: aws s3 sync --quiet ./build/ s3://pyscript.net/unstable/ diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml deleted file mode 100644 index 2978d7a9..00000000 --- a/.github/workflows/docs-release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: "[Docs] Build Release" - -on: - release: - types: [published] - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-${{ github.ref_name }} - path: docs/_build/html/ - - # Deploy to S3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - - name: Copy redirect file - run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html - - - name: Sync to S3 - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/ - - # Make sure to remove the latest folder so we sync the full docs upon release - - name: Delete latest directory - run: aws s3 rm --recursive s3://docs.pyscript.net/latest/ - - # Note that the files are the same as above, but we want to have folders with - # // AND /latest/ which latest will always point to the latest release - - name: Sync to /latest - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/ diff --git a/.github/workflows/docs-review.yml b/.github/workflows/docs-review.yml deleted file mode 100644 index 37ba5b13..00000000 --- a/.github/workflows/docs-review.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: "[Docs] Build Review" - -on: - pull_request: - branches: - - "*" - paths: - - docs/** - -concurrency: - # Concurrency group that uses the workflow name and PR number if available - # or commit SHA as a fallback. If a new build is triggered under that - # concurrency group while a previous build is running it will be canceled. - # Repeated pushes to a PR will cancel all previous builds, while multiple - # merges to main will not cancel. - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} - cancel-in-progress: true - -jobs: - build: - if: github.repository_owner == 'pyscript' - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-review-${{ github.event.number }} - path: docs/_build/html/ diff --git a/.github/workflows/docs-unstable.yml b/.github/workflows/docs-unstable.yml deleted file mode 100644 index 0d093db5..00000000 --- a/.github/workflows/docs-unstable.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: "[Docs] Build Latest" - -on: - push: - branches: - - main - paths: - - docs/** - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-latest - path: docs/_build/html/ - - # Deploy to S3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - # Sync will only copy changed files - - name: Sync Error - run: aws s3 cp --quiet ./docs/_static/s3_error.html s3://docs.pyscript.net/error.html - - # Sync will only copy changed files - - name: Sync to S3 - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/ diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 944eeef1..6bbb666f 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -1,24 +1,20 @@ -name: "[CI] Prepare Release" +name: "Prepare Release" on: push: tags: - "[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+" # YYYY.MM.MICRO -env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 - defaults: run: - working-directory: pyscriptjs + working-directory: ./pyscript.core jobs: - build: + prepare-release: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -38,17 +34,18 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 + - name: NPM Install + run: npm install && npx playwright install - - name: Setup Environment - run: make setup + - name: Build + run: npm run build - - name: Build and Test - run: make test + - name: Generate index.html + working-directory: . + run: sed 's#_PATH_#./#' ./public/index.html > ./pyscript.core/dist/index.html - - name: Zip build folder - run: zip -r -q ./build.zip ./build + - name: Zip dist folder + run: zip -r -q ./build.zip ./dist - name: Prepare Release uses: softprops/action-gh-release@v1 diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 304fc759..36828477 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -1,26 +1,22 @@ -name: "[CI] Publish Release" +name: "Publish Release" on: release: types: [published] -env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 - defaults: run: - working-directory: pyscriptjs + working-directory: ./pyscript.core jobs: - build: + publish-release: runs-on: ubuntu-latest permissions: - contents: read id-token: write + contents: read steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -40,18 +36,18 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 + - name: npm install + run: npm install && npx playwright install - - name: Setup Environment - run: make setup + - name: build + run: npm run build - - name: Build and Test - run: make test + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/releases/${{ github.ref_name }}/#' ./public/index.html > ./pyscript.core/dist/index.html - # Upload to S3 - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} @@ -59,5 +55,5 @@ jobs: - name: Sync to S3 run: | # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/ - aws s3 sync --quiet ./build/ s3://pyscript.net/latest/ - aws s3 sync --quiet ./build/ s3://pyscript.net/releases/${{ github.ref_name }}/ + aws s3 sync --quiet ./dist/ s3://pyscript.net/latest/ + aws s3 sync --quiet ./dist/ s3://pyscript.net/releases/${{ github.ref_name }}/ diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index e2ef5c98..944a26f3 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -1,5 +1,4 @@ -name: "[CI] Publish Snapshot" -# Copy /unstable/ to /snapshots/2022.09.1.RC1/ +name: "Publish Snapshot" on: workflow_dispatch: @@ -9,18 +8,54 @@ on: type: string required: true +defaults: + run: + working-directory: ./pyscript.core + jobs: - snapshot: + publish-snapshot: runs-on: ubuntu-latest permissions: contents: read id-token: write steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Install Dependencies + run: npm install && npx playwright install + + - name: Build Pyscript.core + run: npm run build + - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - name: Sync to S3 + + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html + + - name: Copy to Snapshot run: > - aws s3 sync s3://pyscript.net/unstable/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ + aws s3 sync ./dist/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml new file mode 100644 index 00000000..f2a1df45 --- /dev/null +++ b/.github/workflows/publish-unstable.yml @@ -0,0 +1,61 @@ +name: "Publish Unstable" + +on: + push: # Only run on merges into main that modify files under pyscript.core/ and examples/ + branches: + - main + paths: + - pyscript.core/** + - examples/** + + workflow_dispatch: + +jobs: + publish-unstable: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + defaults: + run: + working-directory: ./pyscript.core + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: NPM Install + run: npm install && npx playwright install + + - name: Build + run: npm run build + + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ secrets.AWS_REGION }} + role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} + + - name: Sync to S3 + run: aws s3 sync --quiet ./dist/ s3://pyscript.net/unstable/ diff --git a/.github/workflows/sync-examples.yml b/.github/workflows/sync-examples.yml deleted file mode 100644 index d8ed32b8..00000000 --- a/.github/workflows/sync-examples.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "[CI] Sync Examples" - -on: - release: - types: [published] - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - defaults: - run: - working-directory: examples - - steps: - # Deploy to S3 - - name: Checkout - uses: actions/checkout@v3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - name: - Sync to S3 - # Sync outdated or new files, delete ones no longer in source - run: aws s3 sync --quiet --delete . s3://pyscript.net/examples/ # Sync directory, delete what is not in source diff --git a/.github/workflows/test-next.yml b/.github/workflows/test-next.yml deleted file mode 100644 index 3764459f..00000000 --- a/.github/workflows/test-next.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: "[CI] Test Next" - -on: - push: # Only run on merges into main that modify files under pyscriptjs/ and examples/ - branches: - - next - paths: - - pyscript.core/** - - .github/workflows/test-next.yml # Test that workflow works when changed - - pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/ - branches: - - next - paths: - - pyscript.core/** - - .github/workflows/test-next.yml # Test that workflow works when changed - workflow_dispatch: - -jobs: - TestNext: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscript.core - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install node - uses: actions/setup-node@v3 - with: - node-version: 20.x - - - name: Cache node modules - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - # TODO: this will likely change soon to pyscript.next - # - name: install next deps - # working-directory: pyscript.core - # run: npm i; npx playwright install - - # - name: build next - # working-directory: pyscript.core - # run: npm run build - - # - name: Run next tests - # working-directory: pyscript.core - # run: npm run test - - # TODO: DO we want to upload next yet? - # - uses: actions/upload-artifact@v3 - # with: - # name: pyscript - # path: | - # pyscriptjs/build/ - # if-no-files-found: error - # retention-days: 7 - - # - uses: actions/upload-artifact@v3 - # if: success() || failure() - # with: - # name: test_results - # path: pyscriptjs/test_results - # if-no-files-found: error diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..f7b83be7 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,92 @@ +name: "[CI] Test" + +on: + push: # Only run on merges into main that modify certain files + branches: + - main + paths: + - pyscript.core/** + - .github/workflows/test.yml + + pull_request: # Only run on merges into main that modify certain files + branches: + - main + paths: + - pyscript.core/** + - .github/workflows/test.yml + workflow_dispatch: + +jobs: + BuildAndTest: + runs-on: ubuntu-latest-8core + env: + MINICONDA_PYTHON_VERSION: py38 + MINICONDA_VERSION: 4.11.0 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 3 + + # display a git log: when you run CI on PRs, github automatically + # merges the PR into main and run the CI on that commit. The idea + # here is to show enough of git log to understand what is the + # actual commit (in the PR) that we are using. See also + # 'fetch-depth: 3' above. + - name: git log + run: git log --graph -3 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 20.x + + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: setup Miniconda + uses: conda-incubator/setup-miniconda@v2 + + - name: Create and activate virtual environment + run: | + python3 -m venv test_venv + source test_venv/bin/activate + echo PATH=$PATH >> $GITHUB_ENV + echo VIRTUAL_ENV=$VIRTUAL_ENV >> $GITHUB_ENV + + - name: Setup dependencies in virtual environment + run: | + make setup + + - name: Build + run: make build + + - name: Integration Tests + #run: make test-integration-parallel + run: | + make test-integration + + - uses: actions/upload-artifact@v3 + with: + name: pyscript + path: | + pyscript.core/dist/ + if-no-files-found: error + retention-days: 7 + + - uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: test_results + path: test_results/ + if-no-files-found: error diff --git a/.github/workflows/test_report.yml b/.github/workflows/test_report.yml index dacbc8e7..6debdbdc 100644 --- a/.github/workflows/test_report.yml +++ b/.github/workflows/test_report.yml @@ -1,12 +1,12 @@ name: Test Report on: workflow_run: - workflows: ['\[CI\] Build Unstable'] + workflows: ['\[CI\] Test'] types: - completed jobs: report: - runs-on: ubuntu-latest + runs-on: ubuntu-latest-8core steps: - uses: dorny/test-reporter@v1.6.0 with: diff --git a/.gitignore b/.gitignore index cc7325e3..d19ac9a9 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,6 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ -pyscriptjs/examples # Translations *.mo @@ -141,3 +140,12 @@ coverage/ # junit xml for test results test_results + +# @pyscript/core npm artifacts +pyscript.core/core.* +pyscript.core/dist +pyscript.core/dist.zip +pyscript.core/src/plugins.js +pyscript.core/src/stdlib/pyscript.js +pyscript.core/src/3rd-party/* +!pyscript.core/src/3rd-party/READMEmd diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 730d1f5b..cd2d4d04 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ # This is the configuration for pre-commit, a local framework for managing pre-commit hooks # Check out the docs at: https://pre-commit.com/ ci: - skip: [eslint] + #skip: [eslint] autoupdate_schedule: monthly default_stages: [commit] @@ -16,24 +16,19 @@ repos: - id: check-json exclude: tsconfig\.json - id: check-toml + exclude: bad\.toml - id: check-xml - id: check-yaml - id: detect-private-key - id: end-of-file-fixer - exclude: pyscript\.core/core.*|\.min\.js$ + exclude: pyscript\.core/dist|\.min\.js$ - id: trailing-whitespace - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.257 - hooks: - - id: ruff - exclude: pyscript\.core/test|pyscript\.core/src/display.py - args: [--fix] - - repo: https://github.com/psf/black rev: 23.1.0 hooks: - id: black + exclude: pyscript\.core/src/stdlib/pyscript/__init__\.py - repo: https://github.com/codespell-project/codespell rev: v2.2.4 @@ -47,17 +42,12 @@ repos: rev: "v3.0.0-alpha.6" hooks: - id: prettier - exclude: pyscript\.core/test|pyscript\.core/core.*|pyscript\.core/types/|pyscript\.sw/ + exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/|pyscript.core/src/3rd-party args: [--tab-width, "4"] - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.36.0 + - repo: https://github.com/pycqa/isort + rev: 5.12.0 hooks: - - id: eslint - files: pyscriptjs/src/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx - types: [file] - additional_dependencies: - - eslint@8.25.0 - - typescript@5.0.4 - - "@typescript-eslint/eslint-plugin@5.58.0" - - "@typescript-eslint/parser@5.58.0" + - id: isort + name: isort (python) + args: [--profile, black] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c536d8c4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,87 @@ +# Release Notes + +## 2023.05.01 + +### Features + +- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal. +- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes. +- Added the `@when` decorator for attaching Python functions as event handlers +- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release. + +#### Runtime py- attributes + +- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435)) + +#### <script type="py"> + +- Added the ability to optionally use ` + + ``` @@ -36,7 +42,7 @@ Check out the [the examples directory](examples) folder for more examples on how Read the [contributing guide](CONTRIBUTING.md) to learn about our development process, reporting bugs and improvements, creating issues and asking questions. -Check out the [developing process](https://docs.pyscript.net/latest/development/developing.html) documentation for more information on how to setup your development environment. +Check out the [developing process](https://docs.pyscript.net/latest/contributing) documentation for more information on how to setup your development environment. ## Resources diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index af47bc08..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build -CONDA_ENV ?= _env - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -env := $(CONDA_ENV) -conda_run := conda run -p $(env) - -setup: - @if [ -z "$${CONDA_SHLVL:+x}" ]; then echo "Conda is not installed." && exit 1; fi - $(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml - -clean: - rm -rf $(BUILDDIR) - -clean-all: clean - rm -rf $(env) *.egg-info - -shell: - @export CONDA_ENV_PROMPT='<{name}>' - @echo 'conda activate $(env)' - -htmlserve: html - @echo 'visit docs at http://localhost:8080' - python -m http.server -d "$(BUILDDIR)/html/" 8080 - -livehtml: - sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - - -.PHONY: help Makefile setup clean clean-all shell - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 59dd0d2a..00000000 --- a/docs/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# PyScript documentation - -Welcome to the PyScript documentation directory, where you can find -and contribute to discussions around PyScript and related topics. - -## Getting started - -Before you start contributing to the documentation, it's worthwhile to -take a look at the general contributing guidelines for the PyScript project. You can find these guidelines here -[Contributing Guidelines](https://github.com/pyscript/pyscript/blob/main/CONTRIBUTING.md) - -## Documentation Principles - -The PyScript documentation is based on a documentation framework called [Diátaxis](https://diataxis.fr/). This framework helps to solve the problem of structure in technical documentation and identifies four modes of documentation - **tutorials, how-to guides, technical reference and explanation**. Each one of these modes answers to a different user need, fulfills a different purpose and requires a different approach to its creation. - -The picture below gives a good visual representation of that separation of concerns: - -![pyodide-pyscript](./img/diataxis.png) - -So, please keep that in mind when contributing to the project documentation. For more information on, make sure to check [their website](https://diataxis.fr/). - -### Setup - -The `docs` directory in the pyscript repository contains a -[Sphinx](https://www.sphinx-doc.org/) documentation project. Sphinx is a system -that takes plaintext files containing documentation written in Markdown, along with -static files like templates and themes, to build the static end result. - -### Build - -To learn how to build the docs, head over the [CONTRIBUTING](../CONTRIBUTING.md) page. - - -## Cross-referencing - -You can link to other pages in the documentation by using the `{doc}` role. For example, to link to the `docs/README.md` file, you would use: - -```markdown -{doc}`docs/README.md` -``` - -You can also cross-reference the python glossary by using the `{term}` role. For example, to link to the `iterable` term, you would use: - -```markdown -{term}`iterable` -``` - -You can also cross-reference functions, methods or data attributes by using the `{attr}` for example: - -```markdown -{py:func}`repr` -``` - -This would link to the `repr` function in the python builtins. diff --git a/docs/_static/examples/what-is-pyscript.html b/docs/_static/examples/what-is-pyscript.html deleted file mode 100644 index ee639cf6..00000000 --- a/docs/_static/examples/what-is-pyscript.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - -

Let's plot random numbers

-
-
-

❰py❱

-
-
- - - packages = [ - "numpy", - "matplotlib" - ] - - - -import matplotlib.pyplot as plt -import numpy as np - -x = np.random.randn(1000) -y = np.random.randn(1000) - -fig, ax = plt.subplots() -ax.scatter(x, y) -pyscript.write('plot', fig) - - - diff --git a/docs/_static/fonts/Hack-Bold.woff b/docs/_static/fonts/Hack-Bold.woff deleted file mode 100644 index 35feb8f8..00000000 Binary files a/docs/_static/fonts/Hack-Bold.woff and /dev/null differ diff --git a/docs/_static/fonts/Hack-BoldItalic.woff b/docs/_static/fonts/Hack-BoldItalic.woff deleted file mode 100644 index 30e7b66c..00000000 Binary files a/docs/_static/fonts/Hack-BoldItalic.woff and /dev/null differ diff --git a/docs/_static/fonts/Hack-Italic.woff b/docs/_static/fonts/Hack-Italic.woff deleted file mode 100644 index 037a0b3e..00000000 Binary files a/docs/_static/fonts/Hack-Italic.woff and /dev/null differ diff --git a/docs/_static/fonts/Hack-Regular.woff b/docs/_static/fonts/Hack-Regular.woff deleted file mode 100644 index 05ea5cf9..00000000 Binary files a/docs/_static/fonts/Hack-Regular.woff and /dev/null differ diff --git a/docs/_static/images/pyscript.svg b/docs/_static/images/pyscript.svg deleted file mode 100644 index 8d32dcac..00000000 --- a/docs/_static/images/pyscript.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/docs/_static/redirect.html b/docs/_static/redirect.html deleted file mode 100644 index 3c3a36bc..00000000 --- a/docs/_static/redirect.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/_static/s3_error.html b/docs/_static/s3_error.html deleted file mode 100644 index a3b97055..00000000 --- a/docs/_static/s3_error.html +++ /dev/null @@ -1,4 +0,0 @@ - -

404 - File not found

-

You will be redirected to the latest documentation in 5 seconds.

- diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index efc26b67..00000000 --- a/docs/changelog.md +++ /dev/null @@ -1,94 +0,0 @@ -# Release Notes - -2023.XX.X -========= - - -Features --------- - -- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal. -- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes. -- Added the `@when` decorator for attaching Python functions as event handlers -- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release. - - -### Runtime py- attributes - -- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435)) - -### <script type="py"> -- Added the ability to optionally use ` - - - - - plugins = ["./hello-world.py"] - - - -``` - -Now we need to start a live server to serve our page. You can use Python's `http.server` module for this. - -```bash -python -m http.server -``` - -Now you can open your browser and go to `http://localhost:8000` to see the page. You might be surprised that the text "Hello World" is not on the page. This is because we need to do a few more things to make our plugin work. - -First, we must create a custom element that our plugin will use. We can use a decorator in our `PyHelloWorld` class. - -```python -from pyscript import Plugin, js - -plugin = Plugin("PyHelloWorld") - -@plugin.register_custom_element("py-hello-world") -class PyHelloWorld: - def __init__(self, element): - self.element = element - - def connect(self): - self.element.innerHTML = "
Hello World!
" -``` - -Now that we have registered our custom element, we can use the custom tag `` to add our plugin to the page. - -```html - - - - - - - Python Plugin - - - - - - - - plugins = ["./hello-world.py"] - - - - - -``` - -Now, if you go to `http://localhost:8000` you should see the text "Hello World" on the page. - -Writing plugins in Python is an excellent way if you want to use PyScript's API's. However, if you want to write plugins in Javascript, you can do that too. - -## Javascript plugins - -Javascript plugins need to have a specific structure to be loaded by PyScript. The plugin export a default class with the following method, which may implement any, all, or none of the [Plugin lifecycle methods](https://github.com/pyscript/pyscript/blob/main/pyscriptjs/src/plugin.ts#L9-L65). These method will be called at the corresponding points in lifecycle of PyScript as it loads, configures itself and its Python interpreter, and executes `` and `` tags. - -```{note} -You need to specify the file extension `.js` when adding your custom plugin to the `` tag. -``` - -### Creating a Hello World plugin - -Let's create a simple plugin that will add the text "Hello World" to the page. We will create a `hello-world.js` file and write the plugin class. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - // Code goes here - } -} -``` - -Now we need to add the code that will add the text to the page. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - const elem = document.createElement("h1"); - elem.innerText = "Hello World"; - document.body.appendChild(elem); - } -} -``` - -Finally, we need to add the plugin to our page's `` tag. - -```html - - - - - - - Javascript Plugin - - - - - - - - plugins = ["./hello-world.js"] - - - -``` - -Now we need to start a live server to serve our page. You can use Python's `http.server` module for this. - -```bash -python -m http.server -``` - -Now you can open your browser and go to `http://localhost:8000` to see the page. You should see the text "Hello World" on the page. - -```{note} -Because we are using a local file, you must start a live server. Otherwise, Pyscript will not be able to fetch the file. -``` - -### Expanding the Hello World plugin - -As you can see, we could build all our plugin logic inside the `afterStartup` method. You may also want to create a custom html element for your plugin. Let's see how we can do that. - -First, we need to create a custom html element. Let's start by creating our `PyHelloWorld` class that extends the `HTMLElement` class. - - -```js -class PyHelloWorld extends HTMLElement { - constructor() { - super(); - } - - connectedCallback() { - this.innerHTML = `

Hello, world!

`; - this.mount_name = this.id; - } -} -``` - -We can now register our custom element in the `afterStartup` method of our `HelloWorldPlugin` class. We will also add the custom tag `py-hello-world` to the page. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - // Create a custom element called - customElements.define("py-hello-world", PyHelloWorld); - - // Add the custom element to the page so we can see it - const elem = document.createElement('py-hello-world'); - document.body.append(elem); - } -} -``` - -Now we can open our page and see the custom element on the page. - -By now, you should have a good idea for creating a custom plugin. Also, how powerful it can be to create custom elements that other users could use in their PyScript pages. diff --git a/docs/guides/event-handlers.md b/docs/guides/event-handlers.md deleted file mode 100644 index 7546ccc4..00000000 --- a/docs/guides/event-handlers.md +++ /dev/null @@ -1,179 +0,0 @@ -# Event handlers in PyScript - -PyScript offer two ways to subscribe to Javascript event handlers: - -## Subscribe to event with `py-*` attributes - -The value of the attribute contains python code which will be executed when the event is fired. A very common pattern is to call a function which does further work, for example: - -```html - - -``` - -```python - - def say_hello_no_param(): - print("Hello!") - - def say_hello_with_param(name): - print("Hello " + name + "!") - -``` - -Note that py-\* attributes need a _function call_ - -Supported py-\* attributes can be seen in the [PyScript API reference](<[../api-reference.md](https://github.com/pyscript/pyscript/blob/66b57bf812dcc472ed6ffee075ace5ced89bbc7c/pyscriptjs/src/components/pyscript.ts#L119-L260)>). - -## Subscribe to event with `addEventListener` - -You can also subscribe to an event using the `addEventListener` method of the DOM element. This is useful if you want to pass event object to the event handler. - -```html - -``` - -```python - - from js import console, document - from pyodide.ffi.wrappers import add_event_listener - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - add_event_listener(document.getElementById("two"), "click", hello_args) - -``` - -or using the `addEventListener` method of the DOM element: - -```html - -``` - -```python - - from js import console, document - from pyodide.ffi import create_proxy - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - document.getElementById("three").addEventListener("click", create_proxy(hello_args)) - -``` - -or using the PyScript Element class: - -```html - -``` - -```python - - from js import console - from pyodide.ffi import create_proxy - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - Element("four").element.addEventListener("click", create_proxy(hello_args)) - -``` - -## JavaScript to PyScript and From PyScript to JavaScript - -If you're wondering about how to pass objects from JavaScript to PyScript and/or the other way around head over to the [Passing Objects](passing-objects.md) page. - - -### Exporting all Global Python Objects - -We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: - -```python - - from js import createObject - from pyodide.ffi import create_proxy - createObject(create_proxy(globals()), "pyodideGlobals") - -``` - -This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. - -(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a ` -``` - -### Exporting Individual Python Objects - -We can also export individual Python objects to the JavaScript global scope if we wish. - -(As above, the following example uses a button to delay the execution of the ` -``` diff --git a/docs/guides/http-requests.md b/docs/guides/http-requests.md deleted file mode 100644 index bdcd0564..00000000 --- a/docs/guides/http-requests.md +++ /dev/null @@ -1,224 +0,0 @@ -# How to make HTTP requests using `PyScript`, in pure Python - -[Pyodide](https://pyodide.org), the interpreter that underlies `PyScript`, does not have the `requests` module -(or other similar modules) available by default, which are traditionally used to make HTTP requests in Python. -However, it is possible to make HTTP requests in Pyodide using the modern `JavaScript` `fetch` API -([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch)). This example shows how to make common HTTP request -(GET, POST, PUT, DELETE) to an API, using only Python code! We will use asynchronous functions with -async/await syntax, as concurrent code is preferred for HTTP requests. - -The purpose of this guide is not to teach the basics of HTTP requests, but to show how to make them -from `PyScript` using Python, since currently, the common tools such as `requests` and `httpx` are not available. - -## Fetch - -The `fetch` API is a modern way to make HTTP requests. It is available in all modern browsers, and in Pyodide. - -Although there are two ways to use `fetch`: -1) using `JavaScript` from `PyScript` -2) using Pyodide's Python wrapper, -`pyodide.http.pyfetch` - -This example will only show how to use the Python wrapper. Still, the -[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) is a useful reference, as its -parameters can be called from Python using the `pyfetch` wrapper. - -## Pyodide.http, pyfetch, and FetchResponse - -The [pyodide.http module](https://pyodide.org/en/stable/usage/api/python-api/http.html#module-pyodide.http) is a Python API -for dealing with HTTP requests. It provides the `pyfetch` function as a wrapper for the `fetch` API, -which returns a `FetchResponse` object whenever a request is made. Extra keyword arguments can be passed to `pyfetch` -which will be passed to the `fetch` API. - -The returned object `FetchResponse` has familiar methods and properties -for dealing with the response, such as `json()` or `status`. See the -[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse) -for more information. - -## Example - -We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`. -First we write a helper function in pure Python that makes a request and returns the response. This function -makes it easier to make specific types of requests with the most common parameters. - -## Python convenience function - -```python -from pyodide.http import pyfetch, FetchResponse -from typing import Optional, Any - -async def request(url: str, method: str = "GET", body: Optional[str] = None, - headers: Optional[dict[str, str]] = None, **fetch_kwargs: Any) -> FetchResponse: - """ - Async request function. Pass in Method and make sure to await! - Parameters: - url: str = URL to make request to - method: str = {"GET", "POST", "PUT", "DELETE"} from `JavaScript` global fetch()) - body: str = body as json string. Example, body=json.dumps(my_dict) - headers: dict[str, str] = header as dict, will be converted to string... - Example, headers=json.dumps({"Content-Type": "application/json"}) - fetch_kwargs: Any = any other keyword arguments to pass to `pyfetch` (will be passed to `fetch`) - Return: - response: pyodide.http.FetchResponse = use with .status or await.json(), etc. - """ - kwargs = {"method": method, "mode": "cors"} # CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing - if body and method not in ["GET", "HEAD"]: - kwargs["body"] = body - if headers: - kwargs["headers"] = headers - kwargs.update(fetch_kwargs) - - response = await pyfetch(url, **kwargs) - return response -``` - -This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function, -so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools. -The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore, -the script containing this function must be importable by `PyScript`. - -For this example, we will name the file containing the Python code `request.py` and place it in the same directory as the file -containing the html code, which is described below. - -## `PyScript` HTML code - -In this How-to, the HTML code is split into separate code blocks to enable context highlighting (coloring of the Python -code inside the html code block), but in reality it is all in the same file. The first part is a bare bones `PyScript` -html page, using the [community examples](https://github.com/pyscript/pyscript-collective/) set-up. The second part is -the actual Python code for HTTP requests, which is wrapped in `` tags, while the third block has the -concluding html code. - -```html - - - - - - - GET, POST, PUT, DELETE example - - - - - - - [[fetch]] - files = ["/request.py"] - - - -

- Hello world request example!
- Here is the output of your request: -

- - import asyncio - import json - from request import request # import our request function. - - async def main(): - baseurl = "https://jsonplaceholder.typicode.com" - - # GET - headers = {"Content-type": "application/json"} - response = await request(f"{baseurl}/posts/2", method="GET", headers=headers) - print(f"GET request=> status:{response.status}, json:{await response.json()}") - - # POST - body = json.dumps({"title": "test_title", "body": "test body", "userId": 1}) - new_post = await request(f"{baseurl}/posts", body=body, method="POST", headers=headers) - print(f"POST request=> status:{new_post.status}, json:{await new_post.json()}") - - # PUT - body = json.dumps({"id": 1, "title": "test_title", "body": "test body", "userId": 2}) - new_post = await request(f"{baseurl}/posts/1", body=body, method="PUT", headers=headers) - print(f"PUT request=> status:{new_post.status}, json:{await new_post.json()}") - - # DELETE - new_post = await request(f"{baseurl}/posts/1", method="DELETE", headers=headers) - print(f"DELETE request=> status:{new_post.status}, json:{await new_post.json()}") - - asyncio.ensure_future(main()) - - -
-

- You can also use other methods. See fetch documentation:
- https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters -

-
-
-

- See pyodide documentation for what to do with a FetchResponse object:
- https://pyodide.org/en/stable/usage/api/python-api.html#pyodide.http.FetchResponse -

-
- - -``` - -## Explanation -### `py-config` tag for importing our Python code -The very first thing to notice is the `py-config` tag. This tag is used to import Python files into the `PyScript`. -In this case, we are importing the `request.py` file, which contains the `request` function we wrote above. - -### `py-script` tag for making async HTTP requests - -Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`, -which are required or helpful for the `request` function. -The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic -HTTP requests. The `await` keyword is required not only for the `request` function, but also for certain methods of the -`FetchResponse` object, such as `json()`, meaning that the code is asynchronous and slower requests will not block the -faster ones. - -### HTTP Requests - -HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from -a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the -local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also -through HTTP requests. - -In our example, we show how to pass in a request `body`, `headers`, and specify the request `method`, in order to make -`GET`, `POST`, `PUT`, and `DELETE` requests, although methods such as `PATCH` are also available. Additional -parameters for the `fetch` API are also available, which can be specified as keyword arguments passed to our helper -function or to `pyfetch`. See the -[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) for more information. -HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and -[RFC 9110](https://www.rfc-editor.org/info/rfc9110). - -## Conclusion - -This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python -code/files into the `PyScript` using the `py-config` tag is also covered. - -Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`, -or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing! - -## API Quick Reference - -## pyodide.http.pyfetch - -### pyfetch Usage - -```python -await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse -``` - -Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`. - -- [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch) - -## pyodide.http.FetchResponse - -### FetchResponse Usage - -```python -response: pyodide.http.FetchResponse = await -status = response.status -json = await response.json() -``` - -Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async) -methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc. - -- [`FetchResponse` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse) diff --git a/docs/guides/index.md b/docs/guides/index.md deleted file mode 100644 index b39f2341..00000000 --- a/docs/guides/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# Guides - -Welcome to the how-to documentation section for PyScript. If you've already -gained some experience with PyScript before and just need practical guides -to get your ideas realized, you can learn step by step how to use PyScript here. - -```{note} -Please head over to the [tutorials](../tutorials/index.md) section if you're only getting started. -``` - -```{toctree} ---- -maxdepth: 2 -glob: -caption: 'Contents:' ---- -passing-objects -http-requests -asyncio -custom-plugins -event-handlers -``` diff --git a/docs/guides/passing-objects.md b/docs/guides/passing-objects.md deleted file mode 100644 index f7ef966c..00000000 --- a/docs/guides/passing-objects.md +++ /dev/null @@ -1,295 +0,0 @@ -# How to Pass Objects from PyScript to Javascript (and Vice Versa) - -[Pyodide](https://pyodide.org), the interpreter that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other. - -This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html). - -For our purposes, an 'object' is anything that can be bound to a variable (a number, string, object, [function](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), etc). - -## JavaScript to PyScript - -We can use the syntax `from js import ...` to import JavaScript objects directly into PyScript. Simple JavaScript objects are converted to equivalent Python types; these are called [implicit conversions](https://pyodide.org/en/stable/usage/type-conversions.html#implicit-conversions). More complicated objects are wrapped in [JSProxy](https://pyodide.org/en/stable/usage/type-conversions.html) objects to make them behave like Python objects. - -`import js` and `from js import ...` [in Pyodide](https://pyodide.org/en/stable/usage/type-conversions.html#type-translations-using-js-obj-from-py) get objects from the [JavaScript globalThis scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis), so keep the[ rules of JavaScript variable scoping](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/) in mind. - -```html - -``` -```python - - # Import and use JS function and variable into Python - from js import name, addTwoNumbers - - print(f"Hello {name}") - print("Adding 1 and 2 in Javascript: " + str(addTwoNumbers(1, 2))) - -``` - -## PyScript to JavaScript - -### Using Pyodide's globals access - -The [PyScript JavaScript module](../reference/modules/pyscript.md) exposes its underlying Pyodide interpreter as `PyScript.interpreter`, and maintains a reference to the [globals()](https://docs.python.org/3/library/functions.html#globals) dictionary of the Python namespace. Thus, any global variables in python are accessible in JavaScript at `PyScript.interpreter.globals.get('my_variable_name')` - -```html - - x = 42 - - - - -``` - -Since [everything is an object](https://docs.python.org/3/reference/datamodel.html) in Python, this applies not only to user created variables, but also to classes, functions, built-ins, etc. If we want, we can even apply Python functions to JavaScript data and variables: - -```html - - - - - -``` - -### Using JavaScript's eval() - -There may be some situations where it isn't possible or ideal to use `PyScript.interpreter.globals.get()` to retrieve a variable from the Pyodide global dictionary. For example, some JavaScript frameworks may take a function/Callable as an html attribute in a context where code execution isn't allowed (i.e. `get()` fails). In these cases, you can create JavaScript proxies of Python objects more or less "manually" using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval). - -First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace. - -Include the following script tag anywhere in your html document: - -```html - -``` - -This function takes a Python Object and creates a variable pointing to it in the JavaScript global scope. - -### Exporting all Global Python Objects - -We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: - -```python - - from js import createObject - from pyodide.ffi import create_proxy - createObject(create_proxy(globals()), "pyodideGlobals") - -``` -This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. - -(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a ` -``` - -#### Full example - -```html - - - - - - - Exporting all Global Python Objects - - - - - - - - - - - from js import createObject - from pyodide.ffi import create_proxy - - createObject(create_proxy(globals()), "pyodideGlobals") - - # create some Python objects: - symbols = {'pi': 3.1415926, 'e': 2.7182818} - - def rough_exponential(x): - return symbols['e']**x - - class Circle(): - def __init__(self, radius): - self.radius = radius - - @property - def area(self): - return symbols['pi'] * self.radius**2 - - - - -``` - - -### Exporting Individual Python Objects - -We can also export individual Python objects to the JavaScript global scope if we wish. - -(As above, the following example uses a button to delay the execution of the ` -``` - -#### Full example - -```html - - - - - - - Exporting Individual Python Objects - - - - - - - - - - import js - from pyodide.ffi import create_proxy - - # Create 3 python objects - language = "Python 3" - animals = ['dog', 'cat', 'bird'] - multiply3 = lambda a, b, c: a * b * c - - # js object can be named the same as Python objects... - js.createObject(language, "language") - - # ...but don't have to be - js.createObject(create_proxy(animals), "animals_from_py") - - # functions are objects too, in both Python and Javascript - js.createObject(create_proxy(multiply3), "multiply") - - - - - - -``` diff --git a/docs/img/diataxis.png b/docs/img/diataxis.png deleted file mode 100644 index a9518ce5..00000000 Binary files a/docs/img/diataxis.png and /dev/null differ diff --git a/docs/img/pyodide-pyscript.png b/docs/img/pyodide-pyscript.png deleted file mode 100644 index 300d8a7c..00000000 Binary files a/docs/img/pyodide-pyscript.png and /dev/null differ diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 72aa2342..00000000 --- a/docs/index.md +++ /dev/null @@ -1,58 +0,0 @@ -# PyScript - -Welcome to the PyScript documentation! - -PyScript provides a way for you to run Python code directly in your browser, giving -anyone the ability to program without infrastructure barriers. Add an interactive -Python REPL directly to your website, share an interactive dashboard with a colleague -as an HTML file, or create a client-side Python-powered web application. This documentation -will show you how. - -::::{grid} 2 -:gutter: 3 - -:::{grid-item-card} [Tutorials](tutorials/index.md) - -Just getting started with PyScript? - -Check out our [getting started guide](tutorials/getting-started.md)! -::: -:::{grid-item-card} [Guides](guides/index.md) - -You already know the basics and want to learn specifics! - -[Passing Objects between JavaScript and Python](guides/passing-objects.md) - -[Making async HTTP requests in pure Python](guides/http-requests.md) - -[Async/Await and Asyncio](guides/asyncio.md) - -::: -:::{grid-item-card} [Concepts](concepts/index.md) - -[What is PyScript?](concepts/what-is-pyscript.md) - -::: -:::{grid-item-card} [Reference](reference/index.md) - -[Frequently asked questions](reference/faq.md) - -[The PyScript JS Module](reference/modules/pyscript.md) - -:::{toctree} -:maxdepth: 1 - -::: -:::: - -```{toctree} ---- -maxdepth: 1 -hidden: ---- -tutorials/index -guides/index -concepts/index -reference/index -changelog -``` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 32bb2452..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/reference/API/__version__.md b/docs/reference/API/__version__.md deleted file mode 100644 index aa649480..00000000 --- a/docs/reference/API/__version__.md +++ /dev/null @@ -1,8 +0,0 @@ -# `__version__` - -`PyScript.__version__` is a `str` representing the current version of PyScript in a human-readable form. For a structured version more suitable to comparisons, and for details of what each part of the version number represents, see [`version_info`](version_info.md) - -```shell ->>> pyscript.__version__ -'2023.02.1.dev' -``` diff --git a/docs/reference/API/attr_to_event.md b/docs/reference/API/attr_to_event.md deleted file mode 100644 index 194583e8..00000000 --- a/docs/reference/API/attr_to_event.md +++ /dev/null @@ -1,85 +0,0 @@ -# List of PyScript Attributes to Events: - -PyScript provides a convenient syntax for mapping JavaScript events to PyScript events, making it easy to connect events to HTML tags. - -For example, you can use the following code to connect the click event to a button: - -``` - -``` - -Here is a list of all the available event mappings: - -| PyScript Event Name | DOM Event Name | -|-------------------|----------------| -| py-afterprint | afterprint | -| py-beforeprint | beforeprint | -| py-beforeunload | beforeunload | -| py-error | error | -| py-hashchange | hashchange | -| py-load | load | -| py-message | message | -| py-offline | offline | -| py-online | online | -| py-pagehide | pagehide | -| py-pageshow | pageshow | -| py-popstate | popstate | -| py-resize | resize | -| py-storage | storage | -| py-unload | unload | -| py-blur | blur | -| py-change | change | -| py-contextmenu | contextmenu | -| py-focus | focus | -| py-input | input | -| py-invalid | invalid | -| py-reset | reset | -| py-search | search | -| py-select | select | -| py-submit | submit | -| py-keydown | keydown | -| py-keypress | keypress | -| py-keyup | keyup | -| py-click | click | -| py-dblclick | dblclick | -| py-mousedown | mousedown | -| py-mousemove | mousemove | -| py-mouseout | mouseout | -| py-mouseover | mouseover | -| py-mouseup | mouseup | -| py-mousewheel | mousewheel | -| py-wheel | wheel | -| py-drag | drag | -| py-dragend | dragend | -| py-dragenter | dragenter | -| py-dragleave | dragleave | -| py-dragover | dragover | -| py-dragstart | dragstart | -| py-drop | drop | -| py-scroll | scroll | -| py-copy | copy | -| py-cut | cut | -| py-paste | paste | -| py-abort | abort | -| py-canplay | canplay | -| py-canplaythrough | canplaythrough | -| py-cuechange | cuechange | -| py-durationchange | durationchange | -| py-emptied | emptied | -| py-ended | ended | -| py-loadeddata | loadeddata | -| py-loadedmetadata | loadedmetadata | -| py-loadstart | loadstart | -| py-pause | pause | -| py-play | play | -| py-playing | playing | -| py-progress | progress | -| py-ratechange | ratechange | -| py-seeked | seeked | -| py-seeking | seeking | -| py-stalled | stalled | -| py-suspend | suspend | -| py-timeupdate | timeupdate | -| py-volumechange | volumechange | -| py-waiting | waiting | -| py-toggle | toggle | diff --git a/docs/reference/API/display.md b/docs/reference/API/display.md deleted file mode 100644 index 1034559f..00000000 --- a/docs/reference/API/display.md +++ /dev/null @@ -1,87 +0,0 @@ -# `display(*values, target=None, append=True)` - -## Parameters - -`*values` - the objects to be displayed. String objects are output as-written. For non-string objects, the default content to display is the the object's {py:func}`repr`. Objects may implement the following methods to indicate that they should be displayed as a different MIME type. MIME types with a * indicate that the content will be wrapped in the appropriate html tags and attributes before output: - - -| Method | Inferred MIME type | -|---------------------|------------------------| -| `__repr__` | text/plain | -| `_repr_html_` | text/html | -| `_repr_svg_` | image/svg+xml | -| `_repr_png_` | image/png* | -| `_repr_pdf_` | application/pdf | -| `_repr_jpeg_` | image/jpeg* | -| `_repr_json_` | application/json | -| `_repr_javascript_` | application/javascript*| -| `savefig` | image/png | -| | | - -`target` - Element's ID. The default value for `target` is the current `py-script` tag ID, it's possible to specify different IDs for this parameter - -`append` - `boolean` if the output is going to be appended or not to the `target`ed element. It creates a `
` tag if `True` and a `` tag with a random ID if `False`. The default value for `append` is `True`. - -### Description - -Display is the default function to display objects on the screen. Functions like the Python `print()` or JavaScript `console.log()` are now defaulted to only appear on the terminal. - -Display will throw an exception if the target is not clear. E.g. the following code is invalid: - -```html - - def display_hello(): - # this fails because we don't have any implicit target - # from event handlers - display('hello') - - -``` - -Because it's considered unclear if the `hello` string should be displayed underneath the `` tag or the ` -``` - -#### Using matplotlib with display - -`matplotlib` has two ways of plotting things as mentioned [here](https://matplotlib.org/matplotblog/posts/pyplot-vs-object-oriented-interface/) - -- In case of using the `pyplot` interface, the graph can be shown using `display(plt)`. - -```python -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -t = np.arange(0.0, 2.0, 0.01) -s = 1 + np.sin(2 * np.pi * t) -plt.plot(t,s) - -display(plt) -``` - -- In case of using the `object oriented` interface, the graph can be shown using `display(fig)` or `display(plt)` both. - -```python -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -t = np.arange(0.0, 2.0, 0.01) -s = 1 + np.sin(2 * np.pi * t) - -fig, ax = plt.subplots() -ax.plot(t, s) - -display(fig) # but even display(plt) would have worked! -``` diff --git a/docs/reference/API/element.md b/docs/reference/API/element.md deleted file mode 100644 index 1d8e89e5..00000000 --- a/docs/reference/API/element.md +++ /dev/null @@ -1,309 +0,0 @@ -# `Element` - -The `Element` API is a helpful way to create and manipulate elements in the DOM. It is a wrapper around the native DOM API, and is designed to be as intuitive as possible. - -## Methods and Properties - -| Property | Description | -|----------|-----------------------------------------| -| `element` | Returns the element with the given ID. | -| `id` | Returns the element's ID. | -| `value` | Returns the element's value. | -| `innerHtml` | Returns the element's inner HTML. | - - - -| Method | Description | -|----------------------|--------------------------------------------------------------| -| `write` | Writes `value` to element and handles various mime types. `append` defaults to `False`, if set to true, it will create a child element. | -| `clear` | Clears the element's value or content. | -| `select` | Select element from `query` which uses [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). | -| `clone` | Clones the with `new_id` if provided and `to` element if provided. | -| `remove_class` | Removes one or more class name from the element. | -| `add_class` | Adds one or more class name to the element. | - -## Element.element - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -The `element` property returns the DOM element with the given ID. - -```html - from pyscript import Element - - my_div = Element('my-div') - print(my_div.element) -``` - -## Element.id - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's ID. - -```html - -
- - - from pyscript import Element - - my_div = Element('my-div') - print(my_div.id) # prints 'my-div' - -``` - -## Element.value - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's value. - -```html - - - - from pyscript import Element - - my_input = Element('my-input') - print(my_input.value) # prints 'hello world' - -``` - -## Element.innerHtml - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's inner HTML. - -```html -
- hello world -
- - - from pyscript import Element - - my_innerHtml = Element('my-innerHtml') - print(my_innerHtml.innerHtml) # prints hello world - -``` - -## Element.write - -| Parameter | Default | Type | -|-------------|---------|-----------------------------| -| `value` | | `str` or `__mime_type__` | -| `append` | False | `bool` | - -Writes `value` to element and handles various mime types. This method also contains a `append` parameter, which defaults to `False`. - -Currently, these are the MIME types that are supported when rendering content using this method - -| Method | Inferred MIME type | -|---------------------|------------------------| -| `__repr__` | text/plain | -| `_repr_html_` | text/html | -| `_repr_svg_` | image/svg+xml | -| `_repr_png_` | image/png* | -| `_repr_pdf_` | application/pdf | -| `_repr_jpeg_` | image/jpeg* | -| `_repr_json_` | application/json | -| `_repr_javascript_` | application/javascript*| -| `savefig` | image/png | - -```html -
- - - from pyscript import Element - el = Element("foo") - el.write("Hello!") - el.write("World!") # will replace the previous content - -``` - -If we set `append` to `True`, it will create a child element using a `div`. - -```html -
- - - from pyscript import Element - el = Element("foo") - el.write("Hello!", append=True) - - # This will create a child div with the id "foo-1" - el.write("World!", append=True) - -``` - -## Element.clear - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Clears the element's value or content. For example, we can clear the value of an input element. - -```html - - - - from pyscript import Element - el = Element("foo") - el.clear() # Removes value from input - -``` - -Or we can clear the content of a div element. - -```html -
Hello!
- - - from pyscript import Element - el = Element("foo") - el.clear() # Removes Hello from div content - -``` - -## Element.select - -Select element from `query`, it will look into the main Element if `from_content` is `True`. This method is a wrapper of [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). - -```html -
-
-
- - - from pyscript import Element - el = Element("foo") - bar = el.select("#bar") - print(bar.id) # prints 'bar' - -``` - -## Element.clone - -| Parameter | Default | Type | -|-------------|---------|-----------| -| `new_id` | None | `str` | -| `to` | None | `Element` | - -Clones the element to a new element. You can provide `new_id` to set a different id to the cloned element. You can also use a `to` element to append the cloned element to. - -```html -
- HI! -
- - - from pyscript import Element - - el = Element("foo") - # Creates two divs with the id "foo" and content "HI!" - el.clone() - -``` - -It's always a good idea to pass a new id to the element you are cloning to avoid confusion if you need to reference the element by id again. - -```html -
Hello!
- - - from pyscript import Element - el = Element("foo") - # Clones foo and its contents, but uses the id 'bar' - el.clone(new_id="bar") - -``` - -You can also clone an element into another element. - -```html -
- Bond -
-
- James -
- - from pyscript import Element - - bond_div = Element("bond") - james_div = Element("james") - - bond_div.clone(new_id="bond-2", to=james_div) - -``` - -## Element.remove_class - -| Parameter | Default | Type | -|-------------|---------|-----------------------| -| `classname` | None | `str` or `List[str]` | - -Removes one or more class names from the element. - -```html -
- - from pyscript import Element - - el = Element("foo") - el.remove_class("bar") - -``` - -You can also remove multiple classes by passing a list of strings. - -```html -
- - from pyscript import Element - - el = Element("foo") - el.remove_class(["bar", "baz"]) # Remove all classes from element - -``` - -## Element.add_class - -| Parameter | Default | Type | -|-------------|---------|-----------------------| -| `classname` | None | `str` or `List[str]` | - -Adds one or more class names to the element. - -```html - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class("red") - -``` - -You can also add multiple classes at once by passing a list of strings. - -```html - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class(["red", "bold"]) - -``` diff --git a/docs/reference/API/version_info.md b/docs/reference/API/version_info.md deleted file mode 100644 index dfba3c20..00000000 --- a/docs/reference/API/version_info.md +++ /dev/null @@ -1,16 +0,0 @@ -# `version_info` - -`PyScript.version_info` is a `namedtuple` representing the current version of PyScript. It can be used to compare whether current version precedes or follows a desired version. For a human-readable version of the same info, see [`__version__`](__version__.md) - -```sh ->>> pyscript.version_info -version_info(year=2023, month=2, minor=1, releaselevel='dev') -``` - -## Version Fields -| **parameter** | **CalVer equivalent field** | **example value** | **description** | -|-----------------|-----------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------| -| `year` | Full year (YYYY) | 2023 | The year of the release; when printed or represented as a string, always written with 4 digits | -| `month` | Short Month (MM) | 2 | The month of the release; when printed or represented as a string, written with 1 or 2 digits as necessary | -| `minor` | | 1 | The incremental number of the release for this month; when printed or represented as a string, written with 1 or two digits as necessary | -| `releaselevel` | | 'dev' | A string representing the qualifications of this build | diff --git a/docs/reference/API/when.md b/docs/reference/API/when.md deleted file mode 100644 index aaf4f761..00000000 --- a/docs/reference/API/when.md +++ /dev/null @@ -1,51 +0,0 @@ -# `@when` - -`@when(event_type:str = None, selector:str = None)` - -The `@when` decorator attaches the decorated function or Callable as an event handler for selected objects on the page. That is, when the named event is emitted by the selected DOM elements, the decorated Python function will be called. - -If the decorated function takes a single (non-self) argument, it will be passed the [Event object](https://developer.mozilla.org/en-US/docs/Web/API/Event) corresponding to the triggered event. If the function takes no (non-self) argument, it will be called with no arguments. - -## Parameters - -`event_type` - A string representing the event type to match against. This can be any of the [https://developer.mozilla.org/en-US/docs/Web/Events#event_listing](https://developer.mozilla.org/en-US/docs/Web/Events) that HTML elements may emit, as appropriate to their element type. - -`selector` = A string containing one or more [CSS selectors](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). The selected DOM elements will have the decorated function attacehed as an event handler. - -## Examples: - -The following example prints "Hello, world!" whenever the button is clicked. It demonstrates using the `@when` decorator on a Callable which takes no arguments: - -```html - - - from pyscript import when - @when("click", selector="#my_btn") - def say_hello(): - print(f"Hello, world!") - -``` - -The following example includes three buttons - when any of the buttons is clicked, that button turns green, and the remaining two buttons turn red. This demonstrates using the `@when` decorator on a Callable which takes one argument, which is then passed the Event object from the associated event. When combined with the ability to look at other elements in on the page, this is quite a powerful feature. - -```html -
- - - -
- - from pyscript import when - import js - - @when("click", selector="#container button") - def highlight(evt): - #Set the clicked button's background to green - evt.target.style.backgroundColor = 'green' - - #Set the background of all buttons to red - other_buttons = (button for button in js.document.querySelectorAll('button') if button != evt.target) - for button in other_buttons: - button.style.backgroundColor = 'red' - -``` diff --git a/docs/reference/elements/py-config.md b/docs/reference/elements/py-config.md deleted file mode 100644 index 3d1058a1..00000000 --- a/docs/reference/elements/py-config.md +++ /dev/null @@ -1,493 +0,0 @@ -# <py-config> - -Use the `` tag to set and configure general metadata along with declaring dependencies for your PyScript application. The configuration has to be set in either [TOML](https://toml.io/)(default) or [JSON](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON) format. - -If you are unfamiliar with TOML, consider [reading about it](https://learnxinyminutes.com/docs/toml/) or if you are unfamiliar with JSON, consider reading [freecodecamp's JSON for beginners](https://www.freecodecamp.org/news/what-is-json-a-json-file-example/) guide for more information. - -The `` element should be placed within the `` element. - -## Attributes - -| attribute | type | default | description | -|-----------|--------|---------|----------------------------------------------------------------------------------------------------------| -| **type** | string | "toml" | Syntax type of the ``. Value can be `json` or `toml`. Default: "toml" if type is unspecified. | -| **src** | url | | Source url to an external configuration file. | - -## Examples - -### Defining an inline config - -- `` using TOML (default) - -```{note} -Reminder: when using TOML, any Arrays of Tables defined with double-brackets (like `[[interpreters]]` and `[[fetch]]` must come after individual keys (like `plugins = ...` and `packages=...`) -``` - -```html - - [splashscreen] - autoclose = true - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js" - name = "pyodide-0.21.2" - lang = "python" - -``` - -- `` using JSON via `type` attribute - -```html - - { - "splashscreen": { - "autoclose": true - }, - "interpreters": [{ - "src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js", - "name": "pyodide-0.21.2", - "lang": "python" - }] - } - -``` - -### Defining a file based config - -- Use of the `src` attribute - -```html - -``` -where `custom.toml` contains - -```toml -[splashscreen] -autoclose = true - -[[interpreters]] -src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js" -name = "pyodide-0.21.2" -lang = "python" -``` - -- JSON using the `type` and `src` attribute - -```html - -``` -where `custom.json` contains - -```json -{ - "splashscreen": { - "autoclose": true, - }, - "interpreters": [{ - "src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js", - "name": "pyodide-0.21.2", - "lang": "python" - }] -} -``` - -### Mixing inline and file based configs - -One can also use both i.e pass the config from `src` attribute as well as specify it as `inline`. So the following snippet is also valid: - -```html - - [[fetch]] - files = ["./utils.py"] - -``` - -This can also be done via JSON using the `type` attribute. - -```html - - { - "fetch": [{ - "files": ["./utils.py"] - }] - } - -``` - -Note: While the `` tag supports both TOML and JSON, one cannot mix the type of config passed from 2 different sources i.e. the case when inline config is in TOML format while config from src is in JSON format is NOT allowed. Similarly for the opposite case. - ---- - -This is helpful in cases where a number of applications share a common configuration (which can be supplied via `src`), but their specific keys need to be customised and overridden. - -The keys supplied through `inline` override the values present in config supplied via `src`. - -## Dependencies and Packages - -One can also declare dependencies so as to get access to many 3rd party OSS packages that are supported by PyScript. -You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html). - -Package dependencies in the `` can be declared by using the direct link to the package URL (whl or any other format supported by the chosen interpreter) or by just providing the package name [and version]. If only the name [and version] are provided, packages will be installed directly from what's provided by your interpreter or from PyPI. - -NOTICE that only pure python packages from PyPI will work and packages with C dependencies will not. These need to be built specifically for WASM (please, consult the Pyodide project for more information about what's supported and on how to build packages with C dependencies) - -```html - - packages = ["./static/wheels/travertino-0.1.3-py3-none-any.whl"] - -``` - -OR in JSON like - -```html - - { - "packages": ["./static/wheels/travertino-0.1.3-py3-none-any.whl"] - } - -``` - -If your `.whl` is not a pure Python wheel, then open a PR or issue with [pyodide](https://github.com/pyodide/pyodide) to get it added [here](https://github.com/pyodide/pyodide/tree/main/packages). - -If there's enough popular demand, the pyodide team will likely work on supporting your package. Regardless, things will likely move faster if you make the PR and consult with the team to get unblocked. - -For example, NumPy and Matplotlib are available. Notice here we're using `display(fig, target="plot")`, which takes the graph and displays it in the element with the id `plot`. - - -```html - - - - - - - -

Let's plot random numbers

-
- - { - "packages": ["numpy", "matplotlib"] - } - - - import matplotlib.pyplot as plt - import numpy as np - x = np.random.randn(1000) - y = np.random.randn(1000) - fig, ax = plt.subplots() - ax.scatter(x, y) - display(fig, target="plot") - - - -``` - -## Local modules - -In addition to packages, you can declare local Python modules that will -be imported in the `` tag. For example, we can place the random -number generation steps in a function in the file `data.py`. - -```python -# data.py -import numpy as np -def make_x_and_y(n): - x = np.random.randn(n) - y = np.random.randn(n) - return x, y -``` - -In the HTML tag ``, paths to local modules are provided in the -`files` key within the `fetch` section. Refer to the [fetch](#fetch) section for -more details. - -```html - - - - - - - -

Let's plot random numbers

-
- - packages = ["numpy", "matplotlib"] - - [[fetch]] - files = ["./data.py"] - - - import matplotlib.pyplot as plt - from data import make_x_and_y - x, y = make_x_and_y(n=1000) - fig, ax = plt.subplots() - ax.scatter(x, y) - display(fig, target="plot") - - - -``` - -## Supported configuration values - -The following optional values are supported by ``: -| Value | Type | Description | -| ------ | ---- | ----------- | -| `name` | string | Name of the user application. This field can be any string and is to be used by the application author for their own customization purposes. | -| `description` | string | Description of the user application. This field can be any string and is to be used by the application author for their own customization purposes. | -| `version` | string | Version of the user application. This field can be any string and is to be used by the application author for their own customization purposes. It is not related to the PyScript version. | -| `schema_version` | number | The version of the config schema which determines what all keys are supported. This can be supplied by the user so PyScript knows what to expect in the config. If not supplied, the latest version for the schema is automatically used. | -| `type` | string | Type of the project. The default is an "app" i.e. a user application | -| `author_name` | string | Name of the author. | -| `author_email` | string | Email of the author. | -| `license` | string | License to be used for the user application. | -| `autoclose_loader` | boolean | If false, PyScript will not close the loading splash screen when the startup operations finish. | -| `packages` | List of Packages | Dependencies on 3rd party OSS packages are specified here. The default value is an empty list. | -| `fetch` | List of Stuff to fetch | Local Python modules OR resources from the internet are to be specified here using a Fetch Configuration, described below. The default value is an empty list. | -| `plugins` | List of Plugins | List of Plugins are to be specified here. The default value is an empty list. | -| `interpreters` | List of Interpreters| List of Interpreter configurations, described below. The default value contains a single Pyodide based interpreter. **Note:** Currently, only a single interpreter is supported. | -| `runtimes` {bdg-warning-line}`Deprecated` | List of Runtimes | This value is deprecated, please use `interpreters`. List of runtime configurations, described below. The default value contains a single Pyodide based interpreter. | - -### Fetch - -A fetch configuration consists of the following: - -| Value | Type | Description | -|--------------|-----------------|-------------------------------------------------| -| `from` | string | Base URL for the resource to be fetched. | -| `to_folder` | string | Name of the folder to create in the filesystem. | -| `to_file` | string | Name of the target to create in the filesystem. | -| `files` | List of strings | List of files to be downloaded. | - -The parameters `to_file` and `files` shouldn't be supplied together. - -#### Mechanism - -The `fetch` mechanism works in the following manner: - -- If both `files` and `to_file` parameters are supplied: Error! -- `from` defaults to an empty string i.e. `""` to denote relative URLs of the serving directory -- `to_folder` defaults to `.` i.e. the current working directory of the filesystem -- If `files` is specified - - for each `file` present in the `files` array - - the `sourcePath` is calculated as `from + file` - - the `destination` is calculated as `to_folder + file` - - thus, the object is downloaded from `sourcePath` to `destination` -- Else i.e. `files` is NOT specified - - If `to_file` is specified - - the object is downloaded from `from` to `to_folder + to_file` - - Otherwise, calculate the `filename` at the end of `from` i.e. the part after last `/` - - the object is downloaded from `from` to `to_folder + filename at the end of 'from'` - -Learn more about `fetch` on PyScript [here](https://jeff.glass/post/whats-new-pyscript-2022-12-1) - -#### Use-Cases - -Assumptions: - -The directory being served has the following tree structure: - -``` -content/ - ├─ index.html <<< File with - ├─ info.txt - ├─ data/ - │ ├─ sensordata.csv - ├─ packages/ - │ ├─ my_package/ - │ │ ├─ __init__.py - │ │ ├─ helloworld/ - │ │ │ ├─ __init__.py - │ │ │ ├─ greetings.py -``` - -1. Fetching a single file - -```html - - [[fetch]] - files = ['info.txt'] - -``` - -```html - - with open('info.txt', 'r') as fp: - print(fp.read()) - -``` - -2. Single File with Renaming - -```html - - [[fetch]] - from = 'info.txt' - to_file = 'info_loaded_from_web.txt' - -``` - -```html - - with open('info_loaded_from_web.txt', 'r') as fp: - print(fp.read()) - -``` - -3. Single File to another Directory - -```html - - [[fetch]] - files = ['info.txt'] - to_folder = 'infofiles/loaded_info' - -``` - -```html - - with open('infofiles/loaded_info/info.txt', 'r') as fp: - print(fp.read()) - -``` - -4. Single File to another Directory with Renaming - -```html - - [[fetch]] - from = 'info.txt' - to_folder = 'infofiles/loaded_info' - to_file = 'info_loaded_from_web.txt' - -``` - -```html - - with open('infofiles/loaded_info/info_loaded_from_web.txt', 'r') as fp: - print(fp.read()) - -``` - -5. Single file from a folder to the current working directory - -```html - - [[fetch]] - from = 'data/' - files = ['sensordata.csv'] - -``` - -```html - - with open('./sensordata.csv', 'r') as fp: - print(fp.read()) - -``` - -6. Single file from a folder to another folder (i.e. not the current working directory) - -```html - - [[fetch]] - from = 'data/' - to_folder = './local_data' - files = ['sensordata.csv'] - -``` - -```html - - with open('./local_data/sensordata.csv', 'r') as fp: - print(fp.read()) - -``` - -7. Multiple files preserving directory structure - -```html - - [[fetch]] - from = 'packages/my_package/' - files = ['__init__.py', 'helloworld/greetings.py', 'helloworld/__init__.py'] - to_folder = 'custom_pkg' - -``` - -```html - - from custom_pkg.helloworld.greetings import say_hi - print(say_hi()) - -``` - -8. From an API endpoint which doesn't end in a filename - -```html - - [[fetch]] - from = 'https://catfact.ninja/fact' - to_file = './cat_fact.json' - -``` - -```html - - import json - with open("cat_fact.json", "r") as fp: - data = json.load(fp) - -``` - -### Interpreter - -An interpreter configuration consists of the following: - -| Value | Type | Description | -|--------|-------------------|-------------| -| `src` | string (Required) | URL to the interpreter source. | -| `name` | string | Name of the interpreter. This field can be any string and is to be used by the application author for their own customization purposes | -| `lang` | string | Programming language supported by the interpreter. This field can be used by the application author to provide clarification. It currently has no implications on how PyScript behaves. | - -#### Example - -- The default interpreter is `pyodide`, another version of which can be specified as following - -```html - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js" - name = "pyodide-0.20.0" - lang = "python" - -``` - -```{note} -Currently, PyScript supports a single interpreter, this may change in the future. -``` - -## Supplying extra information (or metadata) - -Besides the above schema, a user can also supply any extra keys and values that are relevant as metadata information or perhaps are being used within the application. - -For example, a valid config could also be with the snippet below: - -```html - - magic = "unicorn" - -``` - -OR in JSON like - -```html - - { - "magic": "unicorn" - } - -``` - -If this `"magic"` key is present in config supplied via `src` and also present in config supplied via `inline`, then the value in the inline config is given priority i.e. the overriding process also works for custom keys. diff --git a/docs/reference/elements/py-repl.md b/docs/reference/elements/py-repl.md deleted file mode 100644 index 32d95021..00000000 --- a/docs/reference/elements/py-repl.md +++ /dev/null @@ -1,62 +0,0 @@ -# <py-repl> - -The `` element provides a REPL(Read Eval Print Loop) to evaluate multi-line Python and display output. - -## Attributes - -| attribute | type | default | description | -|-------------------|---------|---------|--------------------------------------| -| **auto-generate** | boolean | | Auto-generates REPL after evaluation | -| **output-mode** | string | "" | Determines whether the output element is cleared prior to writing output | -| **output** | string | | The id of the element to write `stdout` and `stderr` to | -| **stderr** | string | | The id of the element to write `stderr` to | -| **src** | string | | Resource to be preloaded into the REPL | - - -### `auto-generate` -If a \ tag has the `auto-generate` attribute, upon execution, another \ tag will be created and added to the DOM as a sibling of the current tag. - -### `output-mode` -By default, the element which displays the output from a REPL is cleared (`innerHTML` set to "") prior to each new execution of the REPL. If `output-mode` == "append", that element is not cleared, and the output is appended instead. - -### `output` -The ID of an element in the DOM that `stdout` (e.g. `print()`), `stderr`, and the results of executing the repl are written to. Defaults to an automatically-generated \ as the next sibling of the REPL itself. - -### `stderr` -The ID of an element in the DOM that `stderr` will be written to. Defaults to None, though writes to `stderr` will still appear in the location specified by `output`. - -### `src` -If a \ tag has the `src` attribute, during page initialization, resource in the `src` will be preloaded into the REPL. Please note that this will not run in advance. If there is content in the \ tag, it will be cleared and replaced with preloaded resource. - -## Examples - -### `` element set to auto-generate - -```html - -``` - -### `` element with output - -The following will write "Hello! World!" to the div with id `replOutput`. - -```html -
- - print("Hello!") - hello = "World!" - hello - -``` - -Note that if we `print` from the REPL (or otherwise write to `sys.stdout`), the output will be printed in the [`py-terminal`](../plugins/py-terminal.md) if is enabled. - -### `` element with src -Preload resource from src into the REPL -```html - - If a py-repl tag has the src attribute, - the content here will be cleared and replaced. - -
-``` diff --git a/docs/reference/elements/py-script.md b/docs/reference/elements/py-script.md deleted file mode 100644 index 85a9a0fd..00000000 --- a/docs/reference/elements/py-script.md +++ /dev/null @@ -1,126 +0,0 @@ -# <py-script> - -The `` element, also available as ` - - - - print("Let's compute π:") - def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - - pi = compute_pi(100000) - s = f"π is approximately {pi:.3f}" - print(s) - - - -``` - -### Using `` element with `src` attribute - -we can also move our python code to its own file and reference it via the `src` attribute. - - -```python -# compute_pi.py -print("Let's compute π:") -def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - -pi = compute_pi(100000) -s = f"π is approximately {pi:.3f}" -print(s) -``` - -Since both compute_pi.py and index.html are in the same directory, we can reference the python file with a relative path. - -```html - - - - - - - - - -``` - -### Writing into labeled elements - -In the example above, we had a single `` tag printing -one or more lines onto the page in order. Within the ``, you can -use the `Element` class to create a python object for interacting with -page elements. Objects created from the `Element` class provide the `.write()` method -which enables you to send strings into the page elements referenced by those objects. - -For example, we'll add some style elements and provide placeholders for -the `` tag to write to. - -```html - - - - - - - - -

Today is

-
-
- - import datetime as dt - Element('today').write(dt.date.today().strftime('%A %B %d, %Y')) - - def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - - pi = compute_pi(100000) - Element('pi').write(f'π is approximately {pi:.3f}') - - - -``` diff --git a/docs/reference/exceptions.md b/docs/reference/exceptions.md deleted file mode 100644 index a298e8af..00000000 --- a/docs/reference/exceptions.md +++ /dev/null @@ -1,52 +0,0 @@ -# Exceptions and error codes - -When creating pages with PyScript, you may encounter exceptions. Each handled exception will contain a specific code which will give you more information about it. -This reference guide contains the error codes you might find and a description of each of them. - -## User Errors - -| Error code | Description | Recommendation | -|------------|--------------------------------|--------------------| -| PY1000 | Invalid configuration supplied | Confirm that your `py-config` tag is using a valid `TOML` or `JSON` syntax and is using the correct configuration type. | -| PY1001 | Unable to install package(s) | Confirm that the package contains a pure Python 3 wheel or the name of the package is correct. | -| PY2000 | Invalid plugin file extension | Only `.js` and `.py` files can be used when loading user plugins. Please confirm your path contains the file extension. | -| PY2001 | Plugin doesn't contain a default export | Please add `export default` to the main plugin class. | -| PY9000 | Top level await is deprecated | Create a coroutine with your code and schedule it with `asyncio.ensure_future` or similar | - - - -## Fetch Errors - -These error codes are related to any exception raised when trying to fetch a resource. If, while trying to fetch a resource, we encounter a status code that is not 200, the error code will contain the HTTP status code and the `PY0` prefix. For example, if we encounter a 404 error, the error code will be `P02404`. - - -| Error Code | Description | -|------------|--------------------------------------------------------------| -| PY0001 | Generic fetch error, failed to fetch page from the server | -| PY0002 | Name supplied when trying to fetch resource is invalid | -| PY0401 | You are not authorized to access this resource. | -| PY0403 | You are not allowed to access this resource. | -| PY0404 | The page you are trying to fetch does not exist. | -| PY0500 | The server encountered an internal error. | -| PY0503 | The server is currently unavailable. | - -## PY1001 - -Pyscript cannot install the package(s) you specified in your `py-config` tag. This can happen for a few reasons: - -- The package does not exist -- The package does not contain a pure Python 3 wheel -- An error occurred while trying to install the package - -An error banner should appear on your page with the error code and a description of the error or a traceback. You can also check the developer console for more information. - -## PY2001 - -Javascript plugins must export a default class. This is required for PyScript to be able to load the plugin. Please add `export default` to the main plugin class. For example: - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - console.log("Hello World from the plugin!"); - } -``` diff --git a/docs/reference/faq.md b/docs/reference/faq.md deleted file mode 100644 index bd459949..00000000 --- a/docs/reference/faq.md +++ /dev/null @@ -1,160 +0,0 @@ -# Frequently asked questions - -As the world’s most popular programming language, Python is powerful in its capabilities and comparatively easy to learn, yet the limitations cannot be ignored: it’s hard to install Python and all necessary dependencies; it’s glued to the backend without the ability to make apps or websites; and it’s difficult to share your work. - -What if we could remove those limitations, making the power of Python accessible to the masses? The makers of PyScript set out to do just that by enabling Python in the browser for frontend web and application development. No more complicated installs. Projects can be shared with anyone, anywhere—all you need is a browser. - -We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable OS on top to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration. - -> “This is the exciting beginning for supporting new ways of programming, building, sharing, and deploying applications. Ultimately, we should be spending our time thinking and writing applications to solve the real problems we have, not dealing with mundane, hardware-induced challenges. Let's make programming more fun and simple.” - Fabio Pliger - -## Why PyScript? - -Exponentially expand accessibility and use cases for Python by enabling Python in the browser for building UIs. Reproduce environments without having to download Python or conda or install other packages. Projects can be shared with anyone and deployed anywhere—all you need is a browser and a web-accessible device (computer, tablet, or mobile). - -We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable operating system on top of the browser to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration. - -- [PyCon US 2022 Keynote with Peter Wang](https://anaconda.cloud/pyscript-pycon2022-peter-wang-keynote) -- [Example demos from Keynote](https://pyscript.net/examples/index.html) - -## What is PyScript? - -PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide — Version 0.20.0](https://pyodide.org/en/stable/), [WebAssembly](https://webassembly.org/), and modern web technologies. The PyScript framework provides users at every experience level with access to an expressive, easy-to-learn programming language with countless applications. - -What is PyScript? Well, here are some of the core components: - -- Python in the browser: Enable drop-in content, external file hosting, and application hosting without the reliance on server-side configuration - -- Python ecosystem: Run many popular packages of Python and the scientific stack (such as numpy, pandas, scikit-learn, and more) - -- Python with JavaScript: Bi-directional communication between Python and Javascript objects and namespaces - -- Environment management: Allow users to define what packages and files to include for the page code to run - -- Visual application development: Use readily available curated UI components, such as buttons, containers, text boxes, and more - -- Flexible framework: A flexible framework that can be leveraged to create and share new pluggable and extensible components directly in Python - -All that to say... PyScript is just HTML, only a bit (okay, maybe a lot) more powerful, thanks to the rich and accessible ecosystem of Python libraries. - -In short, our mission is to enable programming for the 99%. - -## How can a user get started? - -Leveraging Python in HTML is literally as simple as adding a few lines of code to your page. The best place to learn more, get started, and stay updated on all things PyScript is [Pyscript.net](http://pyscript.net/). Additional shareable resources below: - -- [PyScript Repo](https://github.com/pyscript/pyscript) -- [PyScript Announcement Blog](https://www.anaconda.com/blog/pyscript-python-in-the-browser) -- [PyScript Technical Blog](https://engineering.anaconda.com/2022/04/welcome-pyscript.html) -- [PyScript Nucleus Project](https://anaconda.cloud/s/pyscript) -- [PyScript Documentation](https://docs.pyscript.net/) - -## Why isn't this going to be as terrible as PHP? - -This comparison is based on both PHP and PyScript having a similar way of declaring things: put a tag on the page and the interpreter handles it. PHP works on the server side and is itself a whole different programming language that has its own directives and semantics. - -The choice of using tags to allow people to execute Python is explicit; even if this functionality is similar to PHP, it works differently. First of all, everything runs in the browser itself rather than going to the server side. Secondly, PyScript lives close to the text and allows changes to be made to the visual elements. The PyScript REPL can generate output, plus it provides additional visual elements like buttons, titles, and input boxes. PyScript functions as a framework that generates UIs that makes sense as a tag in the html code. - -Currently, both PHP and PyScript operate with only one namespace. However, PyScript will soon support multiple namespaces and different types of isolation of code (scope), along with support for languages beyond Python. - -## Why not just learn JavaScript? - -JavaScript is not only a different language from python, but a challenging language at that. With PyScript, you now have two languages to choose from, with even more on the roadmap. PyScript allows you to use both libraries and makes JavaScript and Python compatible with one another. - -Python is incredibly powerful, super intuitive, and easy to learn. By adding Python to your toolkit, you can use Numpy, SciPy, Pandas, and more, seamlessly. One tradeoff is longer download times, so it isn’t the right tool for everything—but where it is the right tool, it’s almost irreplaceable. - -Ultimately, PyScript will enable the use of a variety of languages, offer a standard set of components that is well linked to the REPLs, and allow you to do an introspection on the code base—you can have, for example, a *modifiable* chart as a python object. - -## Will PyScript replace JavaScript? - -No. PyScript allows Python to leverage HTML, CSS, and JavaScript conventions to build elegant UIs and address general web application building, packaging, distribution, and deployment challenges (a huge pain). We expect the popularity and adoption of HTML, CSS, and JavaScript to rise alongside Python, ultimately making the web a more friendly and hackable place for everyone. That said, we do believe: - -- PyScript will displace some use cases that people have to rely on Javascript for now -- PyScript will heavily leverage and interface with existing powerful, feature-full JS libraries, as appropriate -- PyScript will open up web programming to tens of millions of people who would otherwise not have touched JavaScript; so in this way, it will outpace JavaScript - -But none of these above scenarios lead to a situation where "PyScript replaces all existing JavaScript." Just as Python itself didn't replace C, C++, or Java. But, it did take a LOT of market share for new use cases where those languages would otherwise have been used. - -## What is the difference between PyScript and Pyodide? - -![pyodide-pyscript](../img/pyodide-pyscript.png) - -PyScript provides HTML tags for embedding and executing Python code in your browser. As a ‘glue’ framework, it sits on top of a variety of tools and provides users access to Pyodide, the WebAssembly port of CPython, which is compiled using Emscripten. In other words, Pyodide enables PyScript users to take advantage of real CPython on the browser. - -Together, PyScript and Pyodide allow users to author applications by turning the browser into a code deployment tool that anyone can learn to use. - -With respect to the UI, PyScript is opinionated and purposeful, while Pyodide is agnostic, unopinionated, and intended for more general use. - -## What packages can I use? Can I use anything from PyPI? - -You can use anything within the Pyodide library, and pure python packages from PyPi that do not contain C dependencies should be supported by Pyodide. - -There is a list of packages built in Pyodide in [Packages built in Pyodide — Version 0.20.0](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) (these are mostly packages with C extensions). You can also install pure Python packages from PyPI or custom URLs, assuming they have a wheel. - -In general, Pyodide doesn’t support all Python features—not because of Pyodide itself, but because some concepts just work differently on the browser (think of sockets/websockets, IO, threading, etc.). If it’s a pure python package that doesn’t have any non-supported features, you should expect it to work. If it has C dependencies, etc., don’t expect it to work unless someone builds/ports them. A lot of the features that don’t work can be made to work, but it will take human power to fix. For example, the PyTorch community wanted those features to work, so they rallied around it to make it happen. Expect the set of libraries that work to grow quickly given the volume of package builds coming from the community. - -## This package XXX is not supported because it has C dependencies. How can I make it work? - -See [Creating a Pyodide package — Version 0.20.0](https://pyodide.org/en/stable/development/new-packages.html). - -## Why is PyScript loading so slowly? Why can’t we put things behind a CDN? - -Packages are already served from the JsDelivr CDN. This is not a downloading speed problem—it's WASM assembly time. PyScript loads slowly because the Python standard library and packages are large and WebAssembly code needs to be compiled and run by the browser after they are loaded for the first time. - -Currently, there are efforts to mitigate the problem, and Pyodide is currently working on a bundler, for instance. - -## Is PyScript owned by Anaconda? - -Anaconda doesn’t own PyScript. It is an open source project developed by Anaconda internally, and Anaconda team members are currently the main contributors, but the repo itself is public. We are working on a steering council to ensure the project stays public and owned by the community. - -See [Maintainers](../concepts/governance/maintainers.md). - -See [Governance Policy](../concepts/governance/policy.md). - -## What is the governing model for PyScript? - -See [Governance Policy](../concepts/governance/policy.md). - -## What is the license? - -PyScript uses the Apache-2.0 license. - -Pyodide uses MPL-2.0 license. Various packages are distributed under their corresponding license. - -## Is Pyodide a replacement for CPython? How does PyScript and Pyodide compare to CPython on WASM? - -No. They have different elements that do different things, both of which are additive. - -PyScript sits on top of everything. Pyodide came before the work on CPython and WASM. Patches were created in order for it to work, but now that CPython/WASM are progressing, Pyodide is able to remove a few of those patches. Additionally, CPython doesn’t deal with building Python packages for WASM. WASM related work on upstream CPython will integrate into Pyodide in the near future. - -For a list of differences from “standard” CPython, see [Pyodide Python compatibility — Version 0.20.0](https://pyodide.org/en/stable/usage/wasm-constraints.html). - -## Hasn’t this already been done before by Brython/skulpt? - -No. Brython and Skulpt accomplish different things than PyScript and Pyodide. - -Brython is client-side and functions as syntax on top of Javascript—it is a reimplementation of Python on top of Javascript, without support for packages or a file system. The extraction of a package in normal Python has been replaced completely by something else. You should be able to run code with minimal changes; however, that isn’t possible with Brython. - -Skulpt is a cross compiler from Python to Javascript, leveraged for compatibility with the Python ecosystem. If you want to do any more Python, you would have to send it over. - -Fairly similar syntax to normal Python, but not exactly the same. If Brython was an interpreter and a full Python implementation, it could be used with PyScript to leverage packages like Numpy, but that isn’t possible as it stands today. They do have the Python script tag, but it is a smaller API and not as feature rich—which is why PyScript is built on Pyodide, Emscripten, and WebAssembly. - -## How can I contribute/help? - -**PyScript** - we are currently working on building documentation and a contributing guide. In the meantime, just ask to help on the PyScript [discussions page](https://anaconda.cloud/s/pyscript) or in the [repo](http://github.com/pyscript/pyscript). - -**Pyodide** - refer to [Pyodide docs](https://pyodide.org/en/stable/development/contributing.html). - -## WebAssembly Security - -See [WebAssembly docs](https://webassembly.org/docs/security/). - -## Why don’t Requests and Black work? - -Requests and Black do not work out of the box because they weren’t meant for the browser. On the browser, sockets multiprocessing works differently, so there is work to be done to actually match things. - -For Black, it’s a design choice that can be patched. This is currently being addressed by the team at Pyodide. - -Requests do not work because of the sockets issue (sockets and websockets are two different things) and requests are blocking—which you don’t want in the browser. It’ll require putting the interpreter on a webworker and utilizing an assistant, but on the main thread it’s unlikely that it’ll work. - -There are options as a path forward. For example, Requests can be leveraged using javascript libraries, or building a python async version of Requests API or a python wrapper for fetch (pyfetch), etc. The websockets library has a client side that could be made to work—given that it has all asynchronous APIs, there’s nothing fundamentally difficult about getting it to work. diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index d52f247e..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,54 +0,0 @@ -# Reference - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Elements ---- -elements/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Modules ---- -modules/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Plugins ---- -plugins/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: API ---- -API/* -``` - -```{toctree} ---- -maxdepth: 2 -glob: -caption: Exceptions ---- -exceptions -``` - -```{toctree} ---- -maxdepth: 1 -caption: Miscellaneous ---- -faq -``` diff --git a/docs/reference/modules/pyscript.md b/docs/reference/modules/pyscript.md deleted file mode 100644 index b4604c11..00000000 --- a/docs/reference/modules/pyscript.md +++ /dev/null @@ -1,77 +0,0 @@ -# pyscript - -The code underlying PyScript is a JavaScript module, which is loaded and executed by the browser. This is what loads when you include, for example, ` -``` -```js -//example result -Object { year: 2022, month: 11, patch: 1, releaselevel: "dev" } -``` - -## pyscript.interpreter - -The Interpreter object which is responsible for executing Python code in the Browser. Currently, all interpreters are assumed to be Pyodide interpreters, but there is flexibility to expand this to other web-based Python interpreters in future versions. - -The Interpreter object has the following attributes - -| attribute | type | description | -|---------------------|-----------------------|---------------------------------------------------------------------------------| -| **src** | string | The URL from which the current interpreter was fetched | -| **interface** | InterpreterInterface | A reference to the interpreter object itself | -| **globals** | any | The globals dictionary of the interpreter, if applicable/accessible | -| **name (optional)** | string | A user-designated name for the interpreter | -| **lang (optional)** | string | A user-designation for the language the interpreter runs ('Python', 'C++', etc) | - -### pyscript.interpreter.src - -The URL from which the current interpreter was fetched. - -### pyscript.interpreter.interface - -A reference to the Interpreter wrapper that PyScript uses to execute code. object itself. This allows other frameworks, modules etc to interact with the same [(Pyodide) interpreter instance](https://pyodide.org/en/stable/usage/api/js-api.html) that PyScript uses. - -For example, assuming we've loaded Pyodide, we can access the methods of the Pyodide interpreter as follows: - -```html - - -``` - -### pyscript.interpreter.globals - -A proxy for the interpreter's `globals()` dictionary. For example: - -```html - - x = 42 - - - - -``` -### pyscript.interpreter.name - -A user-supplied string for the interpreter given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript. - -### PyScript.interpreter.lang - -A user-supplied string for the language the interpreter uses given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript. diff --git a/docs/reference/plugins/py-splashscreen.md b/docs/reference/plugins/py-splashscreen.md deleted file mode 100644 index 3c3e84ce..00000000 --- a/docs/reference/plugins/py-splashscreen.md +++ /dev/null @@ -1,65 +0,0 @@ - -# <py-splashscreen> - -This is one of the core plugins in PyScript, which is active by default. The splashscreen is the first thing you see when you open a page with Pyscript while it is loading itself and all the necessary resources. - -## Configuration - -You can control how `` behaves by setting the value of the `splashscreen` configuration in your ``. - - -| parameter | default | description | -|-------------|-----------|-------------| -| `autoclose` | `true` | Whether to close the splashscreen automatically when the page is ready or not | -| `enabled` | `true` | Whether to show the splashscreen or not | - -### Examples - -#### Disabling the splashscreen - -If you don't want the splashscreen to show and log any loading messages, you can disable it by setting the splashscreen option `enabled` to `false`. - -```html - - [splashscreen] - enabled = false - -``` - -#### Disabling autoclose - -If you want to keep the splashscreen open even after the page is ready, you can disable autoclose by setting `autoclose` to `false`. - -```html - - [splashscreen] - autoclose = false - -``` - -## Adding custom messages - -You can add custom messages to the splashscreen. This is useful if you want to show the user that something is happening in the background for your PyScript app. - -There are two ways to add your custom messages to the splashscreen, either by dispatching a new custom event, `py-status-message` to the document: - - -```js -document.dispatchEvent(new CustomEvent("py-status-message", {detail: "Hello, world!"})) -``` - -Or by using the `log` method of the `py-splashscreen` tag directly: - -```js -const splashscreen = document.querySelector("py-splashscreen") -splashscreen.log("Hello, world!") -``` - -If you wish, you can also send messages directly to the splashscreen from your python code: - -```python -from js import document - -splashscreen = document.querySelector("py-splashscreen") -splashscreen.log("Hello, world!") -``` diff --git a/docs/reference/plugins/py-terminal.md b/docs/reference/plugins/py-terminal.md deleted file mode 100644 index 30001a50..00000000 --- a/docs/reference/plugins/py-terminal.md +++ /dev/null @@ -1,82 +0,0 @@ -# <py-terminal> - -This is one of the core plugins in PyScript, which is active by default. With it, you can print to `stdout` and `stderr` from your python code, and the output will be displayed on the page in ``. - -## Configuration - -You can control how `` behaves by setting the values of the `terminal`, `docked`, and `xterm` fields in your configuration in your ``. - -For the **terminal** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | Don't add `` to the page | -| `true` | Automatically add a `` to the page | -| `"auto"` | This is the default. Automatically add a ``, to the page. The terminal is initially hidden and automatically shown as soon as something writes to `stdout` and/or `stderr` | - -For the **docked** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | Don't dock `` to the page | -| `true` | Automatically dock a `` to the page | -| `"docked"` | This is the default. Automatically add a ``, to the page. The terminal, once visible, is automatically shown at the bottom of the page, covering the width of such page | - -Please note that **docked** mode is currently used as default only when `terminal="auto"`, or *terminal* default, is used. - -In all other cases it's up to the user decide if a terminal should be docked or not. - -For the **xterm** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | This is the default. The `` is a simple `
` tag with some CSS styling. |
-| `true` or `xterm` | The [xtermjs](http://xtermjs.org/) library is loaded and its Terminal object is used as the ``. It's visibility and position are determined by the  `docked` and `auto` keys in the same way as the default `` |
-
-The xterm.js [Terminal object](http://xtermjs.org/docs/api/terminal/classes/terminal/) can be accessed directly if you want to adjust its properties, add [custom parser hooks](http://xtermjs.org/docs/guides/hooks/), introduce [xterm.js addons](http://xtermjs.org/docs/guides/using-addons/), etc. Access is best achieved by awaiting the `xtermReady` attribute of the `` HTML element itself:
-
-```python
-import js
-import asyncio
-
-async def adjust_term_size(columns, rows):
-    xterm = await js.document.querySelector('py-terminal').xtermReady
-    xterm.resize(columns, rows)
-
-asyncio.ensure_future(adjust_term_size(40,10))
-```
-
-Some terminal-formatting packages read from specific environment variables to determine whether they should emit formatted output; PyScript does not set these variables explicitly - you may need to set them yourself, or force your terminal-formatting package into a state where it outputs correctly formatted output.
-
-A couple of specific examples:
- - the [rich](https://github.com/Textualize/rich) will not, by default, output colorful text, but passing `256` or `truecolor` as an argument as the `color_system` parameter to the [Console constructor](https://rich.readthedocs.io/en/stable/reference/console.html#rich.console.Console) will force it to do so. (As of rich v13)
- - [termcolor](https://github.com/termcolor/termcolor) will not, by default, output colorful text, but setting `os.environ["FORCE_COLOR"] = "True"` or by passing `force_color=True` to the `colored()` function will force it to do so. (As of termcolor v2.3)
-
-### Examples
-
-```html
-
-    terminal = true
-    docked = false
-
-
-
-    print("Hello, world!")
-
-```
-
-This example will create a new ``, the value "Hello, world!" that was printed will show in it.
-
-You can also add one (or more) `` to the page manually.
-
-```html
-
-    print("Hello, world!")
-
-
-
-```
-
-```{note}
-If you include a `` in the page, you can skip `terminal` from your ``.
-```
diff --git a/docs/robots.txt b/docs/robots.txt
deleted file mode 100644
index 4fccf0cc..00000000
--- a/docs/robots.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-User-agent: *
-Disallow: /review/
-
-Sitemap: https://docs.pyscript.net/sitemap.xml
-Host: docs.pyscript.net
diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md
deleted file mode 100644
index d0e17da0..00000000
--- a/docs/tutorials/getting-started.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# Getting started with PyScript
-
-This page will guide you through getting started with PyScript.
-
-## Development setup
-
-PyScript does not require any development environment other
-than a web browser (we recommend using [Chrome](https://www.google.com/chrome/)) and a text editor, even though using your [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) of choice might be convenient.
-
-If you're using [VSCode](https://code.visualstudio.com/), the
-[Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
-can be used to reload the page as you edit the HTML file.
-
-## Installation
-
-There is no installation required. In this document, we'll use
-the PyScript assets served on [https://pyscript.net](https://pyscript.net).
-
-If you want to download the source and build it yourself, follow
-the instructions in the [README.md](https://github.com/pyscript/pyscript/blob/main/README.md) file.
-
-## Your first PyScript HTML file
-
-Here's a "Hello, world!" example using PyScript.
-
-Using your favorite editor, create a new file called `hello.html` in
-the same directory as your PyScript, JavaScript, and CSS files with the
-following content, and open the file in your web browser. You can typically
-open an HTML by double-clicking it in your file explorer.
-
-```html
-
-  
-    
-    
-  
-  
-    
-        print('Hello, World!')
-    
-  
-
-```
-
-### Using a Local Server
-
-In some situations, your browser may forbid loading remote resources like `pyscript.js` and `pyscript.css` when you open an HTML file directly. When this is the case, you may see your Python code in the text of the webpage, and the [browser developer console](https://balsamiq.com/support/faqs/browserconsole/) may show an error like *"Cross origin requests are only supported for HTTP."* The fix for this is to use a [simple local server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Tools_and_setup/set_up_a_local_testing_server) to make your html file available to the browser.
-
-If you have python installed on your system, you can use it's basic built-in server for this purpose via the command line. Change the current working directory of your terminal or command line to the folder where your HTML file is stored. From this folder, run `python -m http.server 8080 --bind 127.0.0.1` in your terminal or command line. With the server program running, point your browser to `http://localhost:8080` to view the contents of that folder. (If a file in that folder is called `index.html`, it will be displayed by default.)
-
-## A more complex example
-
-Now that we know how you can create a simple 'Hello, World!' example, let's see a more complex example. This example will use the Demo created by [Cheuk Ting Ho](https://github.com/Cheukting). In this example, we will use more features from PyScript.
-
-### Setting up the base index file
-
-Let's create a new file called `index.html` and add the following content:
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-  
-
-```
-
-In this first step, we have created the index file, imported `pyscript.css` and `pyscript.js`. We are ready to start adding the elements we need for our application.
-
-### Importing the needed libraries
-
-For this example, we will need to install `pandas` and `matplotlib`. We can install libraries using the `` tag so we can import them later. Please refer to the [``](../reference/elements/py-config.md) documentation for more information.
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-  
-
-```
-
-### Importing the data and exploring
-
-Now that we have installed the needed libraries, we can import and explore the data. In this step, we need to create a `` tag to import our dependencies, read the data with pandas and then use `py-repl` to explore the data.
-
-You may want to read the [``](../reference/elements/py-script.md) and [``](../reference/elements/py-repl.md) documentation for more information about these elements.
-
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-    
-      import pandas as pd
-
-      from pyodide.http import open_url
-
-      url = (
-          "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv"
-      )
-      ice_data = pd.read_csv(open_url(url))
-    
-
-    
-      ice_data
-    
-  
-
-```
-
-Note that we are adding `ice_data` to `py-repl` to pre-populate the REPL with this variable, so you don't have to type it yourself.
-
-### Creating the plot
-
-Now that we have the data, we can create the plot. We will use the `matplotlib` library to make the plot. We will use the `display` API to display the plot on the page. You may want to read the [`display`](../reference/API/display.md) documentation for more information.
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-    
-      import pandas as pd
-      import matplotlib.pyplot as plt
-
-      from pyodide.http import open_url
-
-      url = (
-          "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv"
-      )
-      ice_data = pd.read_csv(open_url(url))
-
-      def plot(data):
-        plt.rcParams["figure.figsize"] = (22,20)
-        fig, ax = plt.subplots()
-        bars = ax.barh(data["name"], data["rating"], height=0.7)
-        ax.bar_label(bars)
-        plt.title("Rating of ice cream flavours of your choice")
-        display(fig, target="graph-area", append=False)
-
-      plot(ice_data)
-    
-
-    
-      ice_data
-    
-
-    
- - -``` - -### Select specific flavours - -Now that we have a way to explore the data using `py-repl` and a way to create the plot using all of the data, it's time for us to add a way to select specific flavours. - -```html - - - Ice Cream Picker - - - - - - - - packages = ["matplotlib", "pandas"] - - - - import js - import pandas as pd - import matplotlib.pyplot as plt - - from pyodide.http import open_url - from pyodide.ffi import create_proxy - - url = ( - "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv" - ) - ice_data = pd.read_csv(open_url(url)) - - current_selected = [] - flavour_elements = js.document.getElementsByName("flavour") - - def plot(data): - plt.rcParams["figure.figsize"] = (22,20) - fig, ax = plt.subplots() - bars = ax.barh(data["name"], data["rating"], height=0.7) - ax.bar_label(bars) - plt.title("Rating of ice cream flavours of your choice") - display(fig, target="graph-area", append=False) - - def select_flavour(event): - for ele in flavour_elements: - if ele.checked: - current_selected = ele.value - break - if current_selected == "ALL": - plot(ice_data) - else: - filter = ice_data.apply(lambda x: ele.value in x["ingredients"], axis=1) - plot(ice_data[filter]) - - ele_proxy = create_proxy(select_flavour) - - for ele in flavour_elements: - if ele.value == "ALL": - ele.checked = True - current_selected = ele.value - ele.addEventListener("change", ele_proxy) - - plot(ice_data) - - - -
- Select your 🍨 flavour:
- - - - - - - - - - - - -
- - - ice_data - - -
- - -``` diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md deleted file mode 100644 index 225d3e24..00000000 --- a/docs/tutorials/index.md +++ /dev/null @@ -1,38 +0,0 @@ -# Tutorials - -This section contains pyscript tutorials. Each tutorial is a self-contained document that will guide you through a specific topic. - -## Getting Started - -This tutorial will guide you through getting started with PyScript, from installation to writing your first PyScript application. The getting started will show you how to specify dependencies, read a csv file from the web, use `pandas` and `matplotlib` and how to handle user input. - -[Read the get started tutorial](getting-started.md) - - -## Basics - -This section contains tutorials about the basics of PyScript. - -```{toctree} ---- -maxdepth: 1 -glob: ---- -writing-to-page -py-click -requests -``` - -## PyScript Configuration - -This section contains tutorials about the PyScript configuration using the `` tag. - - -```{toctree} ---- -maxdepth: 1 -glob: ---- -py-config-fetch -py-config-interpreter -``` diff --git a/docs/tutorials/py-click.md b/docs/tutorials/py-click.md deleted file mode 100644 index 6cb52c2d..00000000 --- a/docs/tutorials/py-click.md +++ /dev/null @@ -1,127 +0,0 @@ -# Handling click events - -This tutorial will show you how to use the `py-click` attribute to handle mouse clicks on elements on your page. The `py-click` attribute is a special attribute that allows you to specify a Python function that will be called when the element is clicked. There are many other events such as py-mouseover, py-focus, py-input, py-keyress etc, which can be used as well. They are listed here [Attr-to-Event](../reference/API/attr_to_event.html) - -## Development setup - -Let's start by building the base HTML page. We will create an HTML page with a button and a paragraph. When the button is clicked, the paragraph will show the current time. - - -```html - - - - - - - Current Time - - - - - - - -``` - -## Adding elements to the page - -Let's add a button and a paragraph to the page. The button will have the `py-click` attribute, and the paragraph will have the `id` attribute. The `id` attribute is used to identify the element on the page, and the `py-click` attribute will be used to specify the function that will be called when the button is clicked. - -```html - - - - - - - Current Time - - - - - - - -

- - -``` - -There are two things to note here: - -- You must specify an id for an element that uses any `py-*` attribute -- We used the `py-button` class to style the button, this is optional, and these rules are coming from the pyscript.css that we added in the `` section. - -## Creating the Python function - -In this step, we will create the Python function that will be called when the button is clicked. This function will get the current time and update the paragraph with the current time. We will use a `` tag to specify the Python code that will be executed when the page is loaded. - - -```html - - - - - - - Current Time - - - - - - - -

- - - import datetime - - def current_time(): - now = datetime.datetime.now() - - - -``` - -## Writing the time to the page - -If you run the example, you will notice that nothing happened. This is because we still need to update the paragraph with the current time. We can do this by using the [`Element` API](../reference/API/element.md) to get the paragraph element and then update it with the current time with the `write` method. - - -```html - - - - - - - Current Time - - - - - - - -

- - - from pyscript import Element - import datetime - - def current_time(): - now = datetime.datetime.now() - - # Get paragraph element by id - paragraph = Element("current-time") - - # Add current time to the paragraph element - paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S")) - - - -``` - -Now, if you refresh the page and click the button, the paragraph will be updated with the current time. diff --git a/docs/tutorials/py-config-fetch.md b/docs/tutorials/py-config-fetch.md deleted file mode 100644 index 3831d8fa..00000000 --- a/docs/tutorials/py-config-fetch.md +++ /dev/null @@ -1,188 +0,0 @@ -# Using the fetch from py-config - -This tutorial shows how to use the fetch configuration from `py-config` to fetch two files from a remote server, store them in a local directory, and verify their contents. - -## Development setup - -We will create a todo list application similar to the one in the [examples](https://pyscript.net/examples/todo.html). To do this, we need three things: - - * An `index.html` file containing the HTML for the application. - * A `todo.py` file containing the Python code for the application. - * A `utils.py` file containing some utility functions for the application. - - -We will use the `fetch` configuration from `py-config` to fetch these files from a remote server and store them in a local directory. - -### Creating the html file - -In this first step, we will create the `index.html` file and import both `pyscript.css` and `pyscript.js`. These are needed to run our Python code in the browser and style the application. - -```html - - - - - - - My Todo - - - - - - - - - -``` - -## Fetching the files - -### Using `fetch` to get the python files - -Now we will use the `fetch` configuration from `py-config` to fetch the `todo.py` and `utils.py` files from a remote server and store them in a local directory called `todo`. Here we will fetch files from different URLs, using a `fetch` per item. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - - -``` - -## Creating a todo application - -### Creating the todo elements - -Now we will create the todo elements in the `body` of the `index.html` file. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - -
-
-

To Do List

-
-
- - -
-
- -
- - -``` - -Our todo application is starting to shape up, although if you try to add any tasks, you will notice that nothing happens. This is because we have not yet imported the `todo.py` file. - -### Importing the needed functions from `todo.py` - -This is where the magic happens. We can import the `todo.py` file by adding it as a source to the `py-script` tag. By specifying the file, pyscript will automatically import the file and run the code in it. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - - from todo import add_task, add_task_event - -
-
-

To Do List

-
-
- - -
-
- -
- - -``` - -You can now save the file and refresh the page. You should now be able to add tasks to your todo list. - -## That's it! - -You have now created a todo application using pyscript. You can add tasks and mark them as done. Let's take a recap of what we have achieved: - -* We have imported three separate files into our `index.html` file using the `py-config` tag. -* We have created the necessary HTML code to create our todo's -* We have imported functions from the `todo.py` file, using the `py-script` tag. - -For reference, the code from [the gist](https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/todo.py) is the same code that our [todo example](https://pyscript.net/examples/todo.html) uses with a slight change of importing `Element` from `pyscript`. diff --git a/docs/tutorials/py-config-interpreter.md b/docs/tutorials/py-config-interpreter.md deleted file mode 100644 index 9eea0e70..00000000 --- a/docs/tutorials/py-config-interpreter.md +++ /dev/null @@ -1,88 +0,0 @@ -# Setting a pyodide interpreter - -Pyscript will automatically set the interpreter for you, but you can also set it manually. This is useful if you want to use a different version than the one set by default. - -## Development setup - -To get started, let's create a new `index.html` file and import `pyscript.js`. - -```html - - - - - - - Interpreter - - - - - - - - - -``` - -We are using the pyodide CDN to setup our interpreter, but you can also download the files from [the pyodide GitHub releases](https://github.com/pyodide/pyodide/releases/), unzip them and use the `pyodide.js` file as your interpreter. - -## Setting the interpreter - -To set the interpreter, you can use the `interpreter` configuration in the `py-config` element. In this tutorial, we will use the default `TOML` format, but know that you can also use `json` if you prefer by changing the `type` attribute of the `py-config` element. - -```html - - - - - - - Interpreter - - - - - - - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - -``` - -## Confirming the interpreter version - -To confirm that the interpreter is set correctly, you can open the DevTools and check the version from the console. But for the sake of this tutorial, let's create a `py-script` tag and print pyodide's version. - -```html - - - - - - - Interpreter - - - - - - - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - import pyodide - print(pyodide.__version__) - - - -``` diff --git a/docs/tutorials/requests.md b/docs/tutorials/requests.md deleted file mode 100644 index 34a74905..00000000 --- a/docs/tutorials/requests.md +++ /dev/null @@ -1,123 +0,0 @@ -# Calling an API using Requests - -This tutorial will show you how to interact with an API using the [Requests](https://requests.readthedocs.io/en/master/) library. Requests is a popular library, but it doesn't work out of the box with Pyscript. We will use the [pyodide-http](https://github.com/koenvo/pyodide-http) library to patch the Requests library, so it works with Pyscript. - - We will use the [JSON Placeholder API](https://jsonplaceholder.typicode.com/), a free fake API that returns fake data. - -## Development Setup - -Let's build the base HTML page to add our `py-config` and `py-script` tags in the next steps. - -```html - - - - - - - Requests Tutorial - - - - - - - -``` - -## Installing the dependencies - -In this step, we will install the dependencies we need to use the Requests library. We will use the `py-config` tag to specify the dependencies we need to install. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - -``` - -## Patching the Requests library - -Now that we have installed the dependencies, we need to patch the Requests library to work with Pyscript. We will use the `py-script` tag to specify the code that will be executed when the page is loaded. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - - import pyodide_http - pyodide_http.patch_all() - - - -``` - -## Making a request - -Finally, let's make a request to the JSON Placeholder API to confirm that everything is working. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - - import requests - import pyodide_http - - # Patch the Requests library so it works with Pyscript - pyodide_http.patch_all() - - # Make a request to the JSON Placeholder API - response = requests.get("https://jsonplaceholder.typicode.com/todos") - print(response.json()) - - - -``` - -## Conclusion - -In this tutorial, we learned how to use the Requests library to make requests to an API. We also learned how to use the `py-config` and `py-script` tags to install dependencies and execute code when the page is loaded. - -Depending on the API you use, you may need to add additional headers to your request. You can read the [Requests documentation](https://requests.readthedocs.io/en/master/user/quickstart/#custom-headers) to learn more about how to do this. - -You may also be interested in creating your module to make requests. You can read the in-depth guide on [How to make HTTP requests using `PyScript`, in pure Python](../guides/http-requests.md) to learn more about how to do this. diff --git a/docs/tutorials/writing-to-page.md b/docs/tutorials/writing-to-page.md deleted file mode 100644 index d71fa5e8..00000000 --- a/docs/tutorials/writing-to-page.md +++ /dev/null @@ -1,212 +0,0 @@ -# How to write content to the page - -When creating your PyScript application, you will want to write content to the page. This tutorial will explore the different methods you can use to write content to the page and their differences. - -## Development setup - -To get started, we will create an `index.html` file, import PyScript and start building on top of it. - -```html - - - - - - - Writing to the page - - - - - - - - - -``` - -## Writing content to an element - -Let's first see how we can write content to an element on the page. We will start by creating a `div` element with an `id` of `manual-write`, then create a `py-script` tag that, upon a click of a button, will write 'Hello World' to the `div` element. - -```html - - - - - - - Writing to the page - - - - - - -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerText = "Hello World" - - - -``` - -```{note} -When using `py-click` you must supply an `id` to the element you want to use as the trigger. -``` - -We can now open our `index.html` file and click the button. You will see that "Hello World" will appear in the `div` element. You could also write HTML using `manual_div.element.innerHTML` instead of `innerText`. For example: - -```html - - - - - - - Writing to the page - - - - - - -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" -
- - -``` - -## Writing content with the `display` API - -The `display` API is a simple way to write content to the page. Not only does it allow you to write content to the page, but it also allows you to display a range of different content types such as images, markdown, svgs, json, etc. - -Using the' display' API, let's reuse our previous example and write "Hello World" to the page. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") -
- - -``` - -```{note} -When using the `display` API, you must specify the `target` parameter to tell PyScript where to write the content. If you do not use this parameter, an error will be thrown. -``` - -You may be interested in reading more about the `display` API in the [Display API](../reference/api/display) section of the documentation. - -## Printing to the page - -We couldn't have a tutorial on writing to the page without mentioning the `print` function. The `print` function is a simple way to write content to the page, that any Python developer will be familiar with. When you use the `print` function, the content will be written to the page in a `py-terminal` element. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- - - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") - - def print_to_page(): - print("I print things!") -
- - -``` - -You may be surprised to see that when you click the "Print Things!" button, the content is written below the rest of the elements on the page in a black canvas. This is because the `print` function writes content to the page in a `py-terminal` element. You can read more about the `py-terminal` element in the [Terminal Element](../reference/plugins/py-terminal) section of the documentation. - -PyScript comes with the `py-terminal` plugin by default and any `stdout` or `stderr` content will be shown in this element. We can be explicit about where we want the terminal to be shown by adding the `` tag to our HTML. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- -
- -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") - - def print_to_page(): - print("I print things!") -
- - -``` diff --git a/examples/handtrack/say_hello.html b/examples/handtrack/say_hello.html index 95900406..97601ec3 100644 --- a/examples/handtrack/say_hello.html +++ b/examples/handtrack/say_hello.html @@ -11,8 +11,7 @@ rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> - - + diff --git a/pyscriptjs/public/index.html b/public/index.html similarity index 60% rename from pyscriptjs/public/index.html rename to public/index.html index 8443107f..90f67f08 100644 --- a/pyscriptjs/public/index.html +++ b/public/index.html @@ -5,8 +5,8 @@ - - + + PyScript @@ -14,16 +14,15 @@

<py-script>

- + + from pyscript import display import sys - print(sys.version) + display(sys.version)

Example

@@ -34,17 +33,18 @@ <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>PyScript Hello World</title> - <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> - <script defer src="https://pyscript.net/latest/pyscript.js"></script> + <link rel="stylesheet" href="_PATH_core.css" /> + <script type="module" src="_PATH_core.js"></script> </head> <body> Hello world! <br> This is the current date and time, as computed by Python: <py-script> +from pyscript import display from datetime import datetime now = datetime.now() -now.strftime("%m/%d/%Y, %H:%M:%S") +display(now.strftime("%m/%d/%Y, %H:%M:%S")) </py-script> </body> </html>
t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var h=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const y="0811fd41-1b6b-49f1-8344-96210ac283f1",m="M"+y,g="T"+y;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:S}=A,{isArray:j}=Array,{notify:k,wait:P,waitAsync:x}=Atomics,{fromCharCode:M}=String,R=(e,t)=>e?(x||w)(t,0):(P(t,0),{value:{then:e=>e()}}),$=new WeakSet,T=new WeakMap;let W=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!T.has(e)){const s=(t,...r)=>e.postMessage({[y]:r},{transfer:t});T.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,o)=>"then"===o?null:(...r)=>{const a=W++;let i=new b(new _(E)),c=[];$.has(r.at(-1)||c)&&$.delete(c=r.pop()),s(c,a,i,o,n?r.map(n):r);const l=e!==globalThis;return R(l,i).value.then((()=>{const e=i[0];if(!e)return;const r=S*e;return i=new b(new _(r+r%E)),s([],a,i),R(l,i).value.then((()=>t(M(...new A(i.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[y];if(j(s)){e.stopImmediatePropagation();const[o,a,...i]=s;if(i.length){const[e,s]=i;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);{const i=await t.get(e)(...s);if(void 0!==i){const e=r(i);n.set(o,e),a[0]=e.length}}}else{const e=n.get(o);n.delete(o);for(let t=new A(a.buffer),r=0;r($.add(e),e);const F="object",B="function",I="number",L="string",N="undefined",C="symbol",{defineProperty:J,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Y,setPrototypeOf:Q}=Reflect,{assign:X,create:G}=Object,Z=D(Int8Array),K="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case B:return e(r,t);case"boolean":case I:case L:case N:case"bigint":return ee(r,t);case C:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===C)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",he="ownKeys",ye="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;J(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?X(G(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),h=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===I)return l.get(r);if(!(r instanceof Z))for(const e in r)r[e]=h(r[e]);return r;case B:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(B,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case C:return ne(r)}return r},y={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(J(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,V(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[he]:e=>ee(F,z(e).map(f)),[ye]:e=>f(q(e)),[me]:(e,t,r)=>f(Y(e,t,r)),[ge]:(e,t)=>f(Q(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=h(r[0]),r[1]=r[1].map(h);break;case ae:r[0]=r[0].map(h);break;case ie:{const[e,t]=r;r[0]=h(e);const{get:n,set:s,value:o}=t;n&&(t.get=h(n)),s&&(t.set=h(s)),o&&(t.value=h(o));break}default:r=r.map(h)}return y[e](h(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===B?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[K],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===B){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof Z))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),h=e=>{const[t,r]=e;if(!f.has(r)){const n=t===B?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===I?h(e):r;case B:return typeof r===L?n.get(r):h(e);case C:return ne(r)}return r},m=(e,t,...r)=>y(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===B&&(r.get=c(n)),typeof s===B&&(r.set=c(s)),typeof o===B&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&V(r,y)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[he]:e=>m(he,e).map(y),[ye]:e=>m(ye,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return y(t).apply(y(s),o.map(y));case we:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[K];return J(Array,K,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window");const _e=new WeakMap,Ae=(e,...t)=>{const r=O(e,...t);if(!_e.has(r)){const t=e instanceof Worker?be:ve;_e.set(r,t(r,m,g))}return _e.get(r)};Ae.transfer=O.transfer;const{isArray:Ee}=Array,{assign:Se,create:je,defineProperties:ke,defineProperty:Pe,entries:xe}=Object,{all:Me,resolve:Re}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),$e=(e,t=location.href)=>new URL(e,t).href,Te=e=>e.arrayBuffer(),We=e=>e.json(),Oe=e=>e.text(),Fe=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Be{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Fe)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Fe)this[t]&&(e[t]=this[t]);return e}}var Ie=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="0811fd41-1b6b-49f1-8344-96210ac283f1",d="M"+p,g="T"+p;var y=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:h,Map:w,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=h,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||y)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,x=new WeakMap;let k=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!x.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});x.set(e,new Proxy(new w,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,o)=>"then"===o?null:(...r)=>{const a=k++;let i=new h(new m(v)),c=[];_.has(r.at(-1)||c)&&_.delete(c=r.pop()),s(c,a,i,o,n?r.map(n):r);const l=e!==globalThis;return $(l,i).value.then((()=>{const e=i[0];if(!e)return;const r=S*e;return i=new h(new m(r+r%v)),s([],a,i),$(l,i).value.then((()=>t(j(...new b(i.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new w;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[o,a,...i]=s;if(i.length){const[e,s]=i;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);{const i=await t.get(e)(...s);if(void 0!==i){const e=r(i);n.set(o,e),a[0]=e.length}}}else{const e=n.get(o);n.delete(o);for(let t=new b(a.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ge="setPrototypeOf",ye="delete";var he=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ye,Q(R,e))})),g=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=g(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},y={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ge]:(e,t)=>p(z(e,t)),[ye](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=g(r[0]),r[1]=r[1].map(g);break;case ne:r[0]=r[0].map(g);break;case se:{const[e,t]=r;r[0]=g(e);const{get:n,set:s,value:o}=t;n&&(t.get=g(n)),s&&(t.set=g(s)),o&&(t.value=g(o));break}default:r=r.map(g)}return y[e](g(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),we=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ye,c(e))})),g=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,w),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?g(e):r;case F:return typeof r===R?n.get(r):g(e);case J:return ee(r)}return r},h=(e,t,...r)=>y(f(e,o(t),...r)),w={[re]:(e,t,r)=>h(re,e,c(t),r.map(c)),[ne]:(e,t)=>h(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),h(se,e,c(t),r)},[oe]:(e,t)=>h(oe,e,c(t)),[ce]:e=>h(ce,e),[ae]:(e,t)=>t===s?e:h(ae,e,c(t)),[ie]:(e,t)=>{const r=h(ie,e,c(t));return r&&V(r,y)},[le]:(e,t)=>t===s||h(le,e,c(t)),[ue]:e=>h(ue,e),[fe]:e=>h(fe,e).map(y),[pe]:e=>h(pe,e),[de]:(e,t,r)=>h(de,e,c(t),c(r)),[ge]:(e,t)=>h(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return y(t).apply(y(s),o.map(y));case ye:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],w),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window");const me=new WeakMap,be=(e,...t)=>{const r=T(e,...t);if(!me.has(r)){const t=e instanceof Worker?he:we;me.set(r,t(r,d,g))}return me.get(r)};be.transfer=T.transfer;const{isArray:ve}=Array,{assign:Se,create:Pe,defineProperties:Ae,defineProperty:Ee,entries:Me}=Object,{all:je,resolve:$e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),_e=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),ke=e=>e.json(),Te=e=>e.text(),Oe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),Fe=new WeakMap,We=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Fe.set(t,r),t}}},Re=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Be=e=>{const t=e.split("/");return t.pop(),t.join("/")},Je=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Le=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},Ie=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},He=new WeakMap,Ce=(e,t,r)=>je((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ve(n))return n.map((r=>({url:Ie([e,r]),path:Ie([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:Ie([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(_e(t,He.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),De=(e,t,r)=>{e.registerJsModule(t,r)},Ne=(e,t)=>{try{return e.runPython(Oe(t))}catch(t){Fe.get(e).stderr(t)}},Ue=(e,t)=>{try{return e.runPythonAsync(Oe(t))}catch(t){Fe.get(e).stderr(t)}},ze=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Fe.get(e).stderr(t)}};var qe={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=We();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ce(this,a,t.fetch),a},registerJSModule:De,run:Ne,runAsync:Ue,runEvent:ze,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Re({FS:e,PATH:t,PATH_FS:r},n,s)};const Ke={dict_converter:Object.fromEntries};var Ye={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=We(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ce(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:De,run:Ne,runAsync:Ue,runEvent:ze,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ke):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Re({FS:e,PATH:t,PATH_FS:r},n,s)};const Ge="ruby-wasm-wasi",Ve=Ge.replace(/\\W+/g,"_");var Qe={type:Ge,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ce(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of Me(r)){const r=`__module_${Ve}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t)=>e.eval(Oe(t)),runAsync:(e,t)=>e.evalAsync(Oe(t)),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Ve}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ge}`)}};var Xe={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=We(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ce(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of Me(r))e.global.set(t,n)},run:(e,t)=>{try{return e.doStringSync(Oe(t))}catch(t){Fe.get(e).stderr(t)}},runAsync:(e,t)=>{try{return e.doString(Oe(t))}catch(t){Fe.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Fe.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Je(e,Be(t)),t=Le(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const Ze=new Map,et=new Map,tt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=Ze.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{et.set(t,e);const a=e?.fetch;return a&&He.set(a,o),s(n,e,r)}))}}),rt=e=>{for(const t of[].concat(e.type))Ze.set(t,e)};for(const e of[qe,Ye,Qe,Xe])rt(e);const nt=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let st,ot,at;const it=(e,t)=>{addEventListener(e,t||(async t=>{try{await st,ot(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:ct,stringify:lt}=f,{proxy:ut,window:ft,isWindowProxy:pt}=be(self,{parse:ct,stringify:lt,transform:e=>at?at(e):e}),dt={sync:ut,window:ft,isWindowProxy:pt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};it("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{st=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(ke),t=_e(t);else if(t.endsWith(".toml"))r=fetch(t).then(Te).then(nt),t=_e(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=nt(t)}t=_e("./config.txt")}return $e(r).then((r=>tt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Pe(Ze.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r)=>e(t,`${r}\\n${o}`)}if(a){const e=l[u].bind(l);l[u]=(t,r)=>e(t,`${a}\\n${r}`)}}return l.registerJSModule(c,"polyscript",{xworker:dt}),ot=l.runEvent.bind(l,c),at=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),it("error"),it("message"),it("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Be;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=$e(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Oe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return ke(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ae(n,h).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Le=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Ne=new WeakMap,Ce=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Ne.set(t,r),t}}},Je=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},He=e=>{const t=e.split("/");return t.pop(),t.join("/")},De=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ue=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},ze=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},qe=new WeakMap,Ye=(e,t,r)=>Me((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Ee(n))return n.map((r=>({url:ze([e,r]),path:ze([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:ze([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch($e(t,qe.get(e))))(r,n).then(Te).then((r=>e.writeFile(t,s,r)))))),Qe=(e,t,r)=>{e.registerJsModule(t,r)},Xe=(e,t)=>{try{return e.runPython(Le(t))}catch(t){Ne.get(e).stderr(t)}},Ge=(e,t)=>{try{return e.runPythonAsync(Le(t))}catch(t){Ne.get(e).stderr(t)}},Ze=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ne.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Ce();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Qe,run:Xe,runAsync:Ge,runEvent:Ze,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Je({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve={dict_converter:Object.fromEntries};var et={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Ce(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Qe,run:Xe,runAsync:Ge,runEvent:Ze,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ve):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Je({FS:e,PATH:t,PATH_FS:r},n,s)};const tt="ruby-wasm-wasi",rt=tt.replace(/\W+/g,"_");var nt={type:tt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of xe(r)){const r=`__module_${rt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t)=>e.eval(Le(t)),runAsync:(e,t)=>e.evalAsync(Le(t)),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${rt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${tt}`)}};var st={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Ce(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of xe(r))e.global.set(t,n)},run:(e,t)=>{try{return e.doStringSync(Le(t))}catch(t){Ne.get(e).stderr(t)}},runAsync:(e,t)=>{try{return e.doString(Le(t))}catch(t){Ne.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ne.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(De(e,He(t)),t=Ue(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const ot=new Map,at=new Map,it=[],ct=[],lt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=ot.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{at.set(t,e);const a=e?.fetch;return a&&qe.set(a,o),s(n,e,r)}))}}),ut=e=>{for(const t of[].concat(e.type))ot.set(t,e),it.push(`script[type="${t}"]`),ct.push(`${t}-`)};for(const e of[Ke,et,nt,st])ut(e);const pt=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),ft=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(We),t=$e(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(pt),t=$e(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=pt(t)}t=$e("./config.txt")}return Re(r).then((r=>lt[e](r,t)))},dt=(e,t="")=>`${e}@${t}`.replace(/@$/,""),ht=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},yt=new WeakMap,mt={get(){let e=yt.get(this);return e||(e=document.createElement(`${this.type}-script`),yt.set(this,e),_t(this)),e},set(e){"string"==typeof e?yt.set(this,ht(this,e)):(yt.set(this,e),_t(this))}},gt=new WeakMap,wt=new Map,bt=(e,t)=>{const r=e?.value;return r?t+r:""},vt=(e,t,r,n,s,o=e)=>{if(!wt.has(t)){const a={interpreter:ft(r,s),queue:Re(),XWorker:Ie(e,n)};wt.set(t,a),wt.has(e)||wt.set(e,a),wt.has(o)||wt.set(o,a)}return wt.get(t)},_t=async e=>{if(gt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=dt(c,l);let p=bt(r,"|");const f=bt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Ie(c,l))(d,{async:!!t,config:p});return void gt.set(Pe(e,"xworker",{value:r}),{xworker:r})}const h=bt(s,""),y=vt(c,f,u,l,p);gt.set(Pe(e,"target",mt),y),h&&yt.set(e,ht(e,h));const m=i?fetch(i).then(Oe):e.textContent;y.queue=y.queue.then((()=>(async(e,t,r,n)=>{const s=ot.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await Me([gt.get(e).interpreter,t]);try{return Pe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,y.XWorker,!!t)))}};new Proxy(je(null),{get:(e,t)=>At(t)});const At=async e=>{if(wt.has(e)){const{interpreter:t,queue:r}=wt.get(e);return(await Me([t,r]))[0]}const t=wt.size?`Available interpreters are: ${[...wt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},Et=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${ct.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await At(a.getAttribute(`${s}-env`)||s);ot.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${ct.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,Et)},jt=[],kt=new Map,Pt=new Map,xt=e=>{for(const t of jt)if(e.matches(t)){const r=kt.get(t),{resolve:n}=Pt.get(r),{options:s,known:o}=Mt.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=$t.call(new Be(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return Pe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=dt(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:h}=vt(r,f,p,i,a,t);d.then((o=>{const a=je(ot.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Be(o,s),y=function(...e){return h.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o){r&&r.call(this,m,e);const a=s.call(this,t,o);return n&&n.call(this,m,e),a}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o){r&&await r.call(this,m,e);const a=await s.call(this,t,o);return n&&await n.call(this,m,e),a}}a.registerJSModule(o,"polyscript",{XWorker:y});const m={type:r,interpreter:o,XWorker:y,io:Ne.get(o),config:structuredClone(at.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},Mt=new Map,Rt=e=>(Pt.has(e)||Pt.set(e,Promise.withResolvers()),Pt.get(e).promise),$t=Ie(),Tt=it.join(","),Wt=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Tt))_t(e);else{if(t(Tt,e).forEach(_t),!jt.length)continue;xt(e),t(jt.join(","),e).forEach(xt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of ct)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,Et)}break}}}})),Ot=e=>(Wt.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:Ft}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ot(Ft.call(this,e))}}),St(Ot(document)),t(Tt,document).forEach(_t);var Bt='# ⚠️ WARNING - both `document` and `window` are added at runtime\n\nimport base64\nimport html\nimport io\nimport re\n\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" + + + + + +``` + +Once the module is loaded, any `` on the page, or any `` tag, would automatically run its own code or the file defined as `src` attribute, after bootstrapping the *pyodide* interpreter. + +If no ` +``` + +Alternatively, it is possible to specify a `worker` attribute to either run embedded code or the provided `src` file. + +#### CSS + +If you are planning to use either `` or `` tags on the page, where latter case is usually better off with ` +``` + +#### HTML Example + +This is a complete reference to bootstrap *PyScript* in a HTML document. + +```html + + + + PyScript Next + + + + + + + + + +``` + + +## Tag attributes API + +Either ``. Both `async` and `config` attributes are also available and used to bootstrap the worker as desired. + +Please note that other [polyscript's attributes](https://pyscript.github.io/polyscript/#script-attributes) are available too but their usage is more advanced. + + +## JS Module API + +The module itself is currently exporting the following utilities: + + * **PyWorker**, which allows to bootstrap a *worker* with *pyodide* and the *pyscript* module available within the code. This callback accepts a file as argument, and an additional, and optional, `options` object literal, able to understand a `config`, which could also be directly a *JS* object literal instead of a JSON string or a file to point at, and `async` which if `true` will run the worker code with top level await enabled. Please note that the returned reference is exactly the same as [the polyscript's XWorker](https://pyscript.github.io/polyscript/#the-xworker-reference), exposing exact same utilities but granting on bootstrap all hooks are in place and the type is always *pyodide*. + * **hooks**, which allows plugins to define *ASAP* callbacks or strings that should be executed either in the main thread or the worker before, or after, the code has been executed. + +```js +import { hooks } from "https://cdn.jsdelivr.net/npm/@pyscript/core"; + +// example +hooks.onInterpreterReady.add((utils, element) => { + console.log(element, 'found', 'pyscript is ready'); +}); + +// the hooks namespace +({ + // each function is invoked before or after python gets executed + // via: callback(pyScriptUtils, currentElement) + /** @type {Set} */ + onBeforeRun: new Set(), + /** @type {Set} */ + onBeforeRunAync: new Set(), + /** @type {Set} */ + onAfterRun: new Set(), + /** @type {Set} */ + onAfterRunAsync: new Set(), + + // each function is invoked once when PyScript is ready + // and for each element via: callback(pyScriptUtils, currentElement) + /** @type {Set} */ + onInterpreterReady: new Set(), + + // each string is prepended or appended to the worker code + /** @type {Set} */ + codeBeforeRunWorker: new Set(), + /** @type {Set} */ + codeBeforeRunWorkerAsync: new Set(), + /** @type {Set} */ + codeAfterRunWorker: new Set(), + /** @type {Set} */ + codeAfterRunWorkerAsync: new Set(), +}) +``` + +Please note that a *worker* is a completely different environment and it's not possible, by specifications, to pass a callback to it, which is why worker sets are strings and not functions. + +However, each worker string can use `from pyscript import x, y, z` as that will be available out of the box. + +## PyScript Python API + +The `pyscript` python package offers various utilities in either the main thread or the worker. + +The commonly shared utilities are: + + * **window** in both main and worker, refers to the actual main thread global window context. In classic PyScript that'd be the equivalent of `import js` in the main, which is still available in *PyScript Next*. However, to make code easily portable between main and workers, we decided to offer this named export but please note that in workers, this is still the *main* window, not the worker global context, which would be reachable instead still via `import js`. + * **document** in both main and worker, refers to the actual main page `document`. In classic PyScript, this is the equivalent of `from js import document` on the main thread, but this won't ever work in a worker because there is no `document` in there. Fear not though, *PyScript Next* `document` will instead work out of the box, still accessing the main document behind the scene, so that `from pyscript import document` is granted to work in both main and workers seamlessly. + * **display** in both main and worker, refers to the good old `display` utility except: + * in the *main* it automatically uses the current script `target` to display content + * in the *worker* it still needs to know *where* to display content using the `target="dom-id"` named argument, as workers don't get a default target attached + * in both main and worker, the `append=True` is the *default* behavior, which is inherited from the classic PyScript. + +#### Extra main-only features + + * **PyWorker** which allows Python code to create a PyScript worker with the *pyscript* module pre-bundled. Please note that running PyScript on the main requires *pyodide* bootstrap, but also every worker requires *pyodide* bootstrap a part, as each worker is an environment / sandbox a part. This means that using *PyWorker* in the main will take, even if the main interpreter is already up and running, a bit of time to bootstrap the worker, also accordingly to the config files or packages in it. + + +#### Extra worker-only features + + * **sync** which allows both main and the worker to seamlessly pass any serializable data around, without the need to convert Python dictionaries to JS object literals, as that's done automatically. + +```html + +``` + +```python +from pyscript import sync + +sync.alert_message("Hello Main!") +``` + +### Worker requirements + +To make it possible to use what looks like *synchronous* DOM APIs, or any other API available via the `window` within a *worker*, we are using latest Web features such as [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics). + +Without going into too many details, this means that the *SharedArrayBuffer* primitive must be available, and to do so, the server should enable the following headers: + +``` +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: cross-origin +``` + +These headers allow local files to be secured and yet able to load resources from the Web (i.e. pyodide library or its packages). + +> ℹ️ **Careful**: we are using and testing these headers on both Desktop and Mobile to be sure all major browsers work as expected (Safari, Firefox, Chromium based browsers). If you change the value of these headers please be sure you test your target devices and browsers properly. + +Please note that if you don't have control over your server's headers, it is possible to simply put [mini-coi](https://github.com/WebReflection/mini-coi#readme) script at the root of your *PyScript with Workers* enabled folder (site root, or any subfolder). + +```sh +cd project-folder + +# grab mini-coi content and save it locally as mini-coi.js +curl -Ls https://unpkg.com/mini-coi -o mini-coi.js +``` + +With either these two solutions, it should be now possible to bootstrap a *PyScript Worker* without any issue. + +#### mini-coi example +```html + + + + + +``` + +Please note that a local or remote web server is still needed to allow the Service Worker and `python -m http.server` would do locally, *except* we need to reach `http://localhost:8000/`, not `http://0.0.0.0:8000/`, because the browser does not consider safe non localhost sites when the insecure `http://` protocol, instead of `https://`, is reached. + + +#### local server example +If you'd like to test locally these headers, without needing the *mini-coi* Service Worker, you can use various projects or, if you have *NodeJS* available, simply run the following command in the folder containing the site/project: + +```sh +# bootstrap a local server with all headers needed +npx static-handler --cors --coep --coop --corp . +``` + + +### F.A.Q. + +
+ why config attribute can also contain JSON but not TOML? +
+ +The *JSON* standard doesn't require new lines or indentation so it felt quick and desired to allow inline JSON as attribute content. + +It's true that HTML attributes can be multi-line too, if properly embedded, but that looked too awkward and definitively harder to explain to me. + +We might decide to allow TOML too in the future, but the direct config as attribute, instead of a proper file, or the usage of ``, is meant for quick and simple packages or files dependencies and not much else. + +
+
+ +
+ what are the worker's caveats? +
+ +When interacting with `window` or `document` it's important to understand that these use, behind the scene, an orchestrated [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) dance. + +This means that some kind of data that cannot be passed around, specially not compatible with the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). + +In short, please try to stick with *JS* references when passing along, or dealing with, *DOM* or other *APIs*. + +
+
diff --git a/pyscript.core/index.js b/pyscript.core/index.js new file mode 100644 index 00000000..1d970a72 --- /dev/null +++ b/pyscript.core/index.js @@ -0,0 +1 @@ +export * from "./dist/core.js"; diff --git a/pyscript.core/jsdelivr.js b/pyscript.core/jsdelivr.js new file mode 100644 index 00000000..9e9ac722 --- /dev/null +++ b/pyscript.core/jsdelivr.js @@ -0,0 +1,2 @@ +// @see https://github.com/jsdelivr/jsdelivr/issues/18528 +export * from "./core/dist/core.js"; diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 18ad96b5..81e5a1d1 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,28 +1,136 @@ { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.3.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.3.4", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.1.10" + "polyscript": "^0.5.11", + "sticky-module": "^0.1.1", + "to-json-callback": "^0.1.1", + "type-checked-collections": "^0.1.7" }, "devDependencies": { - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.3", - "rollup": "^3.28.0", + "@playwright/test": "^1.39.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@webreflection/toml-j0.4": "^1.1.3", + "chokidar": "^3.5.3", + "eslint": "^8.53.0", + "rollup": "^4.3.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", - "static-handler": "^0.4.2", - "typescript": "^5.1.6" + "static-handler": "^0.4.3", + "typescript": "^5.2.2", + "xterm": "^5.3.0", + "xterm-readline": "^1.1.1" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", + "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.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": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -81,10 +189,125 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@playwright/test": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", + "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "dev": true, + "dependencies": { + "playwright": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", - "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -98,7 +321,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -107,9 +330,9 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz", - "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "dev": true, "dependencies": { "serialize-javascript": "^6.0.1", @@ -120,7 +343,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.x || ^3.x" + "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -129,9 +352,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", - "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", + "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -142,7 +365,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -150,6 +373,162 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.3.0.tgz", + "integrity": "sha512-/4pns6BYi8MXdwnXM44yoGAcFYVHL/BYlB2q1HXZ6AzH++LaiEVWFpBWQ/glXhbMbv3E3o09igrHFbP/snhAvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.3.0.tgz", + "integrity": "sha512-nLO/JsL9idr416vzi3lHm3Xm+QZh4qHij8k3Er13kZr5YhL7/+kBAx84kDmPc7HMexLmwisjDCeDIKNFp8mDlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-dGhVBlllt4iHwTGy21IEoMOTN5wZoid19zEIxsdY29xcEiOEHqzDa7Sqrkh5OE7LKCowL61eFJXxYe/+pYa7ZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.3.0.tgz", + "integrity": "sha512-h8wRfHeLEbU3NzaP1Oku7BYXCJQiTRr+8U0lklyOQXxXiEpHLL8tk1hFl+tezoRKLcPJD7joKaK74ASsqt3Ekg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-wP4VgR/gfV18sylTuym3sxRTkAgUR2vh6YLeX/GEznk5jCYcYSlx585XlcUcl0c8UffIZlRJ09raWSX3JDb4GA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-v/14JCYVkqRSJeQbxFx4oUkwVQQw6lFMN7bd4vuARBc3X2lmomkxBsc+BFiIDL/BK+CTx5AOh/k9XmqDnKWRVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-tNhfYqFH5OxtRzfkTOKdgFYlPSZnlDLNW4+leNEvQZhwTJxoTwsZAAhR97l3qVry/kkLyJPBK+Q8EAJLPinDIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-pw77m8QywdsoFdFOgmc8roF1inBI0rciqzO8ffRUgLoq7+ee9o5eFqtEcS6hHOOplgifAUUisP8cAnwl9nUYPw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-tJs7v2MnV2F8w6X1UpPHl/43OfxjUy9SuJ2ZPoxn79v9vYteChVYO/ueLHCpRMmyTUIVML3N9z4azl9ENH8Xxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-OKGxp6kATQdTyI2DF+e9s+hB3/QZB45b6e+dzcfW1SUqiF6CviWyevhmT4USsMEdP3mlpC9zxLz3Oh+WaTMOSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.3.0.tgz", + "integrity": "sha512-DDZ5AH68JJ2ClQFEA1aNnfA7Ybqyeh0644rGbrLOdNehTmzfICHiWSn0OprzYi9HAshTPQvlwrM+bi2kuaIOjQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-dMvGV8p92GQ8jhNlGIKpyhVZPzJlT258pPrM5q2F8lKcc9Iv9BbfdnhX1OfinYWnb9ms5zLw6MlaMnqLfUkKnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -160,9 +539,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", + "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", "dev": true }, "node_modules/@types/resolve": { @@ -181,6 +560,12 @@ "resolved": "https://registry.npmjs.org/@ungap/with-resolvers/-/with-resolvers-0.1.0.tgz", "integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw==" }, + "node_modules/@webreflection/toml-j0.4": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@webreflection/toml-j0.4/-/toml-j0.4-1.1.3.tgz", + "integrity": "sha512-ragv0U1Hy9JTyFpUqApu/UwF4Qhn0Y5GnQR4Bmy/+wYLKbHNS6hLN6bJR44v5DumaocJ4vpF6HVtYWeDJVs3qg==", + "dev": true + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -193,6 +578,40 @@ "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", @@ -208,21 +627,77 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/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/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/basic-devtools": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/basic-devtools/-/basic-devtools-0.1.6.tgz", "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==" }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "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.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "funding": [ { @@ -239,10 +714,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -269,6 +744,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -282,9 +766,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001547", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz", + "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==", "dev": true, "funding": [ { @@ -317,16 +801,64 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/coincident": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.11.3.tgz", - "integrity": "sha512-a/jBWoCv8O/YyfqXt0P8ees64tkuGKKubHj3KHTezxVmKYcUPVnaSAk9kcZxzDUGfKB5/CgM1rhaPrlQ9el9eg==", + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "@ungap/structured-clone": "^1.2.0", - "@ungap/with-resolvers": "^0.1.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" }, "optionalDependencies": { - "ws": "^8.13.0" + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/codedent": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/codedent/-/codedent-0.1.2.tgz", + "integrity": "sha512-qEqzcy5viM3UoCN0jYHZeXZoyd4NZQzYFg0kOBj8O1CgoGG9WYYTF+VeQRsN0OSKFjF3G1u4WDUOtOsWEx6N2w==", + "dependencies": { + "plain-tag": "^0.1.3" + } + }, + "node_modules/coincident": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.4.tgz", + "integrity": "sha512-XLZs1S0ToZb8jAngtJQa5uFfhOdF168f+jodvkMOVpZl/JI9J+B1WdxX2PwU1vERxmahEubHv9Gr+a3XWOnccw==", + "dependencies": { + "@ungap/structured-clone": "^1.2.0", + "@ungap/with-resolvers": "^0.1.0", + "gc-hook": "^0.2.4" + }, + "optionalDependencies": { + "ws": "^8.14.2" } }, "node_modules/color-convert": { @@ -362,6 +894,18 @@ "node": ">= 10" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "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/concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", @@ -371,6 +915,20 @@ "source-map": "^0.6.1" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/css-declaration-sorter": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", @@ -524,6 +1082,29 @@ "node": ">=8.0.0" } }, + "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/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -533,6 +1114,18 @@ "node": ">=0.10.0" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -589,9 +1182,15 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.488", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.488.tgz", - "integrity": "sha512-Dv4sTjiW7t/UWGL+H8ZkgIjtUAVZDgb/PwGWvMsCT7jipzUV/u5skbLXPFKb6iV0tiddVi/bcS2/kUrczeWgIQ==", + "version": "1.4.549", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.549.tgz", + "integrity": "sha512-gpXfJslSi4hYDkA0mTLEpYKRv9siAgSUgZ+UWyk+J5Cttpd1ThCVwdclzIwQSclz3hYn049+M2fgrP1WpvF8xg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/entities": { @@ -612,22 +1211,269 @@ "node": ">=6" } }, + "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.53.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", + "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.53.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "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.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.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", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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.3", + "strip-ansi": "^6.0.1", + "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-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "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/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/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/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": 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-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.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "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==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -638,11 +1484,10 @@ "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/gc-hook": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.2.4.tgz", + "integrity": "sha512-IP7xtJGpaqbzj7Jn3KMhvVPVp3W7LXGbtz/D1dd147ocWg/7nl9TT28TQ+/o+qmn1hI2oCrI86vUvv9WlIbGwQ==" }, "node_modules/generic-names": { "version": "4.0.0", @@ -653,14 +1498,64 @@ "loader-utils": "^3.2.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==", + "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": { - "function-bind": "^1.1.1" + "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.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, "engines": { "node": ">= 0.4.0" } @@ -674,6 +1569,11 @@ "node": ">=8" } }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" + }, "node_modules/icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", @@ -692,6 +1592,15 @@ "postcss": "^8.1.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-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -704,6 +1613,22 @@ "node": ">=8" } }, + "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/import-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", @@ -716,6 +1641,52 @@ "node": ">=8" } }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-builtin-module": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", @@ -743,12 +1714,127 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, + "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-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-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/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-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-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "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/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -767,6 +1853,21 @@ "node": ">= 12.13.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.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -779,12 +1880,30 @@ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "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/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/mdn-data": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", @@ -812,6 +1931,24 @@ "node": ">= 0.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/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.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -831,12 +1968,27 @@ "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/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -861,6 +2013,32 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "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.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -870,6 +2048,36 @@ "node": ">=4" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-queue": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", @@ -898,6 +2106,45 @@ "node": ">=8" } }, + "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", @@ -934,21 +2181,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/plain-tag": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/plain-tag/-/plain-tag-0.1.3.tgz", + "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" + }, + "node_modules/playwright": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", + "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "dev": true, + "dependencies": { + "playwright-core": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", + "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright/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/polyscript": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.1.10.tgz", - "integrity": "sha512-NdO0inJIJyNgM8bYvD9z8aYbs1chQWq3iNtXjj7YrDT84A7IOVELPCFDlXzLU8UngpO/yQm3j4YrEoln89LbsA==", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.11.tgz", + "integrity": "sha512-/QAp2qkvR9i3n1oSy2mo6DOdCQDRIeZnJhSLjhwghmoAflB0q2VPod21Bl4PS0mlNv50441/zutWix/pFNAsIg==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "coincident": "^0.11.3" + "codedent": "^0.1.2", + "coincident": "^0.14.4", + "html-escaper": "^3.0.3", + "sticky-module": "^0.1.1" } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -1505,6 +2804,15 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "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/promise.series": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", @@ -1514,6 +2822,35 @@ "node": ">=0.12" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "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/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -1523,10 +2860,22 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -1541,27 +2890,64 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "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": ">=8" + "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": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.3.0.tgz", + "integrity": "sha512-scIi1NrKLDIYSPK66jjECtII7vIgdAMFmFo8h6qm++I6nN9qDSV35Ku6erzGVqYjx+lj+j5wkusRMr++8SyDZg==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.3.0", + "@rollup/rollup-android-arm64": "4.3.0", + "@rollup/rollup-darwin-arm64": "4.3.0", + "@rollup/rollup-darwin-x64": "4.3.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.3.0", + "@rollup/rollup-linux-arm64-gnu": "4.3.0", + "@rollup/rollup-linux-arm64-musl": "4.3.0", + "@rollup/rollup-linux-x64-gnu": "4.3.0", + "@rollup/rollup-linux-x64-musl": "4.3.0", + "@rollup/rollup-win32-arm64-msvc": "4.3.0", + "@rollup/rollup-win32-ia32-msvc": "4.3.0", + "@rollup/rollup-win32-x64-msvc": "4.3.0", "fsevents": "~2.3.2" } }, @@ -1616,6 +3002,29 @@ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, + "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/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1651,10 +3060,31 @@ "randombytes": "^2.1.0" } }, + "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/smob": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.0.tgz", - "integrity": "sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", + "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", "dev": true }, "node_modules/source-map": { @@ -1694,9 +3124,9 @@ "dev": true }, "node_modules/static-handler": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/static-handler/-/static-handler-0.4.2.tgz", - "integrity": "sha512-Szbk521mneb5npxg3SEyoufsHr2osAzxMy71W2zFCzLB8wLhHYvKUDCMkLY6imi+fIqkpfas3rzXGBQf99aeEA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/static-handler/-/static-handler-0.4.3.tgz", + "integrity": "sha512-rHi6vtxW/kjC+L18cRVAICAp/ymTjyvZHCPXIrejrlVrRrNxrVGk9FNCg+rC9wM7SpZ9euyjsr7tNVtqpA2iLA==", "dev": true, "dependencies": { "mime-types": "^2.1.35" @@ -1708,12 +3138,55 @@ "node": ">=16" } }, + "node_modules/sticky-module": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sticky-module/-/sticky-module-0.1.1.tgz", + "integrity": "sha512-IuYgnyIMUx/m6rtu14l/LR2MaqOLtpXcWkxPmtPsiScRHEo+S4Tojk+DWFHOncSdFX/OsoLOM4+T92yOmI1AMw==" + }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", "dev": true }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/style-inject": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", @@ -1782,9 +3255,9 @@ } }, "node_modules/terser": { - "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", + "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -1805,10 +3278,62 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "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-json-callback": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/to-json-callback/-/to-json-callback-0.1.1.tgz", + "integrity": "sha512-BzOeinTT3NjE+FJ2iCvWB8HvyuyBzoH3WlSnJ+AYVC4tlePyZWSYdkQIFOARWiq0t35/XhmI0uQsFiUsRksRqg==" + }, + "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/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-checked-collections": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/type-checked-collections/-/type-checked-collections-0.1.7.tgz", + "integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A==" + }, + "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/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1819,9 +3344,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -1848,16 +3373,46 @@ "browserslist": ">= 4.21.0" } }, + "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/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "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/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/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "optional": true, "engines": { "node": ">=10.0.0" @@ -1875,6 +3430,24 @@ } } }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "dev": true + }, + "node_modules/xterm-readline": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/xterm-readline/-/xterm-readline-1.1.1.tgz", + "integrity": "sha512-f87S2/jKwRZoZTxE2vkPgBCipDl6k6tTkMTb9pmwC4R6XkfR491fWBuToZd/nZasp6seD2u0jdABinUDWsK6dw==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "peerDependencies": { + "xterm": "^5.0.0" + } + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -1883,6 +3456,18 @@ "engines": { "node": ">= 6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/pyscript.core/package.json b/pyscript.core/package.json index e3e0be72..e7cbadc3 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,27 +1,36 @@ { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.3.4", "type": "module", "description": "PyScript", - "main": "core.js", - "module": "core.js", + "module": "./index.js", + "unpkg": "./index.js", + "jsdelivr": "./jsdelivr.js", + "browser": "./index.js", + "main": "./index.js", "exports": { ".": { - "types": "./types/esm/core.d.ts", - "import": "./esm/core.js" + "types": "./types/core.d.ts", + "import": "./src/core.js" }, - "./core": { - "import": "./core.js" - }, - "./core.css": { - "import": "./core.css" + "./css": { + "import": "./dist/core.css" }, "./package.json": "./package.json" }, "scripts": { - "server": "npx static-handler --cors --coep --coop --corp .", - "build": "rollup --config rollup/core.config.js && rollup --config rollup/core-css.config.js && npm run ts", - "ts": "tsc -p ." + "server": "npx static-handler --coi .", + "build": "npm run build:3rd-party && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts && npm run test:mpy", + "build:core": "rm -rf dist && rollup --config rollup/core.config.js && cp src/3rd-party/*.css dist/", + "build:plugins": "node rollup/plugins.cjs", + "build:stdlib": "node rollup/stdlib.cjs", + "build:3rd-party": "node rollup/3rd-party.cjs", + "test:mpy": "static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; playwright test --fully-parallel test/ || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE", + "dev": "node dev.cjs", + "release": "npm run build && npm run zip", + "size": "echo -e \"\\033[1mdist/*.js file size\\033[0m\"; for js in $(ls dist/*.js); do echo -e \"\\033[2m$js:\\033[0m $(cat $js | brotli | wc -c) bytes\"; done", + "ts": "tsc -p .", + "zip": "zip -r dist.zip ./dist" }, "keywords": [ "pyscript", @@ -32,16 +41,26 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.1.10" + "polyscript": "^0.5.11", + "sticky-module": "^0.1.1", + "to-json-callback": "^0.1.1", + "type-checked-collections": "^0.1.7" }, "devDependencies": { - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.3", - "rollup": "^3.28.0", + "@playwright/test": "^1.39.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@webreflection/toml-j0.4": "^1.1.3", + "chokidar": "^3.5.3", + "eslint": "^8.53.0", + "rollup": "^4.3.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", - "static-handler": "^0.4.2", - "typescript": "^5.1.6" + "static-handler": "^0.4.3", + "typescript": "^5.2.2", + "xterm": "^5.3.0", + "xterm-readline": "^1.1.1" }, "repository": { "type": "git", diff --git a/pyscript.core/rollup/3rd-party.cjs b/pyscript.core/rollup/3rd-party.cjs new file mode 100644 index 00000000..3f955262 --- /dev/null +++ b/pyscript.core/rollup/3rd-party.cjs @@ -0,0 +1,52 @@ +const { copyFileSync, writeFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const CDN = "https://cdn.jsdelivr.net/npm"; + +const targets = join(__dirname, "..", "src", "3rd-party"); +const node_modules = join(__dirname, "..", "node_modules"); + +const { devDependencies } = require(join(__dirname, "..", "package.json")); + +const v = (name) => devDependencies[name].replace(/[^\d.]/g, ""); + +// Fetch a module via jsdelivr CDN `/+esm` orchestration +// then sanitize the resulting outcome to avoid importing +// anything via `/npm/...` through Rollup +const resolve = (name) => { + const cdn = `${CDN}/${name}@${v(name)}/+esm`; + console.debug("fetching", cdn); + return fetch(cdn) + .then((b) => b.text()) + .then((text) => + text.replace( + /("|')\/npm\/(.+)?\+esm\1/g, + // normalize `/npm/module@version/+esm` as + // just `module` so that rollup can do the rest + (_, quote, module) => { + const i = module.lastIndexOf("@"); + return `${quote}${module.slice(0, i)}${quote}`; + }, + ), + ); +}; + +// key/value pairs as: +// "3rd-party/file-name.js" +// string as content or +// Promise as resolved content +const modules = { + "toml.js": join(node_modules, "@webreflection", "toml-j0.4", "toml.js"), + "xterm.js": resolve("xterm"), + "xterm.css": fetch(`${CDN}/xterm@${v("xterm")}/css/xterm.min.css`).then( + (b) => b.text(), + ), + "xterm-readline.js": resolve("xterm-readline"), +}; + +for (const [target, source] of Object.entries(modules)) { + if (typeof source === "string") copyFileSync(source, join(targets, target)); + else { + source.then((text) => writeFileSync(join(targets, target), text)); + } +} diff --git a/pyscript.core/rollup/core-css.config.js b/pyscript.core/rollup/core-css.config.js deleted file mode 100644 index 370dd49b..00000000 --- a/pyscript.core/rollup/core-css.config.js +++ /dev/null @@ -1,20 +0,0 @@ -import postcss from "rollup-plugin-postcss"; - -export default { - input: "./src/core.css", - plugins: [ - postcss({ - extract: true, - sourceMap: false, - minimize: !process.env.NO_MIN, - plugins: [], - }), - ], - output: { - file: "./core.css", - }, - onwarn(warning, warn) { - if (warning.code === "FILE_NAME_CONFLICT") return; - warn(warning); - }, -}; diff --git a/pyscript.core/rollup/core.config.js b/pyscript.core/rollup/core.config.js index b2e5a0b2..16dc822e 100644 --- a/pyscript.core/rollup/core.config.js +++ b/pyscript.core/rollup/core.config.js @@ -2,23 +2,42 @@ // the default exported as npm entry. import { nodeResolve } from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; import terser from "@rollup/plugin-terser"; -import { string } from "rollup-plugin-string"; +import postcss from "rollup-plugin-postcss"; -const plugins = [ - string({ - // Required to be specified - include: "**/*.py", - }), -]; +const plugins = []; -export default { - input: "./src/core.js", - plugins: plugins.concat( - process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()], - ), - output: { - esModule: true, - file: "./core.js", +export default [ + { + input: "./src/core.js", + plugins: plugins.concat( + process.env.NO_MIN + ? [nodeResolve(), commonjs()] + : [nodeResolve(), commonjs(), terser()], + ), + output: { + esModule: true, + dir: "./dist", + sourcemap: true, + }, }, -}; + { + input: "./src/core.css", + plugins: [ + postcss({ + extract: true, + sourceMap: false, + minimize: !process.env.NO_MIN, + plugins: [], + }), + ], + output: { + file: "./dist/core.css", + }, + onwarn(warning, warn) { + if (warning.code === "FILE_NAME_CONFLICT") return; + warn(warning); + }, + }, +]; diff --git a/pyscript.core/rollup/plugins.cjs b/pyscript.core/rollup/plugins.cjs new file mode 100644 index 00000000..22572b08 --- /dev/null +++ b/pyscript.core/rollup/plugins.cjs @@ -0,0 +1,28 @@ +const { readdirSync, writeFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const plugins = [""]; + +for (const file of readdirSync(join(__dirname, "..", "src", "plugins"))) { + if (/\.js$/.test(file)) { + const name = file.slice(0, -3); + const key = /^[a-zA-Z0-9$_]+$/.test(name) + ? name + : `[${JSON.stringify(name)}]`; + const value = JSON.stringify(`./plugins/${file}`); + plugins.push( + // this comment is needed to avoid bundlers eagerly embedding lazy + // dependencies, causing all sort of issues once in production + ` ${key}: () => import(/* webpackIgnore: true */ ${value}),`, + ); + } +} + +plugins.push(""); + +writeFileSync( + join(__dirname, "..", "src", "plugins.js"), + `// ⚠️ This file is an artifact: DO NOT MODIFY\nexport default {${plugins.join( + "\n", + )}};\n`, +); diff --git a/pyscript.core/rollup/stdlib.cjs b/pyscript.core/rollup/stdlib.cjs new file mode 100644 index 00000000..0c23583e --- /dev/null +++ b/pyscript.core/rollup/stdlib.cjs @@ -0,0 +1,29 @@ +const { + readdirSync, + readFileSync, + statSync, + writeFileSync, +} = require("node:fs"); +const { join } = require("node:path"); + +const crawl = (path, json) => { + for (const file of readdirSync(path)) { + const full = join(path, file); + if (/\.py$/.test(file)) json[file] = readFileSync(full).toString(); + else if (statSync(full).isDirectory() && !file.endsWith("_")) + crawl(full, (json[file] = {})); + } +}; + +const json = {}; + +crawl(join(__dirname, "..", "src", "stdlib"), json); + +writeFileSync( + join(__dirname, "..", "src", "stdlib", "pyscript.js"), + `// ⚠️ This file is an artifact: DO NOT MODIFY\nexport default ${JSON.stringify( + json, + null, + " ", + )};\n`, +); diff --git a/pyscript.core/src/3rd-party/README.md b/pyscript.core/src/3rd-party/README.md new file mode 100644 index 00000000..93cc7fe1 --- /dev/null +++ b/pyscript.core/src/3rd-party/README.md @@ -0,0 +1,7 @@ +# PyScript 3rd Party + +This folder contains artifacts created via [3rd-party.cjs](../../rollup/3rd-party.cjs). + +As we would like to offer a way to run PyScript offline, and we already offer a `dist` folder with all the necessary scripts, we have created a foreign dependencies resolver that allow to lazy-load CDN dependencies out of the box. + +Please **note** these dependencies are **not interpreters**, because interpreters have their own mechanism, folders structure, WASM files, and whatnot, to work locally, but at least XTerm or the TOML parser, among other lazy dependencies, should be available within the dist folder. diff --git a/pyscript.core/src/all-done.js b/pyscript.core/src/all-done.js new file mode 100644 index 00000000..4a005660 --- /dev/null +++ b/pyscript.core/src/all-done.js @@ -0,0 +1,17 @@ +import TYPES from "./types.js"; + +const waitForIt = []; + +for (const [TYPE] of TYPES) { + const selectors = [`script[type="${TYPE}"]`, `${TYPE}-script`]; + for (const element of document.querySelectorAll(selectors.join(","))) { + const { promise, resolve } = Promise.withResolvers(); + waitForIt.push(promise); + element.addEventListener(`${TYPE}:done`, resolve, { once: true }); + } +} + +// wait for all the things then cleanup +Promise.all(waitForIt).then(() => { + dispatchEvent(new Event("py:all-done")); +}); diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js new file mode 100644 index 00000000..a027ef4e --- /dev/null +++ b/pyscript.core/src/config.js @@ -0,0 +1,126 @@ +/** + * This file parses a generic or config attribute + * to use as base config for all py-script elements, importing + * also a queue of plugins *before* the interpreter (if any) resolves. + */ +import { $ } from "basic-devtools"; + +import TYPES from "./types.js"; +import allPlugins from "./plugins.js"; +import { robustFetch as fetch, getText } from "./fetch.js"; +import { ErrorCode } from "./exceptions.js"; + +const badURL = (url, expected = "") => { + let message = `(${ErrorCode.BAD_CONFIG}): Invalid URL: ${url}`; + if (expected) message += `\nexpected ${expected} content`; + throw new Error(message); +}; + +/** + * Given a string, returns its trimmed content as text, + * fetching it from a file if the content is a URL. + * @param {string} config either JSON, TOML, or a file to fetch + * @param {string?} type the optional type to enforce + * @returns {{json: boolean, toml: boolean, text: string}} + */ +const configDetails = async (config, type) => { + let text = config?.trim(); + // we only support an object as root config + let url = "", + toml = false, + json = /^{/.test(text) && /}$/.test(text); + // handle files by extension (relaxing urls parts after) + if (!json && /\.(\w+)(?:\?\S*)?$/.test(text)) { + const ext = RegExp.$1; + if (ext === "json" && type !== "toml") json = true; + else if (ext === "toml" && type !== "json") toml = true; + else badURL(text, type); + url = text; + text = (await fetch(url).then(getText)).trim(); + } + return { json, toml: toml || (!json && !!text), text, url }; +}; + +const syntaxError = (type, url, { message }) => { + let str = `(${ErrorCode.BAD_CONFIG}): Invalid ${type}`; + if (url) str += ` @ ${url}`; + return new SyntaxError(`${str}\n${message}`); +}; + +const configs = new Map(); + +for (const [TYPE] of TYPES) { + /** @type {Promise<[...any]>} A Promise wrapping any plugins which should be loaded. */ + let plugins; + + /** @type {any} The PyScript configuration parsed from the JSON or TOML object*. May be any of the return types of JSON.parse() or toml-j0.4's parse() ( {number | string | boolean | null | object | Array} ) */ + let parsed; + + /** @type {SyntaxError | undefined} The error thrown when parsing the PyScript config, if any.*/ + let error; + + let config, + type, + pyConfig = $(`${TYPE}-config`); + if (pyConfig) { + config = pyConfig.getAttribute("src") || pyConfig.textContent; + type = pyConfig.getAttribute("type"); + } else { + pyConfig = $( + [ + `script[type="${TYPE}"][config]:not([worker])`, + `${TYPE}-script[config]:not([worker])`, + ].join(","), + ); + if (pyConfig) config = pyConfig.getAttribute("config"); + } + + // catch possible fetch errors + if (config) { + try { + const { json, toml, text, url } = await configDetails(config, type); + config = text; + if (json || type === "json") { + try { + parsed = JSON.parse(text); + } catch (e) { + error = syntaxError("JSON", url, e); + } + } else if (toml || type === "toml") { + try { + const { parse } = await import( + /* webpackIgnore: true */ "./3rd-party/toml.js" + ); + parsed = parse(text); + } catch (e) { + error = syntaxError("TOML", url, e); + } + } + } catch (e) { + error = e; + } + } + + // parse all plugins and optionally ignore only + // those flagged as "undesired" via `!` prefix + const toBeAwaited = []; + for (const [key, value] of Object.entries(allPlugins)) { + if (error) { + if (key === "error") { + // show on page the config is broken, meaning that + // it was not possible to disable error plugin neither + // as that part wasn't correctly parsed anyway + value().then(({ notify }) => notify(error.message)); + } + } else if (!parsed?.plugins?.includes(`!${key}`)) { + toBeAwaited.push(value().then(({ default: p }) => p)); + } + } + + // assign plugins as Promise.all only if needed + plugins = Promise.all(toBeAwaited); + + configs.set(TYPE, { config: parsed, plugins, error }); +} + +export default configs; diff --git a/pyscript.core/src/core.css b/pyscript.core/src/core.css index c1a3dae9..73220a9a 100644 --- a/pyscript.core/src/core.css +++ b/pyscript.core/src/core.css @@ -1,4 +1,6 @@ py-script, -py-config { +py-config, +mpy-script, +mpy-config { display: none; } diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index daa1d454..880ad214 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -1,76 +1,38 @@ +/*! (c) PyScript Development Team */ + +import stickyModule from "sticky-module"; import "@ungap/with-resolvers"; -import { $ } from "basic-devtools"; -import { define, XWorker } from "polyscript"; -// this is imported as string (via rollup) -import display from "./display.py"; +import { + INVALID_CONTENT, + Hook, + XWorker, + assign, + dedent, + define, + defineProperty, + dispatch, + queryTarget, + unescape, + whenDefined, +} from "polyscript/exports"; -// TODO: this is not strictly polyscript related but handy ... not sure -// we should factor this utility out a part but this works anyway. -import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; -import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; - -import { robustFetch as fetch } from "./fetch.js"; - -const { defineProperty } = Object; - -const getText = (body) => body.text(); +import "./all-done.js"; +import TYPES from "./types.js"; +import configs from "./config.js"; +import sync from "./sync.js"; +import bootstrapNodeAndPlugins from "./plugins-helper.js"; +import { ErrorCode } from "./exceptions.js"; +import { robustFetch as fetch, getText } from "./fetch.js"; +import { hooks, main, worker, codeFor, createFunction } from "./hooks.js"; // allows lazy element features on code evaluation let currentElement; -// create a unique identifier when/if needed -let id = 0; -const getID = (prefix = "py") => `${prefix}-${id++}`; - -// find the shared config for all py-script elements -let config; -let pyConfig = $("py-config"); -if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent; -else { - pyConfig = $('script[type="py"]'); - config = pyConfig?.getAttribute("config"); -} - -if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText); - // generic helper to disambiguate between custom element and script -const isScript = (element) => element.tagName === "SCRIPT"; - -// helper for all script[type="py"] out there -const before = (script) => { - defineProperty(document, "currentScript", { - configurable: true, - get: () => script, - }); -}; - -const after = () => { - delete document.currentScript; -}; - -/** - * Given a generic DOM Element, tries to fetch the 'src' attribute, if present. - * It either throws an error if the 'src' can't be fetched or it returns a fallback - * content as source. - */ -const fetchSource = async (tag, io) => { - if (tag.hasAttribute("src")) { - try { - return await fetch(tag.getAttribute("src")).then(getText); - } catch (error) { - io.stderr(error); - } - } - return tag.textContent; -}; - -// common life-cycle handlers for any node -const bootstrapNodeAndPlugins = (pyodide, element, callback, hook) => { - if (isScript(element)) callback(element); - for (const fn of hooks[hook]) fn(pyodide, element); -}; +const isScript = ({ tagName }) => tagName === "SCRIPT"; +let shouldRegister = true; const registerModule = ({ XWorker: $XWorker, interpreter, io }) => { // automatically use the pyscript stderr (when/if defined) // this defaults to console.error @@ -79,161 +41,275 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => { worker.onerror = ({ error }) => io.stderr(error); return worker; } - // trap once the python `display` utility (borrowed from "classic PyScript") - // provide the regular Pyodide globals instead of those from xworker - const pyDisplay = interpreter.runPython( - [ - "import js", - "document=js.document", - "window=js", - display, - "display", - ].join("\n"), - ); - interpreter.registerJsModule("pyscript", { + + // enrich the Python env with some JS utility for main + interpreter.registerJsModule("_pyscript", { PyWorker, - document, - window, - // a getter to ensure if multiple scripts with same - // env (py) runs, their execution code will have the correct - // display reference with automatic target - get display() { - const id = isScript(currentElement) + get target() { + return isScript(currentElement) ? currentElement.target.id : currentElement.id; - - return (...args) => { - const last = args.at(-1); - let kw = { target: id, append: false }; - if ( - typeof last === "object" && - last && - ("target" in last || "append" in last) - ) - kw = { ...kw, ...args.pop() }; - pyDisplay.callKwargs(...args, kw); - }; }, }); }; -export const hooks = { - /** @type {Set} */ - onBeforeRun: new Set(), - /** @type {Set} */ - onBeforeRunAync: new Set(), - /** @type {Set} */ - onAfterRun: new Set(), - /** @type {Set} */ - onAfterRunAsync: new Set(), - /** @type {Set} */ - onInterpreterReady: new Set(), - - /** @type {Set} */ - codeBeforeRunWorker: new Set(), - /** @type {Set} */ - codeBeforeRunWorkerAsync: new Set(), - /** @type {Set} */ - codeAfterRunWorker: new Set(), - /** @type {Set} */ - codeAfterRunWorkerAsync: new Set(), -}; - -const workerPyScriptModule = [ - "from pyodide_js import FS", - `FS.writeFile('./pyscript.py', ${JSON.stringify( - [ - "import polyscript", - "document=polyscript.xworker.window.document", - "window=polyscript.xworker.window", - "sync=polyscript.xworker.sync", - display, - ].join("\n"), - )})`, -].join("\n"); - -const workerHooks = { - codeBeforeRunWorker: () => - [workerPyScriptModule, ...hooks.codeBeforeRunWorker].join("\n"), - codeBeforeRunWorkerAsync: () => - [workerPyScriptModule, ...hooks.codeBeforeRunWorkerAsync].join("\n"), - codeAfterRunWorker: () => [...hooks.codeAfterRunWorker].join("\n"), - codeAfterRunWorkerAsync: () => - [...hooks.codeAfterRunWorkerAsync].join("\n"), -}; - -// define the module as both ` + + + + + print(2) + + + print(3) + + + + print(5) + + + diff --git a/pyscript.core/test/async.html b/pyscript.core/test/async.html new file mode 100644 index 00000000..0e9801d1 --- /dev/null +++ b/pyscript.core/test/async.html @@ -0,0 +1,15 @@ + + + + + + + + + import asyncio + print('foo') + await asyncio.sleep(1) + print('bar') + + + diff --git a/pyscript.core/test/bad.toml b/pyscript.core/test/bad.toml new file mode 100644 index 00000000..b79b726d --- /dev/null +++ b/pyscript.core/test/bad.toml @@ -0,0 +1 @@ +files = [ diff --git a/pyscript.core/test/click.html b/pyscript.core/test/click.html new file mode 100644 index 00000000..576c87b9 --- /dev/null +++ b/pyscript.core/test/click.html @@ -0,0 +1,29 @@ + + + + + + PyScript Next Plugin Bug? + + + + + + + + +
+ + diff --git a/pyscript.core/test/combo.html b/pyscript.core/test/combo.html new file mode 100644 index 00000000..fc66a9f6 --- /dev/null +++ b/pyscript.core/test/combo.html @@ -0,0 +1,17 @@ + + + + + + PyScript Error + + + + [[fetch]] + files = ["a.py"] + + + + diff --git a/pyscript.core/test/config-url.html b/pyscript.core/test/config-url.html new file mode 100644 index 00000000..8d4c7251 --- /dev/null +++ b/pyscript.core/test/config-url.html @@ -0,0 +1,11 @@ + + + + + + PyScript Next Plugin + + + + + diff --git a/pyscript.core/test/config.html b/pyscript.core/test/config.html new file mode 100644 index 00000000..e9f0af02 --- /dev/null +++ b/pyscript.core/test/config.html @@ -0,0 +1,13 @@ + + + + + + PyScript Next Plugin + + + + files = [ + + + diff --git a/pyscript.core/test/create-element.html b/pyscript.core/test/create-element.html new file mode 100644 index 00000000..f8543606 --- /dev/null +++ b/pyscript.core/test/create-element.html @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/pyscript.core/test/dialog.html b/pyscript.core/test/dialog.html new file mode 100644 index 00000000..05c9736a --- /dev/null +++ b/pyscript.core/test/dialog.html @@ -0,0 +1,31 @@ + + + + + + PyScript Next + + + + + + + + Loading PyScript ... + + + diff --git a/pyscript.core/test/display.html b/pyscript.core/test/display.html new file mode 100644 index 00000000..f7ca53c7 --- /dev/null +++ b/pyscript.core/test/display.html @@ -0,0 +1,30 @@ + + + + + + PyScript Next + + + + + + +

hello 2

+ + + diff --git a/pyscript.core/test/error.html b/pyscript.core/test/error.html new file mode 100644 index 00000000..3b6850aa --- /dev/null +++ b/pyscript.core/test/error.html @@ -0,0 +1,23 @@ + + + + + + PyScript Next Plugin + + + + + print(4, 5, 6) + second() + + + print(4, 5, 6) + second() + + + + diff --git a/pyscript.core/test/error.js b/pyscript.core/test/error.js new file mode 100644 index 00000000..46a99a9d --- /dev/null +++ b/pyscript.core/test/error.js @@ -0,0 +1,39 @@ +// PyScript Error Plugin +import { hooks } from '@pyscript/core'; + +hooks.onBeforeRun.add(function override(pyScript) { + // be sure this override happens only once + hooks.onBeforeRun.delete(override); + + // trap generic `stderr` to propagate to it regardless + const { stderr } = pyScript.io; + + // override it with our own logic + pyScript.io.stderr = (...args) => { + // grab the message of the first argument (Error) + const [ { message } ] = args; + // show it + notify(message); + // still let other plugins or PyScript itself do the rest + return stderr(...args); + }; +}); + +// Error hook utilities + +// Custom function to show notifications +function notify(message) { + const div = document.createElement('div'); + div.textContent = message; + div.style.cssText = ` + border: 1px solid red; + background: #ffdddd; + color: black; + font-family: courier, monospace; + white-space: pre; + overflow-x: auto; + padding: 8px; + margin-top: 8px; + `; + document.body.append(div); +} diff --git a/pyscript.core/test/hooks.html b/pyscript.core/test/hooks.html new file mode 100644 index 00000000..b706a15d --- /dev/null +++ b/pyscript.core/test/hooks.html @@ -0,0 +1,60 @@ + + + + + + PyScript Next Plugin Bug? + + + + + + + + diff --git a/pyscript.core/test/html-decode.html b/pyscript.core/test/html-decode.html new file mode 100644 index 00000000..471ec382 --- /dev/null +++ b/pyscript.core/test/html-decode.html @@ -0,0 +1,35 @@ + + + + + + + + + import js; js.console.log(1<2, 1>2) + import js; js.console.log("
")
+ + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
+ import js; js.console.log(1<2, 1>2) + import js; js.console.log("
")
+ + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
+ + + diff --git a/pyscript.core/test/index.html b/pyscript.core/test/index.html index 40b56441..7c537c01 100644 --- a/pyscript.core/test/index.html +++ b/pyscript.core/test/index.html @@ -4,8 +4,11 @@ PyScript Next - - + + + + + + + + + + from pyscript import display + display("Hello", "M-PyScript Main 2", append=False) + + + from pyscript import display, document + display("Hello", "M-PyScript Worker", append=False) + document.documentElement.classList.add('worker') + + + diff --git a/pyscript.core/test/mpy.spec.js b/pyscript.core/test/mpy.spec.js new file mode 100644 index 00000000..7a69cee2 --- /dev/null +++ b/pyscript.core/test/mpy.spec.js @@ -0,0 +1,37 @@ +import { test, expect } from '@playwright/test'; + +test('MicroPython display', async ({ page }) => { + await page.goto('http://localhost:8080/test/mpy.html'); + await page.waitForSelector('html.done.worker'); + const body = await page.evaluate(() => document.body.innerText); + await expect(body.trim()).toBe([ + 'M-PyScript Main 1', + 'M-PyScript Main 2', + 'M-PyScript Worker', + ].join('\n')); +}); + +test('MicroPython hooks', async ({ page }) => { + const logs = []; + page.on('console', msg => { + const text = msg.text(); + if (!text.startsWith('[')) + logs.push(text); + }); + await page.goto('http://localhost:8080/test/hooks.html'); + await page.waitForSelector('html.done.worker'); + await expect(logs.join('\n')).toBe([ + 'main onReady', + 'main onBeforeRun', + 'main codeBeforeRun', + 'actual code in main', + 'main codeAfterRun', + 'main onAfterRun', + 'worker onReady', + 'worker onBeforeRun', + 'worker codeBeforeRun', + 'actual code in worker', + 'worker codeAfterRun', + 'worker onAfterRun', + ].join('\n')); +}); diff --git a/pyscript.core/test/no-error.html b/pyscript.core/test/no-error.html new file mode 100644 index 00000000..92e06f13 --- /dev/null +++ b/pyscript.core/test/no-error.html @@ -0,0 +1,23 @@ + + + + + + PyScript Next No Plugin + + + plugins = ['!error'] + + + print(4, 5, 6) + second() + + + print(4, 5, 6) + second() + + + diff --git a/pyscript.core/test/piratical.html b/pyscript.core/test/piratical.html new file mode 100644 index 00000000..317f5d8f --- /dev/null +++ b/pyscript.core/test/piratical.html @@ -0,0 +1,18 @@ + + + + + + Arrr - Piratical PyScript + + + + +

Arrr

+

Translate English into Pirate speak...

+ + +
+ + + diff --git a/pyscript.core/test/piratical.py b/pyscript.core/test/piratical.py new file mode 100644 index 00000000..82bef268 --- /dev/null +++ b/pyscript.core/test/piratical.py @@ -0,0 +1,9 @@ +import arrr +from js import document + + +def translate_english(event): + input_text = document.querySelector("#english") + english = input_text.value + output_div = document.querySelector("#output") + output_div.innerText = arrr.translate(english) diff --git a/pyscript.core/test/piratical.toml b/pyscript.core/test/piratical.toml new file mode 100644 index 00000000..cdebd8db --- /dev/null +++ b/pyscript.core/test/piratical.toml @@ -0,0 +1 @@ +packages = ["arrr"] diff --git a/pyscript.core/test/py-terminal.html b/pyscript.core/test/py-terminal.html new file mode 100644 index 00000000..9570c45b --- /dev/null +++ b/pyscript.core/test/py-terminal.html @@ -0,0 +1,29 @@ + + + + + + PyTerminal + + + + + + + + import sys + from pyscript import display, document + display("Hello", "PyScript Next - PyTerminal", append=False) + print("this should go to the terminal") + print("another line") + + # this works as expected + print("this goes to stderr", file=sys.stderr) + document.addEventListener('click', lambda event: print(event.type)); + + + + diff --git a/pyscript.core/test/pydom.html b/pyscript.core/test/pydom.html new file mode 100644 index 00000000..ff647381 --- /dev/null +++ b/pyscript.core/test/pydom.html @@ -0,0 +1,19 @@ + + + + + + PyScript Next Plugin + + + + + + + + + + +
+ + diff --git a/pyscript.core/test/pydom.py b/pyscript.core/test/pydom.py new file mode 100644 index 00000000..e251b8b4 --- /dev/null +++ b/pyscript.core/test/pydom.py @@ -0,0 +1,27 @@ +import random +from datetime import datetime as dt + +from pyscript import display +from pyweb import pydom +from pyweb.base import when + + +@when("click", "#just-a-button") +def on_click(event): + print(f"Hello from Python! {dt.now()}") + display(f"Hello from Python! {dt.now()}", append=False, target="result") + + +@when("click", "#color-button") +def on_color_click(event): + print("1") + btn = pydom["#result"] + print("2") + btn.style["background-color"] = f"#{random.randrange(0x1000000):06x}" + + +def reset_color(): + pydom["#result"].style["background-color"] = "white" + + +# btn_reset = pydom["#color-reset-button"][0].when('click', reset_color) diff --git a/pyscript.core/test/pyscript_dom/index.html b/pyscript.core/test/pyscript_dom/index.html new file mode 100644 index 00000000..80f684d5 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/index.html @@ -0,0 +1,110 @@ + + + PyperCard PyTest Suite + + + + + + + + + + +

pyscript.dom Tests

+

You can pass test parameters to this test suite by passing them as query params on the url. + For instance, to pass "-v -s --pdb" to pytest, you would use the following url: + +

+
+ + + + + + + +
+ +
+

Test Read and Write

+
Content test_rr_div
+

Content test_rr_h3

+ +
Content multi-elem-div
+

Content multi-elem-p

+

Content multi-elem-h2

+ +
+ + + + +
+ +
+ + + + + +
+

+
+

+
+ + + + + diff --git a/pyscript.core/test/pyscript_dom/run_tests.py b/pyscript.core/test/pyscript_dom/run_tests.py new file mode 100644 index 00000000..128abccc --- /dev/null +++ b/pyscript.core/test/pyscript_dom/run_tests.py @@ -0,0 +1,7 @@ +print("tests starting") +import pytest +from pyscript import window + +args = window.location.search.replace("?", "").split("&") + +pytest.main(args) diff --git a/pyscript.core/test/pyscript_dom/tests.toml b/pyscript.core/test/pyscript_dom/tests.toml new file mode 100644 index 00000000..6bcee173 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests.toml @@ -0,0 +1,8 @@ +packages = [ + "pytest" +] + +[[fetch]] +from = "tests/" +files = ["__init__.py", "conftest.py", "test_dom.py"] +to_folder = "tests" diff --git a/pyscriptjs/tests/integration/__init__.py b/pyscript.core/test/pyscript_dom/tests/__init__.py similarity index 100% rename from pyscriptjs/tests/integration/__init__.py rename to pyscript.core/test/pyscript_dom/tests/__init__.py diff --git a/pyscript.core/test/pyscript_dom/tests/conftest.py b/pyscript.core/test/pyscript_dom/tests/conftest.py new file mode 100644 index 00000000..4ba26c05 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest +from js import document, localStorage + + +@pytest.fixture(autouse=True) +def before_tests(): + """ + Ensure browser storage is always reset to empty. Remove the app + placeholder. Reset the page title. + """ + localStorage.clear() + # app_placeholder = document.querySelector("pyper-app") + # if app_placeholder: + # app_placeholder.remove() + document.querySelector("title").innerText = "Web API PyTest Suite" diff --git a/pyscript.core/test/pyscript_dom/tests/test_dom.py b/pyscript.core/test/pyscript_dom/tests/test_dom.py new file mode 100644 index 00000000..c55d20e1 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests/test_dom.py @@ -0,0 +1,294 @@ +from unittest import mock + +import pytest +from pyscript import document, when +from pyweb import pydom + + +class TestDocument: + def test__element(self): + assert pydom._js == document + + def test_no_parent(self): + assert pydom.parent is None + + def test_create_element(self): + new_el = pydom.create("div") + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "DIV" + # EXPECT the new element to be associated with the document + assert new_el.parent == None + + +def test_getitem_by_id(): + # GIVEN an existing element on the page with a known text content + id_ = "test_id_selector" + txt = "You found test_id_selector" + selector = f"#{id_}" + # EXPECT the element to be found by id + result = pydom[selector] + div = result[0] + # EXPECT the element text value to match what we expect and what + # the JS document.querySelector API would return + assert document.querySelector(selector).innerHTML == div.html == txt + # EXPECT the results to be of the right types + assert isinstance(div, pydom.BaseElement) + assert isinstance(result, pydom.ElementCollection) + + +def test_getitem_by_class(): + ids = [ + "test_class_selector", + "test_selector_w_children", + "test_selector_w_children_child_1", + ] + expected_class = "a-test-class" + result = pydom[f".{expected_class}"] + div = result[0] + + # EXPECT to find exact number of elements with the class in the page (== 3) + assert len(result) == 3 + + # EXPECT that all element ids are in the expected list + assert [el.id for el in result] == ids + + +def test_read_n_write_collection_elements(): + elements = pydom[".multi-elems"] + + for element in elements: + assert element.html == f"Content {element.id.replace('#', '')}" + + new_content = "New Content" + elements.html = new_content + for element in elements: + assert element.html == new_content + + +class TestElement: + def test_query(self): + # GIVEN an existing element on the page, with at least 1 child element + id_ = "test_selector_w_children" + parent_div = pydom[f"#{id_}"][0] + + # EXPECT it to be able to query for the first child element + div = parent_div.find("div")[0] + + # EXPECT the new element to be associated with the parent + assert div.parent == parent_div + # EXPECT the new element to be a BaseElement + assert isinstance(div, pydom.BaseElement) + # EXPECT the div attributes to be == to how they are configured in the page + assert div.html == "Child 1" + assert div.id == "test_selector_w_children_child_1" + + def test_equality(self): + # GIVEN 2 different Elements pointing to the same underlying element + id_ = "test_id_selector" + selector = f"#{id_}" + div = pydom[selector][0] + div2 = pydom[selector][0] + + # EXPECT them to be equal + assert div == div2 + # EXPECT them to be different objects + assert div is not div2 + + # EXPECT their value to always be equal + assert div.html == div2.html + div.html = "some value" + + assert div.html == div2.html == "some value" + + def test_append_element(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + new_el = div.create("p") + div.append(new_el) + assert len(div.children) == len_children_before + 1 + assert div.children[-1] == new_el + + def test_append_js_element(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + new_el = div.create("p") + div.append(new_el._js) + assert len(div.children) == len_children_before + 1 + assert div.children[-1] == new_el + + def test_append_collection(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + collection = pydom[".collection"] + div.append(collection) + assert len(div.children) == len_children_before + len(collection) + + for i in range(len(collection)): + assert div.children[-1 - i] == collection[-1 - i] + + def test_read_classes(self): + id_ = "test_class_selector" + expected_class = "a-test-class" + div = pydom[f"#{id_}"][0] + assert div.classes == [expected_class] + + def test_add_remove_class(self): + id_ = "div-no-classes" + classname = "tester-class" + div = pydom[f"#{id_}"][0] + assert not div.classes + div.add_class(classname) + same_div = pydom[f"#{id_}"][0] + assert div.classes == [classname] == same_div.classes + div.remove_class(classname) + assert div.classes == [] == same_div.classes + + def test_when_decorator(self): + called = False + + just_a_button = pydom["#a-test-button"][0] + + @when("click", just_a_button) + def on_click(event): + nonlocal called + called = True + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk pydom getting in the way + assert not called + just_a_button._js.click() + + assert called + + +class TestCollection: + def test_iter_eq_children(self): + elements = pydom[".multi-elems"] + assert [el for el in elements] == [el for el in elements.children] + assert len(elements) == 3 + + def test_slices(self): + elements = pydom[".multi-elems"] + assert elements[0] + _slice = elements[:2] + assert len(_slice) == 2 + for i, el in enumerate(_slice): + assert el == elements[i] + assert elements[:] == elements + + def test_style_rule(self): + selector = ".multi-elems" + elements = pydom[selector] + for el in elements: + assert el.style["background-color"] != "red" + + elements.style["background-color"] = "red" + + for i, el in enumerate(pydom[selector]): + assert elements[i].style["background-color"] == "red" + assert el.style["background-color"] == "red" + + elements.style.remove("background-color") + + for i, el in enumerate(pydom[selector]): + assert el.style["background-color"] != "red" + assert elements[i].style["background-color"] != "red" + + def test_when_decorator(self): + called = False + + buttons_collection = pydom["button"] + + @when("click", buttons_collection) + def on_click(event): + nonlocal called + called = True + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk pydom getting in the way + assert not called + for button in buttons_collection: + button._js.click() + assert called + called = False + + +class TestCreation: + def test_create_document_element(self): + new_el = pydom.create("div") + new_el.id = "new_el_id" + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "DIV" + # EXPECT the new element to be associated with the document + assert new_el.parent == None + pydom.body.append(new_el) + + assert pydom["#new_el_id"][0].parent == pydom.body + + def test_create_element_child(self): + selector = "#element-creation-test" + parent_div = pydom[selector][0] + + # Creating an element from another element automatically creates that element + # as a child of the original element + new_el = parent_div.create( + "p", classes=["code-description"], html="Ciao PyScripters!" + ) + + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "P" + # EXPECT the new element to be associated with the document + assert new_el.parent == parent_div + + assert pydom[selector][0].children[0] == new_el + + +class TestInput: + input_ids = [ + "test_rr_input_text", + "test_rr_input_button", + "test_rr_input_email", + "test_rr_input_password", + ] + + def test_value(self): + for id_ in self.input_ids: + expected_type = id_.split("_")[-1] + result = pydom[f"#{id_}"] + input_el = result[0] + assert input_el._js.type == expected_type + assert input_el.value == f"Content {id_}" == input_el._js.value + + # Check that we can set the value + new_value = f"New Value {expected_type}" + input_el.value = new_value + assert input_el.value == new_value + + # Check that we can set the value back to the original using + # the collection + new_value = f"Content {id_}" + result.value = new_value + assert input_el.value == new_value + + def test_set_value_collection(self): + for id_ in self.input_ids: + input_el = pydom[f"#{id_}"] + + assert input_el.value[0] == f"Content {id_}" == input_el[0].value + + new_value = f"New Value {id_}" + input_el.value = new_value + assert input_el.value[0] == new_value == input_el[0].value + + def test_element_without_value(self): + result = pydom[f"#tests-terminal"][0] + with pytest.raises(AttributeError): + result.value = "some value" + + def test_element_without_collection(self): + result = pydom[f"#tests-terminal"] + with pytest.raises(AttributeError): + result.value = "some value" diff --git a/pyscript.core/test/split-config.html b/pyscript.core/test/split-config.html new file mode 100644 index 00000000..434426bc --- /dev/null +++ b/pyscript.core/test/split-config.html @@ -0,0 +1,20 @@ + + + + + + PyScript Config + + + + [[fetch]] + files = ["a.py"] + + + + diff --git a/pyscript.core/test/target.html b/pyscript.core/test/target.html new file mode 100644 index 00000000..90703d60 --- /dev/null +++ b/pyscript.core/test/target.html @@ -0,0 +1,37 @@ + + + + + + @pyscript/core + + + + + + import pyscript + from pyscript import display + display("Hello", append=True) # Appears in a DIV that is a child of this py-script tag + pyscript.display("same", append=True) # Appears in another DIV that is a child of this py-script tag + + + # Appears in a DIV that is a child of this py-script tag, no need to re-import + display("World", append=True) + + + # Appears in a DIV that is a child of this py-script tag + # Re-importing has no effect in the essential behavior + from pyscript import display + display("A part", append=True) + + + # Use the 'target' element to specify the ID of an element in the DOM to write the content to + display("!", target="first", append=True) + + + # Appears in a DIV that is a child of this py-script tag, even with the code running in a worker + from pyscript import display + display("worker", append=True) + + + diff --git a/pyscript.core/test/test_display_HTML.html b/pyscript.core/test/test_display_HTML.html new file mode 100644 index 00000000..ffd44a70 --- /dev/null +++ b/pyscript.core/test/test_display_HTML.html @@ -0,0 +1,16 @@ + + + + + + PyScript Next: Display HTML + + + + + + from pyscript import display, HTML + display(HTML('

world

')) +
+ + diff --git a/pyscript.core/test/test_when.html b/pyscript.core/test/test_when.html new file mode 100644 index 00000000..84d9b7ee --- /dev/null +++ b/pyscript.core/test/test_when.html @@ -0,0 +1,24 @@ + + + + + + PyScript Next: When Decorator + + + + +

Click for a hi!

+ + + from pyscript import window, when + @when("click", selector="#say-hi") + + def say_hi(event): + window.alert("Hi! 🤗") + + + + + + diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 6b8e6cb9..0258328c 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -4,18 +4,20 @@ PyScript Next - + - + + + + {extra_head} - {py_config_maybe} {snippet} @@ -515,7 +545,9 @@ class PyScriptTest: - wait until pyscript has been fully loaded """ doc = self._pyscript_format( - snippet, execution_thread=self.execution_thread, extra_head=extra_head + snippet, + execution_thread=self.execution_thread, + extra_head=extra_head, ) if not wait_for_pyscript and timeout is not None: raise ValueError("Cannot set a timeout if wait_for_pyscript=False") @@ -550,7 +582,7 @@ class PyScriptTest: Ensure that there is an alert banner on the page with the given message. Currently it only handles a single. """ - banner = self.page.wait_for_selector(".alert-banner") + banner = self.page.wait_for_selector(".py-error") banner_text = banner.inner_text() if expected_message not in banner_text: @@ -636,7 +668,7 @@ TEST_ITERATIONS = math.ceil( ) # 120 iters of 1/4 second -def wait_for_render(page, selector, pattern, timeout_seconds: int | None = None): +def wait_for_render(page, selector, pattern, timeout_seconds=None): """ Assert that rendering inserts data into the page as expected: search the DOM from within the timing loop for a string that is not present in the diff --git a/pyscriptjs/tests/integration/test_00_support.py b/pyscript.core/tests/integration/test_00_support.py similarity index 95% rename from pyscriptjs/tests/integration/test_00_support.py rename to pyscript.core/tests/integration/test_00_support.py index 7e164ae0..f3500a65 100644 --- a/pyscriptjs/tests/integration/test_00_support.py +++ b/pyscript.core/tests/integration/test_00_support.py @@ -474,22 +474,3 @@ class TestSupport(PyScriptTest): assert [ "Failed to load resource: the server responded with a status of 404 (Not Found)" ] == self.console.all.lines - - def test__pyscript_format_inject_execution_thread(self): - """ - This is slightly different than other tests: it doesn't use playwright, it - just tests that our own internal helper works - """ - doc = self._pyscript_format("Hello", execution_thread="main") - cfg = self._parse_py_config(doc) - assert cfg == {"execution_thread": "main"} - - def test__pyscript_format_modify_existing_py_config(self): - src = """ - - hello = 42 - - """ - doc = self._pyscript_format(src, execution_thread="main") - cfg = self._parse_py_config(doc) - assert cfg == {"execution_thread": "main", "hello": 42} diff --git a/pyscriptjs/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py similarity index 61% rename from pyscriptjs/tests/integration/test_01_basic.py rename to pyscript.core/tests/integration/test_01_basic.py index 1170adc7..ffedcc34 100644 --- a/pyscriptjs/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -2,47 +2,76 @@ import re import pytest -from .support import PyScriptTest, skip_worker +from .support import PyScriptTest, only_main, skip_worker class TestBasic(PyScriptTest): - def test_pyscript_hello(self): + def test_pyscript_exports(self): + self.pyscript_run( + """ + + """ + ) + assert self.console.error.lines == [] + + def test_script_py_hello(self): self.pyscript_run( """ """ ) - assert self.console.log.lines == ["hello pyscript"] + assert self.console.log.lines == ["hello from script py"] + + def test_py_script_hello(self): + self.pyscript_run( + """ + + import js + js.console.log('hello from py-script') + + """ + ) + assert self.console.log.lines == ["hello from py-script"] def test_execution_thread(self): self.pyscript_run( """ - - """ + + """, ) assert self.execution_thread in ("main", "worker") - if self.execution_thread == "main": - where = "the main thread" - elif self.execution_thread == "worker": - where = "a web worker" - expected = f"[pyscript/main] Starting the interpreter in {where}" - assert expected in self.console.info.lines + in_worker = self.execution_thread == "worker" + in_worker = str(in_worker).lower() + assert self.console.log.lines[-1] == f"worker? {in_worker}" + @skip_worker("NEXT: it should show a nice error on the page") def test_no_cors_headers(self): self.disable_cors_headers() self.pyscript_run( """ - + """, wait_for_pyscript=False, ) assert self.headers == {} - if self.execution_thread == "worker": + if self.execution_thread == "main": + self.wait_for_pyscript() + assert self.console.log.lines == ["hello"] + self.assert_no_banners() + else: + # XXX adapt and fix the test expected_alert_banner_msg = ( '(PY1000): When execution_thread is "worker", the site must be cross origin ' "isolated, but crossOriginIsolated is false. To be cross origin isolated, " @@ -51,56 +80,50 @@ class TestBasic(PyScriptTest): '"Cross-Origin-Opener-Policy":"same-origin"}. ' "The problem may be that one or both of these are missing." ) - alert_banner = self.page.wait_for_selector(".alert-banner") + alert_banner = self.page.wait_for_selector(".py-error") assert expected_alert_banner_msg in alert_banner.inner_text() - else: - self.assert_no_banners() def test_print(self): self.pyscript_run( """ - + """ ) assert self.console.log.lines[-1] == "hello pyscript" + @skip_worker("NEXT: exceptions should be displayed in the DOM") def test_python_exception(self): self.pyscript_run( """ - + """ ) assert "hello pyscript" in self.console.log.lines self.check_py_errors("Exception: this is an error") # - # check that we sent the traceback to the console - tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" - assert tb_lines[-1] == "Exception: this is an error" - # # check that we show the traceback in the page. Note that here we # display the "raw" python traceback, without the "[pyexec] Python # exception:" line (which is useful in the console, but not for the # user) - pre = self.page.locator("py-script > pre") - tb_lines = pre.inner_text().splitlines() + banner = self.page.locator(".py-error") + tb_lines = banner.inner_text().splitlines() assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error" + @skip_worker("NEXT: py-click doesn't work inside workers") def test_python_exception_in_event_handler(self): self.pyscript_run( """ - - - def onclick(): + + """ ) @@ -111,28 +134,23 @@ class TestBasic(PyScriptTest): self.check_py_errors("Exception: this is an error inside handler") - ## error in console - tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" - assert tb_lines[-1] == "Exception: this is an error inside handler" - ## error in DOM tb_lines = self.page.locator(".py-error").inner_text().splitlines() assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error inside handler" + @only_main def test_execution_in_order(self): """ - Check that they py-script tags are executed in the same order they are + Check that they script py tags are executed in the same order they are defined """ self.pyscript_run( """ - import js; js.console.log('one') - js.console.log('two') - js.console.log('three') - js.console.log('four') + + + + """ ) assert self.console.log.lines[-4:] == [ @@ -144,30 +162,43 @@ class TestBasic(PyScriptTest): def test_escaping_of_angle_brackets(self): """ - Check that py-script tags escape angle brackets + Check that script tags escape angle brackets """ self.pyscript_run( """ - import js; js.console.log(1<2, 1>2) - js.console.log("
")
+ + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
""" ) - - assert self.console.log.lines[-2:] == ["true false", "
"] + # in workers the order of execution is not guaranteed, better to play + # safe + lines = sorted(self.console.log.lines[-4:]) + assert lines == [ + "A true false", + "B
", + "C true false", + "D
", + ] def test_packages(self): self.pyscript_run( """ - # we use asciitree because it's one of the smallest packages - # which are built and distributed with pyodide packages = ["asciitree"] - + """ ) @@ -177,13 +208,16 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] - @skip_worker("FIXME: the banner doesn't appear") + @pytest.mark.skip("NEXT: No banner") def test_non_existent_package(self): self.pyscript_run( """ packages = ["i-dont-exist"] + """, wait_for_pyscript=False, ) @@ -198,13 +232,16 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") - @skip_worker("FIXME: the banner doesn't appear") + @pytest.mark.skip("NEXT: No banner") def test_no_python_wheel(self): self.pyscript_run( """ packages = ["opsdroid"] + """, wait_for_pyscript=False, ) @@ -218,56 +255,56 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't find a pure Python 3 wheel for 'opsdroid'") + @only_main def test_dynamically_add_py_script_tag(self): self.pyscript_run( """ - - """ + """, + timeout=20000, ) - self.page.locator("button").click() + self.page.locator("py-script") - self.page.wait_for_selector("py-terminal") assert self.console.log.lines[-1] == "hello world" def test_py_script_src_attribute(self): self.writefile("foo.py", "print('hello from foo')") self.pyscript_run( """ - + """ ) assert self.console.log.lines[-1] == "hello from foo" + @skip_worker("NEXT: banner not shown") def test_py_script_src_not_found(self): self.pyscript_run( """ - + """, check_js_errors=False, ) assert "Failed to load resource" in self.console.error.lines[0] + # TODO: we need to be sure errors make sense from both main and worker worlds expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404" - assert any((expected_msg in line) for line in self.console.js_error.lines) + assert any((expected_msg in line) for line in self.console.error.lines) assert self.assert_banner_message(expected_msg) - pyscript_tag = self.page.locator("py-script") - assert pyscript_tag.inner_html() == "" - - self.check_js_errors(expected_msg) - + # TODO: ... and we shouldn't: it's a module and we better don't leak in global + @pytest.mark.skip("NEXT: we don't expose pyscript on window") def test_js_version(self): self.pyscript_run( """ - - + """ ) self.page.add_script_tag(content="console.log(pyscript.version)") @@ -277,14 +314,16 @@ class TestBasic(PyScriptTest): is not None ) + # TODO: ... and we shouldn't: it's a module and we better don't leak in global + @pytest.mark.skip("NEXT: we don't expose pyscript on window") def test_python_version(self): self.pyscript_run( """ - + """ ) assert ( @@ -300,47 +339,35 @@ class TestBasic(PyScriptTest): is not None ) - @skip_worker("FIXME: showWarning()") - def test_assert_no_banners(self): - """ - Test that the DOM doesn't contain error/warning banners - """ - self.pyscript_run( - """ - - from _pyscript_js import showWarning - showWarning("hello") - showWarning("world") - - """ - ) - with pytest.raises(AssertionError, match="Found 2 alert banners"): - self.assert_no_banners() - + @pytest.mark.skip("NEXT: works with not with """ ) - pyscript_tag = self.page.locator("py-script") assert pyscript_tag.inner_html() == "" assert ( - pyscript_tag.evaluate("node => node.getPySrc()") - == 'print("hello world!")\n' + pyscript_tag.evaluate("node => node.srcCode") + == 'print("hello from py-script")' + ) + script_py_tag = self.page.locator('script[type="py"]') + assert ( + script_py_tag.evaluate("node => node.srcCode") + == 'print("hello from script py")' ) + @skip_worker("NEXT: py-click doesn't work inside workers") def test_py_attribute_without_id(self): self.pyscript_run( """ - - - def myfunc(): + + """ ) btn = self.page.wait_for_selector("button") @@ -349,16 +376,16 @@ class TestBasic(PyScriptTest): assert self.console.log.lines[-1] == "hello world!" assert self.console.error.lines == [] - def test_py_mount_shows_deprecation_warning(self): - # last non-deprecated version: 2023.03.1 + def test_py_all_done_event(self): self.pyscript_run( """ -
+ + """ ) - banner = self.page.locator(".alert-banner") - expected_message = ( - 'The "py-mount" attribute is deprecated. ' - + "Please add references to HTML Elements manually in your script." - ) - assert banner.inner_text() == expected_message + assert self.console.log.lines == ["1", "2"] + assert self.console.error.lines == [] diff --git a/pyscript.core/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py new file mode 100644 index 00000000..1ea60330 --- /dev/null +++ b/pyscript.core/tests/integration/test_02_display.py @@ -0,0 +1,526 @@ +################################################################################ + +import base64 +import html +import io +import os +import re + +import numpy as np +import pytest +from PIL import Image + +from .support import ( + PageErrors, + PyScriptTest, + filter_inner_text, + filter_page_content, + only_main, + skip_worker, + wait_for_render, +) + +DISPLAY_OUTPUT_ID_PATTERN = r'script-py[id^="py-"]' + + +class TestDisplay(PyScriptTest): + def test_simple_display(self): + self.pyscript_run( + """ + + """, + timeout=20000, + ) + node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) + pattern = r"
hello world
" + assert node_list[0].inner_html() == pattern + assert len(node_list) == 1 + + def test_consecutive_display(self): + self.pyscript_run( + """ + +

hello 2

+ + """ + ) + inner_text = self.page.inner_text("body") + lines = inner_text.splitlines() + + lines = [line for line in filter_page_content(lines)] # remove empty lines + assert lines == ["hello 1", "hello 2", "hello 3"] + + def test_target_parameter(self): + self.pyscript_run( + """ + +
+ """ + ) + mydiv = self.page.locator("#mydiv") + assert mydiv.inner_text() == "hello world" + + def test_target_parameter_with_sharp(self): + self.pyscript_run( + """ + +
+ """ + ) + mydiv = self.page.locator("#mydiv") + assert mydiv.inner_text() == "hello world" + + def test_non_existing_id_target_raises_value_error(self): + self.pyscript_run( + """ + + """ + ) + error_msg = ( + f"Invalid selector with id=non-existing. Cannot be found in the page." + ) + self.check_py_errors(f"ValueError: {error_msg}") + + def test_empty_string_target_raises_value_error(self): + self.pyscript_run( + """ + + """ + ) + self.check_py_errors(f"ValueError: Cannot have an empty target") + + def test_non_string_target_values_raise_typerror(self): + self.pyscript_run( + """ + + """ + ) + error_msg = f"target must be str or None, not bool" + self.check_py_errors(f"TypeError: {error_msg}") + + self.pyscript_run( + """ + + """ + ) + error_msg = f"target must be str or None, not int" + self.check_py_errors(f"TypeError: {error_msg}") + + @skip_worker("NEXT: display(target=...) does not work") + def test_tag_target_attribute(self): + self.pyscript_run( + """ + +
+
+ """ + ) + hello = self.page.locator("#hello") + assert hello.inner_text() == "hello\nworld" + + goodbye = self.page.locator("#goodbye") + assert goodbye.inner_text() == "goodbye world" + + @skip_worker("NEXT: display target does not work properly") + def test_target_script_py(self): + self.pyscript_run( + """ +
ONE
+ +
THREE
+ + + """ + ) + text = self.page.inner_text("body") + assert text == "ONE\nTWO\nTHREE" + + @skip_worker("NEXT: display target does not work properly") + def test_consecutive_display_target(self): + self.pyscript_run( + """ + +

hello in between 1 and 2

+ + + """ + ) + inner_text = self.page.inner_text("body") + lines = inner_text.splitlines() + lines = [line for line in filter_page_content(lines)] # remove empty lines + assert lines == ["hello 1", "hello in between 1 and 2", "hello 2", "hello 3"] + + def test_multiple_display_calls_same_tag(self): + self.pyscript_run( + """ + + """ + ) + tag = self.page.locator("script-py") + lines = tag.inner_text().splitlines() + assert lines == ["hello", "world"] + + @only_main # with workers, two tags are two separate interpreters + def test_implicit_target_from_a_different_tag(self): + self.pyscript_run( + """ + + + + """ + ) + elems = self.page.locator("script-py") + py0 = elems.nth(0) + py1 = elems.nth(1) + assert py0.inner_text() == "" + assert py1.inner_text() == "hello" + + @skip_worker("NEXT: py-click doesn't work") + def test_no_explicit_target(self): + self.pyscript_run( + """ + + + """ + ) + self.page.locator("button").click() + + text = self.page.locator("script-py").text_content() + assert "hello world" in text + + @skip_worker("NEXT: display target does not work properly") + def test_explicit_target_pyscript_tag(self): + self.pyscript_run( + """ + + + """ + ) + text = self.page.locator("script-py").nth(1).inner_text() + assert text == "hello" + + @skip_worker("NEXT: display target does not work properly") + def test_explicit_target_on_button_tag(self): + self.pyscript_run( + """ + + + """ + ) + self.page.locator("text=Click me").click() + text = self.page.locator("id=my-button").inner_text() + assert "hello" in text + + def test_append_true(self): + self.pyscript_run( + """ + + """ + ) + output = self.page.locator("script-py") + assert output.inner_text() == "AAA\nBBB" + + def test_append_false(self): + self.pyscript_run( + """ + + """ + ) + output = self.page.locator("script-py") + assert output.inner_text() == "BBB" + + def test_display_multiple_values(self): + self.pyscript_run( + """ + + """ + ) + output = self.page.locator("script-py") + assert output.inner_text() == "hello\nworld" + + def test_display_multiple_append_false(self): + self.pyscript_run( + """ + + """ + ) + output = self.page.locator("script-py") + assert output.inner_text() == "world" + + # TODO: this is a display.py issue to fix when append=False is used + # do not use the first element, just clean up and then append + # remove the # display comment once that's done + def test_display_multiple_append_false_with_target(self): + self.pyscript_run( + """ +
+ + """ + ) + innerhtml = self.page.locator("id=circle-div").inner_html() + assert ( + innerhtml + == '' # noqa: E501 + ) + assert self.console.error.lines == [] + + def test_display_list_dict_tuple(self): + self.pyscript_run( + """ + + """ + ) + inner_text = self.page.inner_text("html") + filtered_inner_text = filter_inner_text(inner_text) + print(filtered_inner_text) + assert ( + filtered_inner_text + == "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')" + ) + + def test_display_should_escape(self): + self.pyscript_run( + """ + + """ + ) + out = self.page.locator("script-py > div") + assert out.inner_html() == html.escape("

hello world

") + assert out.inner_text() == "

hello world

" + + def test_display_HTML(self): + self.pyscript_run( + """ + + """ + ) + out = self.page.locator("script-py > div") + assert out.inner_html() == "

hello world

" + assert out.inner_text() == "hello world" + + @skip_worker("NEXT: matplotlib-pyodide backend does not work") + def test_image_display(self): + self.pyscript_run( + """ + packages = ["matplotlib"] + + """, + timeout=30 * 1000, + ) + wait_for_render(self.page, "*", " + from pyscript import display + import js + print('print from python') + js.console.log('print from js') + js.console.error('error from js'); + + """ + ) + inner_html = self.page.content() + assert re.search("", inner_html) + console_text = self.console.all.lines + assert "print from python" in console_text + assert "print from js" in console_text + assert "error from js" in console_text + + def test_text_HTML_and_console_output(self): + self.pyscript_run( + """ + + """ + ) + inner_text = self.page.inner_text("script-py") + assert inner_text == "this goes to the DOM" + assert self.console.log.lines[-2:] == [ + "print from python", + "print from js", + ] + print(self.console.error.lines) + assert self.console.error.lines[-1] == "error from js" + + def test_console_line_break(self): + self.pyscript_run( + """ + + """ + ) + console_text = self.console.all.lines + assert console_text.index("1print") == (console_text.index("2print") - 1) + assert console_text.index("1console") == (console_text.index("2console") - 1) + + @skip_worker("NEXT: display target does not work properly") + def test_image_renders_correctly(self): + """ + This is just a sanity check to make sure that images are rendered + in a reasonable way. + """ + self.pyscript_run( + """ + + packages = ["pillow"] + + +
+ + """, + ) + + img_src = self.page.locator("img").get_attribute("src") + assert img_src.startswith("data:image/png;charset=utf-8;base64") diff --git a/pyscriptjs/tests/integration/test_assets/line_plot.png b/pyscript.core/tests/integration/test_assets/line_plot.png similarity index 100% rename from pyscriptjs/tests/integration/test_assets/line_plot.png rename to pyscript.core/tests/integration/test_assets/line_plot.png diff --git a/pyscriptjs/tests/integration/test_assets/tripcolor.png b/pyscript.core/tests/integration/test_assets/tripcolor.png similarity index 100% rename from pyscriptjs/tests/integration/test_assets/tripcolor.png rename to pyscript.core/tests/integration/test_assets/tripcolor.png diff --git a/pyscriptjs/tests/integration/test_async.py b/pyscript.core/tests/integration/test_async.py similarity index 79% rename from pyscriptjs/tests/integration/test_async.py rename to pyscript.core/tests/integration/test_async.py index 78daf0aa..8c265a59 100644 --- a/pyscriptjs/tests/integration/test_async.py +++ b/pyscript.core/tests/integration/test_async.py @@ -1,11 +1,13 @@ -from .support import PyScriptTest, skip_worker +import pytest + +from .support import PyScriptTest, filter_inner_text, only_main class TestAsync(PyScriptTest): # ensure_future() and create_task() should behave similarly; # we'll use the same source code to test both coroutine_script = """ - + """ def test_asyncio_ensure_future(self): @@ -30,7 +32,7 @@ class TestAsync(PyScriptTest): def test_asyncio_gather(self): self.pyscript_run( """ - + """ ) self.wait_for_console("DONE") assert self.console.log.lines[-2:] == ["[3, 2, 1]", "DONE"] + @only_main def test_multiple_async(self): self.pyscript_run( """ - + - + """ ) self.wait_for_console("b func done") @@ -87,70 +90,69 @@ class TestAsync(PyScriptTest): "b func done", ] - @skip_worker("FIXME: display()") + @only_main def test_multiple_async_multiple_display_targeted(self): self.pyscript_run( """ - + + + """ ) self.wait_for_console("B DONE") inner_text = self.page.inner_text("html") - assert "A0\nA1\nB0\nB1" in inner_text + assert "A0\nA1\nB0\nB1" in filter_inner_text(inner_text) - @skip_worker("FIXME: display()") def test_async_display_untargeted(self): self.pyscript_run( """ - + """ ) self.wait_for_console("DONE") - assert ( - self.console.error.lines[-1] - == "Implicit target not allowed here. Please use display(..., target=...)" - ) + assert self.page.locator("script-py").inner_text() == "A" + @only_main def test_sync_and_async_order(self): """ The order of execution is defined as follows: - 1. first, we execute all the py-script tag in order + 1. first, we execute all the script tags in order 2. then, we start all the tasks which were scheduled with create_task Note that tasks are started *AFTER* all py-script tags have been @@ -158,12 +160,12 @@ class TestAsync(PyScriptTest): executed after e.g. js.console.log("6"). """ src = """ - + - + - + - + """ self.pyscript_run(src, wait_for_pyscript=False) self.wait_for_console("DONE") diff --git a/pyscriptjs/tests/integration/test_importmap.py b/pyscript.core/tests/integration/test_importmap.py similarity index 94% rename from pyscriptjs/tests/integration/test_importmap.py rename to pyscript.core/tests/integration/test_importmap.py index 9ef3e9dd..17ba21aa 100644 --- a/pyscriptjs/tests/integration/test_importmap.py +++ b/pyscript.core/tests/integration/test_importmap.py @@ -28,10 +28,10 @@ class TestImportmap(PyScriptTest): say_hello("JS"); - + """ ) assert self.console.log.lines == [ @@ -46,9 +46,9 @@ class TestImportmap(PyScriptTest): this is not valid JSON - + """, wait_for_pyscript=False, ) diff --git a/pyscriptjs/tests/integration/test_interpreter.py b/pyscript.core/tests/integration/test_interpreter.py similarity index 91% rename from pyscriptjs/tests/integration/test_interpreter.py rename to pyscript.core/tests/integration/test_interpreter.py index 4eae127a..d7147208 100644 --- a/pyscriptjs/tests/integration/test_interpreter.py +++ b/pyscript.core/tests/integration/test_interpreter.py @@ -1,5 +1,12 @@ +import pytest + from .support import PyScriptTest +pytest.skip( + reason="NEXT: pyscript API changed doesn't expose pyscript to window anymore", + allow_module_level=True, +) + class TestInterpreterAccess(PyScriptTest): """Test accessing Python objects from JS via pyscript.interpreter""" @@ -7,11 +14,11 @@ class TestInterpreterAccess(PyScriptTest): def test_interpreter_python_access(self): self.pyscript_run( """ - + """ ) @@ -67,11 +74,11 @@ class TestInterpreterAccess(PyScriptTest): """Test accessing Python objects from JS via pyscript.runtime""" self.pyscript_run( """ - + """ ) diff --git a/pyscriptjs/tests/integration/test_plugins.py b/pyscript.core/tests/integration/test_plugins.py similarity index 98% rename from pyscriptjs/tests/integration/test_plugins.py rename to pyscript.core/tests/integration/test_plugins.py index f16136f8..8ee70738 100644 --- a/pyscriptjs/tests/integration/test_plugins.py +++ b/pyscript.core/tests/integration/test_plugins.py @@ -1,5 +1,12 @@ +import pytest + from .support import PyScriptTest, skip_worker +pytest.skip( + reason="NEXT: plugins not supported", + allow_module_level=True, +) + # Source code of a simple plugin that creates a Custom Element for testing purposes CE_PLUGIN_CODE = """ from pyscript import Plugin @@ -243,11 +250,11 @@ class TestPlugin(PyScriptTest): @prepare_test( "exec_test_logger", PYSCRIPT_HOOKS_PLUGIN_CODE, - template=HTML_TEMPLATE_NO_TAG + "\nx=2; x", + template=HTML_TEMPLATE_NO_TAG + "\n", ) def test_pyscript_exec_hooks(self): """Test that the beforePyScriptExec and afterPyScriptExec hooks work as intended""" - assert self.page.locator("py-script") is not None + assert self.page.locator("script") is not None log_lines: list[str] = self.console.log.lines diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py new file mode 100644 index 00000000..3ec15ddf --- /dev/null +++ b/pyscript.core/tests/integration/test_py_config.py @@ -0,0 +1,193 @@ +import os + +import pytest + +from .support import PyScriptTest, with_execution_thread + + +# Disable the main/worker dual testing, for two reasons: +# +# 1. the logic happens before we start the worker, so there is +# no point in running these tests twice +# +# 2. the logic to inject execution_thread into works only with +# plain tags, but here we want to test all weird combinations +# of config +@with_execution_thread(None) +class TestConfig(PyScriptTest): + def test_py_config_inline_pyscript(self): + self.pyscript_run( + """ + + name = "foobar" + + + + from pyscript import window + window.console.log("config name:", window.pyConfig.name) + + """ + ) + assert self.console.log.lines[-1] == "config name: foobar" + + @pytest.mark.skip("NEXT: works with not with + """ + ) + assert self.console.log.lines[-1] == "config name: foobar" + + @pytest.mark.skip("NEXT: works with not with + """ + ) + assert self.console.log.lines[-1] == "config name: app with external config" + + def test_invalid_json_config(self): + # we need wait_for_pyscript=False because we bail out very soon, + # before being able to write 'PyScript page fully initialized' + self.pyscript_run( + """ + + [[ + + """, + wait_for_pyscript=False, + ) + banner = self.page.wait_for_selector(".py-error") + # assert "Unexpected end of JSON input" in self.console.error.text + expected = "(PY1000): Invalid JSON\n" "Unexpected end of JSON input" + assert banner.inner_text() == expected + + def test_invalid_toml_config(self): + # we need wait_for_pyscript=False because we bail out very soon, + # before being able to write 'PyScript page fully initialized' + self.pyscript_run( + """ + + [[ + + """, + wait_for_pyscript=False, + ) + banner = self.page.wait_for_selector(".py-error") + # assert "Expected DoubleQuote" in self.console.error.text + expected = ( + "(PY1000): Invalid TOML\n" + "Expected DoubleQuote, Whitespace, or [a-z], [A-Z], " + '[0-9], "-", "_" but end of input found.' + ) + assert banner.inner_text() == expected + + @pytest.mark.skip("NEXT: emit a warning in case of multiple py-config") + def test_multiple_py_config(self): + self.pyscript_run( + """ + + name = "foobar" + + + + name = "this is ignored" + + + + """ + ) + banner = self.page.wait_for_selector(".py-warning") + expected = ( + "Multiple tags detected. Only the first " + "is going to be parsed, all the others will be ignored" + ) + assert banner.text_content() == expected + + def test_paths(self): + self.writefile("a.py", "x = 'hello from A'") + self.writefile("b.py", "x = 'hello from B'") + self.pyscript_run( + """ + + [[fetch]] + files = ["./a.py", "./b.py"] + + + + """ + ) + assert self.console.log.lines[-2:] == [ + "hello from A", + "hello from B", + ] + + @pytest.mark.skip("NEXT: emit an error if fetch fails") + def test_paths_that_do_not_exist(self): + self.pyscript_run( + """ + + [[fetch]] + files = ["./f.py"] + + + + """, + wait_for_pyscript=False, + ) + + expected = "(PY0404): Fetching from URL ./f.py failed with " "error 404" + inner_html = self.page.locator(".py-error").inner_html() + assert expected in inner_html + assert expected in self.console.error.lines[-1] + assert self.console.log.lines == [] + + def test_paths_from_packages(self): + self.writefile("utils/__init__.py", "") + self.writefile("utils/a.py", "x = 'hello from A'") + self.pyscript_run( + """ + + [[fetch]] + from = "utils" + to_folder = "pkg" + files = ["__init__.py", "a.py"] + + + + """ + ) + assert self.console.log.lines[-1] == "hello from A" diff --git a/pyscriptjs/tests/integration/test_py_repl.py b/pyscript.core/tests/integration/test_py_repl.py similarity index 99% rename from pyscriptjs/tests/integration/test_py_repl.py rename to pyscript.core/tests/integration/test_py_repl.py index 930389e3..c9687dc9 100644 --- a/pyscriptjs/tests/integration/test_py_repl.py +++ b/pyscript.core/tests/integration/test_py_repl.py @@ -1,7 +1,14 @@ import platform +import pytest + from .support import PyScriptTest, skip_worker +pytest.skip( + reason="NEXT: pyscript NEXT doesn't support the REPL yet", + allow_module_level=True, +) + class TestPyRepl(PyScriptTest): def _replace(self, py_repl, newcode): @@ -379,7 +386,7 @@ class TestPyRepl(PyScriptTest): self.pyscript_run( """
- + asyncio.ensure_future(print_it()); @@ -537,7 +544,7 @@ class TestPyRepl(PyScriptTest): this_tag.setAttribute("output", "third") print("three.") - + """ ) diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py new file mode 100644 index 00000000..0fd70fec --- /dev/null +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -0,0 +1,187 @@ +import time + +import pytest +from playwright.sync_api import expect + +from .support import PageErrors, PyScriptTest, only_worker, skip_worker + + +class TestPyTerminal(PyScriptTest): + def test_multiple_terminals(self): + """ + Multiple terminals are not currently supported + """ + self.pyscript_run( + """ + + + """, + wait_for_pyscript=False, + check_js_errors=False, + ) + assert self.assert_banner_message("You can use at most 1 terminal") + + with pytest.raises(PageErrors, match="You can use at most 1 terminal"): + self.check_js_errors() + + # TODO: interactive shell still unclear + # @only_worker + # def test_py_terminal_input(self): + # """ + # Only worker py-terminal accepts an input + # """ + # self.pyscript_run( + # """ + # + # """, + # wait_for_pyscript=False, + # ) + # self.page.get_by_text(">>> ", exact=True).wait_for() + # self.page.keyboard.type("'the answer is ' + str(6 * 7)") + # self.page.keyboard.press("Enter") + # self.page.get_by_text("the answer is 42").wait_for() + + @only_worker + def test_py_terminal_os_write(self): + """ + An `os.write("text")` should land in the terminal + """ + self.pyscript_run( + """ + + """, + wait_for_pyscript=False, + ) + self.page.get_by_text("hello\n").wait_for() + self.page.get_by_text("world\n").wait_for() + + def test_py_terminal(self): + """ + 1. should redirect stdout and stderr to the DOM + + 2. they also go to the console as usual + """ + self.pyscript_run( + """ + + """, + wait_for_pyscript=False, + ) + self.page.get_by_text("hello world").wait_for() + term = self.page.locator("py-terminal") + term_lines = term.inner_text().splitlines() + assert term_lines[0:3] == [ + "hello world", + "this goes to stderr", + "this goes to stdout", + ] + + @skip_worker( + "Workers don't have events + two different workers don't share the same I/O" + ) + def test_button_action(self): + self.pyscript_run( + """ + + + + + """ + ) + term = self.page.locator("py-terminal") + self.page.locator("button").click() + last_line = self.page.get_by_text("hello world") + last_line.wait_for() + assert term.inner_text().rstrip() == "hello world" + + def test_xterm_function(self): + """Test a few basic behaviors of the xtermjs terminal. + + This test isn't meant to capture all of the behaviors of an xtermjs terminal; + rather, it confirms with a few basic formatting sequences that (1) the xtermjs + terminal is functioning/loaded correctly and (2) that output toward that terminal + isn't being escaped in a way that prevents it reacting to escape seqeunces. The + main goal is preventing regressions. + """ + self.pyscript_run( + """ + + """, + wait_for_pyscript=False, + ) + + # Wait for "done" to actually appear in the xterm; may be delayed, + # since xtermjs processes its input buffer in chunks + last_line = self.page.get_by_text("done") + last_line.wait_for() + + # Yes, this is not ideal. However, per http://xtermjs.org/docs/guides/hooks/ + # "It is not possible to conclude, whether or when a certain chunk of data + # will finally appear on the screen," which is what we'd really like to know. + # By waiting for the "done" test to appear above, we get close, however it is + # possible for the text to appear and not be 'processed' (i.e.) formatted. This + # small delay should avoid that. + time.sleep(1) + + rows = self.page.locator(".xterm-rows") + + # The following use locator.evaluate() and getComputedStyle to get + # the computed CSS values; this tests that the lines are rendering + # properly in a better way than just testing whether they + # get the right css classes from xtermjs + + # First line should be yellow + first_line = rows.locator("div").nth(0) + first_char = first_line.locator("span").nth(0) + color = first_char.evaluate( + "(element) => getComputedStyle(element).getPropertyValue('color')" + ) + assert color == "rgb(196, 160, 0)" + + # Second line should be underlined + second_line = rows.locator("div").nth(1) + first_char = second_line.locator("span").nth(0) + text_decoration = first_char.evaluate( + "(element) => getComputedStyle(element).getPropertyValue('text-decoration')" + ) + assert "underline" in text_decoration + + # We'll make sure the 'bold' font weight is more than the + # default font weight without specifying a specific value + baseline_font_weight = first_char.evaluate( + "(element) => getComputedStyle(element).getPropertyValue('font-weight')" + ) + + # Third line should be bold + third_line = rows.locator("div").nth(2) + first_char = third_line.locator("span").nth(0) + font_weight = first_char.evaluate( + "(element) => getComputedStyle(element).getPropertyValue('font-weight')" + ) + assert int(font_weight) > int(baseline_font_weight) + + # Fourth line should be italic + fourth_line = rows.locator("div").nth(3) + first_char = fourth_line.locator("span").nth(0) + font_style = first_char.evaluate( + "(element) => getComputedStyle(element).getPropertyValue('font-style')" + ) + assert font_style == "italic" diff --git a/pyscriptjs/tests/integration/test_script_type.py b/pyscript.core/tests/integration/test_script_type.py similarity index 57% rename from pyscriptjs/tests/integration/test_script_type.py rename to pyscript.core/tests/integration/test_script_type.py index c364a320..b52b9e49 100644 --- a/pyscriptjs/tests/integration/test_script_type.py +++ b/pyscript.core/tests/integration/test_script_type.py @@ -1,91 +1,105 @@ -from .support import PyScriptTest, skip_worker +import pytest + +from .support import PyScriptTest, with_execution_thread +# these tests don't need to run in 'main' and 'worker' modes: the workers are +# already tested explicitly by some of them (see e.g. +# test_script_type_py_worker_attribute) +@with_execution_thread(None) class TestScriptTypePyScript(PyScriptTest): - @skip_worker("FIXME: js.document") def test_display_line_break(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "hello\nworld" == text_content - @skip_worker("FIXME: js.document") def test_amp(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "a & b" == text_content - @skip_worker("FIXME: js.document") def test_quot(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "a " b" == text_content - @skip_worker("FIXME: js.document") def test_lt_gt(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "< < > >" == text_content - @skip_worker("FIXME: js.document") def test_dynamically_add_script_type_py_tag(self): self.pyscript_run( """ - """ ) - self.page.locator("button").click() + # please note the test here was on timeout + # incapable of finding a
- print("first 1.") - print("second.") - print("third.") - print("first 2.") - print("no output.") + + + + + """ ) @@ -59,10 +63,10 @@ class TestOutputHandling(PyScriptTest): self.pyscript_run( """
- + """ ) @@ -77,16 +81,16 @@ class TestOutputHandling(PyScriptTest): self.pyscript_run( """
- +
- + """ ) @@ -102,7 +106,7 @@ class TestOutputHandling(PyScriptTest): # Test the behavior of stdio capture in async contexts self.pyscript_run( """ - +
- +
- +
- + - + """ ) self.wait_for_console("DONE DONE") - # py-script tags without output parameter should not send + # script tags without output parameter should not send # stdout to element assert self.page.locator("#first").text_content() == "" - # py-script tags with output parameter not expected to send + # script tags with output parameter not expected to send # std to element in coroutine assert self.page.locator("#second").text_content() == "" assert self.page.locator("#third").text_content() == "" @@ -153,7 +157,7 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -192,7 +196,7 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -220,18 +224,18 @@ class TestOutputHandling(PyScriptTest): # Attribute creates exactly 1 warning banner per missing id self.pyscript_run( """ - +
- + - + """ ) @@ -249,19 +253,19 @@ class TestOutputHandling(PyScriptTest): # attribute creates exactly 1 warning banner per missing id self.pyscript_run( """ - +
- + - + """ ) @@ -281,11 +285,11 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -295,14 +299,14 @@ class TestOutputHandling(PyScriptTest): @skip_worker("FIXME: js.document") def test_stdio_output_attribute_change(self): - # If the user changes the 'output' attribute of a tag mid-execution, + # If the user changes the 'output' attribute of a """ ) @@ -336,7 +340,7 @@ class TestOutputHandling(PyScriptTest):
- + """ ) diff --git a/pyscript.core/tests/integration/test_style.py b/pyscript.core/tests/integration/test_style.py new file mode 100644 index 00000000..c669c204 --- /dev/null +++ b/pyscript.core/tests/integration/test_style.py @@ -0,0 +1,25 @@ +import pytest +from playwright.sync_api import expect + +from .support import PyScriptTest, with_execution_thread + + +@with_execution_thread(None) +class TestStyle(PyScriptTest): + def test_pyscript_not_defined(self): + """Test raw elements that are not defined for display:none""" + doc = """ + + + + + + hello + hello + + + """ + self.writefile("test-not-defined-css.html", doc) + self.goto("test-not-defined-css.html") + expect(self.page.locator("py-config")).to_be_hidden() + expect(self.page.locator("py-script")).to_be_hidden() diff --git a/pyscript.core/tests/integration/test_warnings_and_banners.py b/pyscript.core/tests/integration/test_warnings_and_banners.py new file mode 100644 index 00000000..6ffb726f --- /dev/null +++ b/pyscript.core/tests/integration/test_warnings_and_banners.py @@ -0,0 +1,54 @@ +import pytest + +from .support import PyScriptTest, skip_worker + + +class TestWarningsAndBanners(PyScriptTest): + # Test the behavior of generated warning banners + + def test_deprecate_loading_scripts_from_latest(self): + # Use a script tag with an invalid output attribute to generate a warning, but only one + self.pyscript_run( + """ + + """, + extra_head='', + ) + + # wait for the banner to appear (we could have a page.locater call but for some reason + # the worker takes to long to render on CI, since it's a test we can afford 2 calls) + loc = self.page.wait_for_selector(".py-error") + assert ( + loc.inner_text() + == "Loading scripts from latest is deprecated and will be removed soon. Please use a specific version instead." + ) + + # Only one banner should appear + loc = self.page.locator(".py-error") + assert loc.count() == 1 + + @pytest.mark.skip("NEXT: To check if behaviour is consistent with classic") + def test_create_singular_warning(self): + # Use a script tag with an invalid output attribute to generate a warning, but only one + self.pyscript_run( + """ + + + """ + ) + + loc = self.page.locator(".alert-banner") + + # Only one banner should appear + assert loc.count() == 1 + assert ( + loc.text_content() + == 'output = "foo" does not match the id of any element on the page.' + ) diff --git a/pyscriptjs/tests/integration/test_event_handling.py b/pyscript.core/tests/integration/test_when.py similarity index 64% rename from pyscriptjs/tests/integration/test_event_handling.py rename to pyscript.core/tests/integration/test_when.py index 04efa392..6585d88d 100644 --- a/pyscriptjs/tests/integration/test_event_handling.py +++ b/pyscript.core/tests/integration/test_when.py @@ -1,8 +1,9 @@ +import pytest + from .support import PyScriptTest, skip_worker class TestEventHandler(PyScriptTest): - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_when_decorator_with_event(self): """When the decorated function takes a single parameter, it should be passed the event object @@ -10,21 +11,18 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert "I've clicked [object HTMLButtonElement] with id foo_id" in console_text + self.wait_for_console("clicked foo_id") self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_when_decorator_without_event(self): """When the decorated function takes no parameters (not including 'self'), it should be called without the event object @@ -32,93 +30,81 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() self.wait_for_console("The button was clicked") - assert "The button was clicked" in self.console.log.lines self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_multiple_when_decorators_with_event(self): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert "I've clicked [object HTMLButtonElement] with id foo_id" in console_text - + self.wait_for_console("foo_click! id=foo_id") self.page.locator("text=bar_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id bar_id") - assert "I've clicked [object HTMLButtonElement] with id bar_id" in console_text + self.wait_for_console("bar_click! id=bar_id") self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_two_when_decorators(self): """When decorating a function twice, both should function""" self.pyscript_run( """ - + """ ) self.page.locator("text=bar_button").hover() + self.wait_for_console("got event: mouseover") self.page.locator("text=foo_button").click() - self.wait_for_console("An event of type click happened") - assert "An event of type mouseover happened" in self.console.log.lines - assert "An event of type click happened" in self.console.log.lines + self.wait_for_console("got event: click") self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_two_when_decorators_same_element(self): """When decorating a function twice *on the same DOM element*, both should function""" self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").hover() + self.wait_for_console("got event: mouseover") self.page.locator("text=foo_button").click() - self.wait_for_console("An event of type click happened") - assert "An event of type mouseover happened" in self.console.log.lines - assert "An event of type click happened" in self.console.log.lines + self.wait_for_console("got event: click") self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_when_decorator_multiple_elements(self): """The @when decorator's selector should successfully select multiple DOM elements @@ -127,12 +113,12 @@ class TestEventHandler(PyScriptTest): """ - + """ ) self.page.locator("text=button1").click() @@ -142,42 +128,39 @@ class TestEventHandler(PyScriptTest): assert "button2 was clicked" in self.console.log.lines self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") def test_when_decorator_duplicate_selectors(self): """ """ self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert ( - console_text.count("I've clicked [object HTMLButtonElement] with id foo_id") - == 2 - ) + self.wait_for_console("click 1 on foo_id") + self.wait_for_console("click 2 on foo_id") self.assert_no_banners() - @skip_worker(reason="FIXME: js.document (@when decorator)") + @skip_worker("NEXT: error banner not shown") def test_when_decorator_invalid_selector(self): """When the selector parameter of @when is invalid, it should show an error""" self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() diff --git a/pyscriptjs/tests/integration/test_zz_examples.py b/pyscript.core/tests/integration/test_zz_examples.py similarity index 98% rename from pyscriptjs/tests/integration/test_zz_examples.py rename to pyscript.core/tests/integration/test_zz_examples.py index a2dc3335..a0651714 100644 --- a/pyscriptjs/tests/integration/test_zz_examples.py +++ b/pyscript.core/tests/integration/test_zz_examples.py @@ -11,8 +11,10 @@ from PIL import Image from .support import ROOT, PyScriptTest, wait_for_render, with_execution_thread +@pytest.mark.skip( + reason="SKIPPING EXAMPLES: these should be moved elsewhere and updated" +) @with_execution_thread(None) -@pytest.mark.usefixtures("chdir") class TestExamples(PyScriptTest): """ Each example requires the same three tests: @@ -23,11 +25,6 @@ class TestExamples(PyScriptTest): - Testing that the page contains appropriate content after rendering """ - @pytest.fixture() - def chdir(self): - # make sure that the http server serves from the right directory - ROOT.join("pyscriptjs").chdir() - def test_hello_world(self): self.goto("examples/hello_world.html") self.wait_for_pyscript() diff --git a/pyscript.core/tsconfig.json b/pyscript.core/tsconfig.json index e47fd091..f9fc9e68 100644 --- a/pyscript.core/tsconfig.json +++ b/pyscript.core/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "module": "ES2022", - "target": "ES2022", - "moduleResolution": "Classic", + "module": "NodeNext", + "target": "esnext", + "moduleResolution": "nodenext", "allowJs": true, "declaration": true, "emitDeclarationOnly": true, diff --git a/pyscript.core/types/3rd-party/toml.d.ts b/pyscript.core/types/3rd-party/toml.d.ts new file mode 100644 index 00000000..14f8437c --- /dev/null +++ b/pyscript.core/types/3rd-party/toml.d.ts @@ -0,0 +1,12 @@ +/*! (c) Jak Wings - MIT */ declare class e extends SyntaxError { + constructor(r: any, { offset: t, line: e, column: n }: { + offset: any; + line: any; + column: any; + }); + offset: any; + line: any; + column: any; +} +declare function n(n: any): any; +export { e as SyntaxError, n as parse }; diff --git a/pyscript.core/types/3rd-party/xterm-readline.d.ts b/pyscript.core/types/3rd-party/xterm-readline.d.ts new file mode 100644 index 00000000..99a16d83 --- /dev/null +++ b/pyscript.core/types/3rd-party/xterm-readline.d.ts @@ -0,0 +1,138 @@ +declare var b: any; +declare var I: boolean; +declare namespace r { + export let __esModule: boolean; + export { Readline }; +} +declare class Readline { + highlighter: { + highlight(t: any, e: any): any; + highlightPrompt(t: any): any; + highlightChar(t: any, e: any): boolean; + }; + history: { + entries: any[]; + cursor: number; + maxEntries: any; + saveToLocalStorage(): void; + restoreFromLocalStorage(): void; + append(t: any): void; + resetCursor(): void; + next(): any; + prev(): any; + }; + disposables: any[]; + watermark: number; + highWatermark: number; + lowWatermark: number; + highWater: boolean; + state: { + line: { + buf: string; + pos: number; + buffer(): string; + pos_buffer(): string; + length(): number; + char_length(): number; + update(t: any, e: any): void; + insert(t: any): boolean; + moveBack(t: any): boolean; + moveForward(t: any): boolean; + moveHome(): boolean; + moveEnd(): boolean; + startOfLine(): number; + endOfLine(): number; + moveLineUp(t: any): boolean; + moveLineDown(t: any): boolean; + set_pos(t: any): void; + prevPos(t: any): number; + nextPos(t: any): number; + backspace(t: any): boolean; + delete(t: any): boolean; + deleteEndOfLine(): boolean; + }; + highlighting: boolean; + prompt: any; + tty: any; + highlighter: any; + history: any; + promptSize: any; + layout: p; + buffer(): string; + shouldHighlight(): boolean; + clearScreen(): void; + editInsert(t: any): void; + update(t: any): void; + editBackspace(t: any): void; + editDelete(t: any): void; + editDeleteEndOfLine(): void; + refresh(): void; + moveCursorBack(t: any): void; + moveCursorForward(t: any): void; + moveCursorUp(t: any): void; + moveCursorDown(t: any): void; + moveCursorHome(): void; + moveCursorEnd(): void; + moveCursorToEnd(): void; + previousHistory(): void; + nextHistory(): void; + moveCursor(): void; + }; + checkHandler: () => boolean; + ctrlCHandler: () => void; + pauseHandler: (t: any) => void; + activate(t: any): void; + term: any; + dispose(): void; + appendHistory(t: any): void; + setHighlighter(t: any): void; + setCheckHandler(t: any): void; + setCtrlCHandler(t: any): void; + setPauseHandler(t: any): void; + writeReady(): boolean; + write(t: any): void; + print(t: any): void; + println(t: any): void; + output(): this; + tty(): { + tabWidth: any; + col: any; + row: any; + out: any; + write(t: any): any; + print(t: any): any; + println(t: any): any; + clearScreen(): void; + calculatePosition(t: any, e: any): any; + computeLayout(t: any, e: any): { + promptSize: any; + cursor: any; + end: any; + }; + refreshLine(t: any, e: any, s: any, i: any, r: any): void; + clearOldRows(t: any): void; + moveCursor(t: any, e: any): void; + }; + read(t: any): Promise; + activeRead: { + prompt: any; + resolve: (value: any) => void; + reject: (reason?: any) => void; + }; + handleKeyEvent(t: any): boolean; + readData(t: any): void; + readPaste(t: any): void; + readKey(t: any): void; +} +declare class p { + constructor(t: any); + promptSize: any; + cursor: c; + end: c; +} +declare class c { + constructor(t: any, e: any); + row: any; + col: any; +} +export { b as Readline, I as __esModule, r as default }; diff --git a/pyscript.core/types/3rd-party/xterm.d.ts b/pyscript.core/types/3rd-party/xterm.d.ts new file mode 100644 index 00000000..636fd9ee --- /dev/null +++ b/pyscript.core/types/3rd-party/xterm.d.ts @@ -0,0 +1,4 @@ +declare var i: any; +declare var s: any; +declare var t: {}; +export { i as Terminal, s as __esModule, t as default }; diff --git a/pyscript.core/types/all-done.d.ts b/pyscript.core/types/all-done.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/pyscript.core/types/all-done.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/pyscript.core/types/coincident/window.d.ts b/pyscript.core/types/coincident/window.d.ts deleted file mode 100644 index 86a2839c..00000000 --- a/pyscript.core/types/coincident/window.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { ie as default }; -declare function ie(e: any, ...r: any[]): any; -declare namespace ie { - import transfer = m.transfer; - export { transfer }; -} -declare function m(t: any, { parse: n, stringify: r, transform: u }?: JSON): any; -declare namespace m { - function transfer(...e: any[]): any[]; -} diff --git a/pyscript.core/types/config.d.ts b/pyscript.core/types/config.d.ts new file mode 100644 index 00000000..d9c40f26 --- /dev/null +++ b/pyscript.core/types/config.d.ts @@ -0,0 +1,2 @@ +export default configs; +declare const configs: Map; diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index 54e52757..371bfc43 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -1,25 +1,42 @@ +import TYPES from "./types.js"; /** * A `Worker` facade able to bootstrap on the worker thread only a PyScript module. * @param {string} file the python file to run ina worker. * @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker. * @returns {Worker & {sync: ProxyHandler}} */ -export function PyWorker(file: string, options?: { +declare function exportedPyWorker(file: string, options?: { config?: string | object; async?: boolean; }): Worker & { sync: ProxyHandler; }; -export namespace hooks { - let onBeforeRun: Set; - let onBeforeRunAync: Set; - let onAfterRun: Set; - let onAfterRunAsync: Set; - let onInterpreterReady: Set; - let codeBeforeRunWorker: Set; - let codeBeforeRunWorkerAsync: Set; - let codeAfterRunWorker: Set; - let codeAfterRunWorkerAsync: Set; -} -declare let config: any; -export {}; +declare const exportedHooks: { + main: { + onWorker: Set; + onReady: Set; + onBeforeRun: Set; + onBeforeRunAsync: Set; + onAfterRun: Set; + onAfterRunAsync: Set; + codeBeforeRun: Set; + codeBeforeRunAsync: Set; + codeAfterRun: Set; + codeAfterRunAsync: Set; + }; + worker: { + onReady: Set; + onBeforeRun: Set; + onBeforeRunAsync: Set; + onAfterRun: Set; + onAfterRunAsync: Set; + codeBeforeRun: Set; + codeBeforeRunAsync: Set; + codeAfterRun: Set; + codeAfterRunAsync: Set; + }; +}; +declare const exportedConfig: {}; +declare const exportedWhenDefined: (type: string) => Promise; +import sync from "./sync.js"; +export { TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; diff --git a/pyscript.core/types/exceptions.d.ts b/pyscript.core/types/exceptions.d.ts index 138ddfdd..f13f1fbf 100644 --- a/pyscript.core/types/exceptions.d.ts +++ b/pyscript.core/types/exceptions.d.ts @@ -1,6 +1,19 @@ -export function _createAlertBanner(message: any, level: any, messageType?: string, logMessage?: boolean): void; +/** + * Internal function for creating alert banners on the page + * @param {string} message The message to be displayed to the user + * @param {string} level The alert level of the message. Can be any string; 'error' or 'warning' cause matching messages to be emitted to the console + * @param {string} [messageType="text"] If set to "html", the message content will be assigned to the banner's innerHTML directly, instead of its textContent + * @param {any} [logMessage=true] An additional flag for whether the message should be sent to the console log. + */ +export function _createAlertBanner(message: string, level: string, messageType?: string, logMessage?: any): void; export namespace ErrorCode { let GENERIC: string; + let CONFLICTING_CODE: string; + let BAD_CONFIG: string; + let MICROPIP_INSTALL_ERROR: string; + let BAD_PLUGIN_FILE_EXTENSION: string; + let NO_DEFAULT_EXPORT: string; + let TOP_LEVEL_AWAIT: string; let FETCH_ERROR: string; let FETCH_NAME_ERROR: string; let FETCH_UNAUTHORIZED_ERROR: string; @@ -8,20 +21,51 @@ export namespace ErrorCode { let FETCH_NOT_FOUND_ERROR: string; let FETCH_SERVER_ERROR: string; let FETCH_UNAVAILABLE_ERROR: string; - let BAD_CONFIG: string; - let MICROPIP_INSTALL_ERROR: string; - let BAD_PLUGIN_FILE_EXTENSION: string; - let NO_DEFAULT_EXPORT: string; - let TOP_LEVEL_AWAIT: string; } +/** + * Keys of the ErrorCode object + * @typedef {keyof ErrorCode} ErrorCodes + * */ export class UserError extends Error { - constructor(errorCode: any, message?: string, messageType?: string); - errorCode: any; + /** + * @param {ErrorCodes} errorCode + * @param {string} message + * @param {string} messageType + * */ + constructor(errorCode: ErrorCodes, message?: string, messageType?: string); + errorCode: "GENERIC" | "CONFLICTING_CODE" | "BAD_CONFIG" | "MICROPIP_INSTALL_ERROR" | "BAD_PLUGIN_FILE_EXTENSION" | "NO_DEFAULT_EXPORT" | "TOP_LEVEL_AWAIT" | "FETCH_ERROR" | "FETCH_NAME_ERROR" | "FETCH_UNAUTHORIZED_ERROR" | "FETCH_FORBIDDEN_ERROR" | "FETCH_NOT_FOUND_ERROR" | "FETCH_SERVER_ERROR" | "FETCH_UNAVAILABLE_ERROR"; messageType: string; } export class FetchError extends UserError { - constructor(errorCode: any, message: any); + /** + * @param {ErrorCodes} errorCode + * @param {string} message + * */ + constructor(errorCode: ErrorCodes, message: string); } export class InstallError extends UserError { - constructor(errorCode: any, message: any); + /** + * @param {ErrorCodes} errorCode + * @param {string} message + * */ + constructor(errorCode: ErrorCodes, message: string); } +/** + * Keys of the ErrorCode object + */ +export type ErrorCodes = keyof { + GENERIC: string; + CONFLICTING_CODE: string; + BAD_CONFIG: string; + MICROPIP_INSTALL_ERROR: string; + BAD_PLUGIN_FILE_EXTENSION: string; + NO_DEFAULT_EXPORT: string; + TOP_LEVEL_AWAIT: string; + FETCH_ERROR: string; + FETCH_NAME_ERROR: string; + FETCH_UNAUTHORIZED_ERROR: string; + FETCH_FORBIDDEN_ERROR: string; + FETCH_NOT_FOUND_ERROR: string; + FETCH_SERVER_ERROR: string; + FETCH_UNAVAILABLE_ERROR: string; +}; diff --git a/pyscript.core/types/fetch.d.ts b/pyscript.core/types/fetch.d.ts index 5921ebb6..83b6bed2 100644 --- a/pyscript.core/types/fetch.d.ts +++ b/pyscript.core/types/fetch.d.ts @@ -8,3 +8,5 @@ * @returns {Promise} */ export function robustFetch(url: string, options?: Request): Promise; +export { getText }; +import { getText } from "polyscript/exports"; diff --git a/pyscript.core/types/hooks.d.ts b/pyscript.core/types/hooks.d.ts new file mode 100644 index 00000000..e79ff791 --- /dev/null +++ b/pyscript.core/types/hooks.d.ts @@ -0,0 +1,38 @@ +export function main(name: any): any; +export function worker(name: any): any; +export function codeFor(branch: any): {}; +export function createFunction(self: any, name: any): any; +export namespace hooks { + namespace main { + let onWorker: Set; + let onReady: Set; + let onBeforeRun: Set; + let onBeforeRunAsync: Set; + let onAfterRun: Set; + let onAfterRunAsync: Set; + let codeBeforeRun: Set; + let codeBeforeRunAsync: Set; + let codeAfterRun: Set; + let codeAfterRunAsync: Set; + } + namespace worker { + let onReady_1: Set; + export { onReady_1 as onReady }; + let onBeforeRun_1: Set; + export { onBeforeRun_1 as onBeforeRun }; + let onBeforeRunAsync_1: Set; + export { onBeforeRunAsync_1 as onBeforeRunAsync }; + let onAfterRun_1: Set; + export { onAfterRun_1 as onAfterRun }; + let onAfterRunAsync_1: Set; + export { onAfterRunAsync_1 as onAfterRunAsync }; + let codeBeforeRun_1: Set; + export { codeBeforeRun_1 as codeBeforeRun }; + let codeBeforeRunAsync_1: Set; + export { codeBeforeRunAsync_1 as codeBeforeRunAsync }; + let codeAfterRun_1: Set; + export { codeAfterRun_1 as codeAfterRun }; + let codeAfterRunAsync_1: Set; + export { codeAfterRunAsync_1 as codeAfterRunAsync }; + } +} diff --git a/pyscript.core/types/plugins-helper.d.ts b/pyscript.core/types/plugins-helper.d.ts new file mode 100644 index 00000000..7af7edde --- /dev/null +++ b/pyscript.core/types/plugins-helper.d.ts @@ -0,0 +1,2 @@ +declare function _default(main: any, wrap: any, element: any, hook: any): Promise; +export default _default; diff --git a/pyscript.core/types/plugins.d.ts b/pyscript.core/types/plugins.d.ts new file mode 100644 index 00000000..286e91d0 --- /dev/null +++ b/pyscript.core/types/plugins.d.ts @@ -0,0 +1,6 @@ +declare const _default: { + "deprecations-manager": () => Promise; + error: () => Promise; + "py-terminal": () => Promise; +}; +export default _default; diff --git a/pyscript.core/types/plugins/deprecations-manager.d.ts b/pyscript.core/types/plugins/deprecations-manager.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/pyscript.core/types/plugins/deprecations-manager.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/pyscript.core/types/plugins/error.d.ts b/pyscript.core/types/plugins/error.d.ts new file mode 100644 index 00000000..bf9a6788 --- /dev/null +++ b/pyscript.core/types/plugins/error.d.ts @@ -0,0 +1,5 @@ +/** + * Add a banner to the top of the page, notifying the user of an error + * @param {string} message + */ +export function notify(message: string): void; diff --git a/pyscript.core/types/plugins/py-terminal.d.ts b/pyscript.core/types/plugins/py-terminal.d.ts new file mode 100644 index 00000000..35a35db4 --- /dev/null +++ b/pyscript.core/types/plugins/py-terminal.d.ts @@ -0,0 +1,2 @@ +declare const _default: Promise; +export default _default; diff --git a/pyscript.core/types/polyscript/esm/custom.d.ts b/pyscript.core/types/polyscript/esm/custom.d.ts deleted file mode 100644 index d231cfb7..00000000 --- a/pyscript.core/types/polyscript/esm/custom.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const CUSTOM_SELECTORS: any[]; -export function handleCustomType(node: Element): void; -export function define(type: string, options: CustomOptions): void; -export function whenDefined(type: string): Promise; -/** - * custom configuration - */ -export type Runtime = { - /** - * the bootstrapped interpreter - */ - interpreter: object; - /** - * an XWorker constructor that defaults to same interpreter on the Worker. - */ - XWorker: (url: string, options?: object) => Worker; - /** - * a cloned config used to bootstrap the interpreter - */ - config: object; - /** - * an utility to run code within the interpreter - */ - run: (code: string) => any; - /** - * an utility to run code asynchronously within the interpreter - */ - runAsync: (code: string) => Promise; - /** - * an utility to write a file in the virtual FS, if available - */ - writeFile: (path: string, data: ArrayBuffer) => void; -}; -/** - * custom configuration - */ -export type CustomOptions = { - /** - * the interpreter to use - */ - interpreter: 'pyodide' | 'micropython' | 'wasmoon' | 'ruby-wasm-wasi'; - /** - * the optional interpreter version to use - */ - version?: string; - /** - * the optional config to use within such interpreter - */ - config?: string; - /** - * the callback that will be invoked once - */ - onInterpreterReady?: (environment: object, node: Element) => void; -}; diff --git a/pyscript.core/types/polyscript/esm/fetch-utils.d.ts b/pyscript.core/types/polyscript/esm/fetch-utils.d.ts deleted file mode 100644 index ba68c296..00000000 --- a/pyscript.core/types/polyscript/esm/fetch-utils.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getBuffer(response: Response): Promise; -export function getJSON(response: Response): Promise; -export function getText(response: Response): Promise; diff --git a/pyscript.core/types/polyscript/esm/index.d.ts b/pyscript.core/types/polyscript/esm/index.d.ts deleted file mode 100644 index 7e12d538..00000000 --- a/pyscript.core/types/polyscript/esm/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { env } from "./listeners.js"; -export const XWorker: (url: string, options?: import("./worker/class.js").WorkerOptions) => Worker; -export { define, whenDefined } from "./custom.js"; diff --git a/pyscript.core/types/polyscript/esm/interpreter/_python.d.ts b/pyscript.core/types/polyscript/esm/interpreter/_python.d.ts deleted file mode 100644 index a6cf5b0d..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/_python.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function registerJSModule(interpreter: any, name: any, value: any): void; -export function run(interpreter: any, code: any): any; -export function runAsync(interpreter: any, code: any): any; -export function runEvent(interpreter: any, code: any, event: any): Promise; diff --git a/pyscript.core/types/polyscript/esm/interpreter/_utils.d.ts b/pyscript.core/types/polyscript/esm/interpreter/_utils.d.ts deleted file mode 100644 index 1b0a089c..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/_utils.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function clean(code: string): string; -export const io: WeakMap; -export function stdio(init: any): { - stderr: (...args: any[]) => any; - stdout: (...args: any[]) => any; - get(engine: any): Promise; -}; -export function writeFile({ FS, PATH, PATH_FS }: { - FS: any; - PATH: any; - PATH_FS: any; -}, path: any, buffer: any): any; -export function writeFileShim(FS: any, path: any, buffer: any): any; -export const base: WeakMap; -export function fetchPaths(module: any, interpreter: any, config_fetch: any): Promise; diff --git a/pyscript.core/types/polyscript/esm/interpreter/micropython.d.ts b/pyscript.core/types/polyscript/esm/interpreter/micropython.d.ts deleted file mode 100644 index 1b5f6c7e..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/micropython.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -declare namespace _default { - export { type }; - export function module(version?: string): string; - export function engine({ loadMicroPython }: { - loadMicroPython: any; - }, config: any, url: any): Promise; - export { registerJSModule }; - export { run }; - export { runAsync }; - export { runEvent }; - export function transform(_: any, value: any): any; - export function writeFile({ FS, _module: { PATH, PATH_FS } }: { - FS: any; - _module: { - PATH: any; - PATH_FS: any; - }; - }, path: any, buffer: any): any; -} -export default _default; -declare const type: "micropython"; -import { registerJSModule } from './_python.js'; -import { run } from './_python.js'; -import { runAsync } from './_python.js'; -import { runEvent } from './_python.js'; diff --git a/pyscript.core/types/polyscript/esm/interpreter/pyodide.d.ts b/pyscript.core/types/polyscript/esm/interpreter/pyodide.d.ts deleted file mode 100644 index c701caf0..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/pyodide.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -declare namespace _default { - export { type }; - export function module(version?: string): string; - export function engine({ loadPyodide }: { - loadPyodide: any; - }, config: any, url: any): Promise; - export { registerJSModule }; - export { run }; - export { runAsync }; - export { runEvent }; - export function transform(interpreter: any, value: any): any; - export function writeFile({ FS, PATH, _module: { PATH_FS } }: { - FS: any; - PATH: any; - _module: { - PATH_FS: any; - }; - }, path: any, buffer: any): any; -} -export default _default; -declare const type: "pyodide"; -import { registerJSModule } from './_python.js'; -import { run } from './_python.js'; -import { runAsync } from './_python.js'; -import { runEvent } from './_python.js'; diff --git a/pyscript.core/types/polyscript/esm/interpreter/ruby-wasm-wasi.d.ts b/pyscript.core/types/polyscript/esm/interpreter/ruby-wasm-wasi.d.ts deleted file mode 100644 index fc8568d5..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/ruby-wasm-wasi.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -declare namespace _default { - export { type }; - export let experimental: boolean; - export function module(version?: string): string; - export function engine({ DefaultRubyVM }: { - DefaultRubyVM: any; - }, config: any, url: any): Promise; - export function registerJSModule(interpreter: any, _: any, value: any): void; - export function run(interpreter: any, code: any): any; - export function runAsync(interpreter: any, code: any): any; - export function runEvent(interpreter: any, code: any, event: any): Promise; - export function transform(_: any, value: any): any; - export function writeFile(): never; -} -export default _default; -declare const type: "ruby-wasm-wasi"; diff --git a/pyscript.core/types/polyscript/esm/interpreter/wasmoon.d.ts b/pyscript.core/types/polyscript/esm/interpreter/wasmoon.d.ts deleted file mode 100644 index 5f0dca9d..00000000 --- a/pyscript.core/types/polyscript/esm/interpreter/wasmoon.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -declare namespace _default { - export { type }; - export function module(version?: string): string; - export function engine({ LuaFactory, LuaLibraries }: { - LuaFactory: any; - LuaLibraries: any; - }, config: any): Promise; - export function registerJSModule(interpreter: any, _: any, value: any): void; - export function run(interpreter: any, code: any): any; - export function runAsync(interpreter: any, code: any): any; - export function runEvent(interpreter: any, code: any, event: any): Promise; - export function transform(_: any, value: any): any; - export function writeFile({ cmodule: { module: { FS }, }, }: { - cmodule: { - module: { - FS: any; - }; - }; - }, path: any, buffer: any): any; -} -export default _default; -declare const type: "wasmoon"; diff --git a/pyscript.core/types/polyscript/esm/interpreters.d.ts b/pyscript.core/types/polyscript/esm/interpreters.d.ts deleted file mode 100644 index ef35e452..00000000 --- a/pyscript.core/types/polyscript/esm/interpreters.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** @type {Map} */ -export const registry: Map; -/** @type {Map} */ -export const configs: Map; -/** @type {string[]} */ -export const selectors: string[]; -/** @type {string[]} */ -export const prefixes: string[]; -export const interpreter: Map; diff --git a/pyscript.core/types/polyscript/esm/listeners.d.ts b/pyscript.core/types/polyscript/esm/listeners.d.ts deleted file mode 100644 index 98f55b0c..00000000 --- a/pyscript.core/types/polyscript/esm/listeners.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const env: any; -export function listener(event: any): Promise; -export function addAllListeners(root: Document | Element): void; diff --git a/pyscript.core/types/polyscript/esm/loader.d.ts b/pyscript.core/types/polyscript/esm/loader.d.ts deleted file mode 100644 index 02350ce0..00000000 --- a/pyscript.core/types/polyscript/esm/loader.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export function getRuntime(id: string, config?: string, options?: object): Promise; -export function getRuntimeID(type: string, version?: string): string; diff --git a/pyscript.core/types/polyscript/esm/script-handler.d.ts b/pyscript.core/types/polyscript/esm/script-handler.d.ts deleted file mode 100644 index a8e029c0..00000000 --- a/pyscript.core/types/polyscript/esm/script-handler.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function queryTarget(script: any, idOrSelector: any): any; -export const interpreters: Map; -export function getDetails(type: any, id: any, name: any, version: any, config: any, runtime?: any): any; -export function handle(script: HTMLScriptElement): Promise; diff --git a/pyscript.core/types/polyscript/esm/toml.d.ts b/pyscript.core/types/polyscript/esm/toml.d.ts deleted file mode 100644 index d86d9471..00000000 --- a/pyscript.core/types/polyscript/esm/toml.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function parse(text: string): object; diff --git a/pyscript.core/types/polyscript/esm/utils.d.ts b/pyscript.core/types/polyscript/esm/utils.d.ts deleted file mode 100644 index b62f2241..00000000 --- a/pyscript.core/types/polyscript/esm/utils.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -export const isArray: (arg: any) => arg is any[]; -export const assign: { - (target: T, source: U): T & U; - (target: T_1, source1: U_1, source2: V): T_1 & U_1 & V; - (target: T_2, source1: U_2, source2: V_1, source3: W): T_2 & U_2 & V_1 & W; - (target: object, ...sources: any[]): any; -}; -export const create: { - (o: object): any; - (o: object, properties: PropertyDescriptorMap & ThisType): any; -}; -export const defineProperties: (o: T, properties: PropertyDescriptorMap & ThisType) => T; -export const defineProperty: (o: T, p: PropertyKey, attributes: PropertyDescriptor & ThisType) => T; -export const entries: { - (o: { - [s: string]: T; - } | ArrayLike): [string, T][]; - (o: {}): [string, any][]; -}; -export const all: { - (values: Iterable>): Promise[]>; - (values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited; }>; -}; -export const resolve: { - (): Promise; - (value: T): Promise>; - (value: T_1 | PromiseLike): Promise>; -}; -export function absoluteURL(path: any, base?: string): string; diff --git a/pyscript.core/types/polyscript/esm/worker/class.d.ts b/pyscript.core/types/polyscript/esm/worker/class.d.ts deleted file mode 100644 index 0845d4d2..00000000 --- a/pyscript.core/types/polyscript/esm/worker/class.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare function _default(...args: any[]): (url: string, options?: WorkerOptions) => Worker; -export default _default; -/** - * custom configuration - */ -export type WorkerOptions = { - /** - * the interpreter type to use - */ - type: string; - /** - * the optional interpreter version to use - */ - version?: string; - /** - * the optional config to use within such interpreter - */ - config?: string; -}; diff --git a/pyscript.core/types/polyscript/esm/worker/hooks.d.ts b/pyscript.core/types/polyscript/esm/worker/hooks.d.ts deleted file mode 100644 index ea2da89f..00000000 --- a/pyscript.core/types/polyscript/esm/worker/hooks.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class Hook { - constructor(interpreter: any, options: any); - interpreter: any; - onWorkerReady: any; - get stringHooks(): {}; -} diff --git a/pyscript.core/types/polyscript/esm/worker/xworker.d.ts b/pyscript.core/types/polyscript/esm/worker/xworker.d.ts deleted file mode 100644 index 5575be5a..00000000 --- a/pyscript.core/types/polyscript/esm/worker/xworker.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare function _default(): Worker; -export default _default; diff --git a/pyscript.core/types/pyscript/pyscript.core/src/core.d.ts b/pyscript.core/types/pyscript/pyscript.core/src/core.d.ts deleted file mode 100644 index 54e52757..00000000 --- a/pyscript.core/types/pyscript/pyscript.core/src/core.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * A `Worker` facade able to bootstrap on the worker thread only a PyScript module. - * @param {string} file the python file to run ina worker. - * @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker. - * @returns {Worker & {sync: ProxyHandler}} - */ -export function PyWorker(file: string, options?: { - config?: string | object; - async?: boolean; -}): Worker & { - sync: ProxyHandler; -}; -export namespace hooks { - let onBeforeRun: Set; - let onBeforeRunAync: Set; - let onAfterRun: Set; - let onAfterRunAsync: Set; - let onInterpreterReady: Set; - let codeBeforeRunWorker: Set; - let codeBeforeRunWorkerAsync: Set; - let codeAfterRunWorker: Set; - let codeAfterRunWorkerAsync: Set; -} -declare let config: any; -export {}; diff --git a/pyscript.core/types/pyscript/pyscript.core/src/exceptions.d.ts b/pyscript.core/types/pyscript/pyscript.core/src/exceptions.d.ts deleted file mode 100644 index 138ddfdd..00000000 --- a/pyscript.core/types/pyscript/pyscript.core/src/exceptions.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -export function _createAlertBanner(message: any, level: any, messageType?: string, logMessage?: boolean): void; -export namespace ErrorCode { - let GENERIC: string; - let FETCH_ERROR: string; - let FETCH_NAME_ERROR: string; - let FETCH_UNAUTHORIZED_ERROR: string; - let FETCH_FORBIDDEN_ERROR: string; - let FETCH_NOT_FOUND_ERROR: string; - let FETCH_SERVER_ERROR: string; - let FETCH_UNAVAILABLE_ERROR: string; - let BAD_CONFIG: string; - let MICROPIP_INSTALL_ERROR: string; - let BAD_PLUGIN_FILE_EXTENSION: string; - let NO_DEFAULT_EXPORT: string; - let TOP_LEVEL_AWAIT: string; -} -export class UserError extends Error { - constructor(errorCode: any, message?: string, messageType?: string); - errorCode: any; - messageType: string; -} -export class FetchError extends UserError { - constructor(errorCode: any, message: any); -} -export class InstallError extends UserError { - constructor(errorCode: any, message: any); -} diff --git a/pyscript.core/types/pyscript/pyscript.core/src/fetch.d.ts b/pyscript.core/types/pyscript/pyscript.core/src/fetch.d.ts deleted file mode 100644 index 5921ebb6..00000000 --- a/pyscript.core/types/pyscript/pyscript.core/src/fetch.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This is a fetch wrapper that handles any non 200 responses and throws a - * FetchError with the right ErrorCode. This is useful because our FetchError - * will automatically create an alert banner. - * - * @param {string} url - URL to fetch - * @param {Request} [options] - options to pass to fetch - * @returns {Promise} - */ -export function robustFetch(url: string, options?: Request): Promise; diff --git a/pyscript.core/types/stdlib.d.ts b/pyscript.core/types/stdlib.d.ts new file mode 100644 index 00000000..ae80ecad --- /dev/null +++ b/pyscript.core/types/stdlib.d.ts @@ -0,0 +1,2 @@ +declare const _default: string; +export default _default; diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts new file mode 100644 index 00000000..fa33defe --- /dev/null +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -0,0 +1,13 @@ +declare namespace _default { + let pyscript: { + "__init__.py": string; + "display.py": string; + "event_handling.py": string; + "magic_js.py": string; + "util.py": string; + }; + let pyweb: { + "pydom.py": string; + }; +} +export default _default; diff --git a/pyscript.core/types/sync.d.ts b/pyscript.core/types/sync.d.ts new file mode 100644 index 00000000..3dd52650 --- /dev/null +++ b/pyscript.core/types/sync.d.ts @@ -0,0 +1,8 @@ +declare namespace _default { + /** + * 'Sleep' for the given number of seconds. Used to implement Python's time.sleep in Worker threads. + * @param {number} seconds The number of seconds to sleep. + */ + function sleep(seconds: number): Promise; +} +export default _default; diff --git a/pyscript.core/types/toml.d.ts b/pyscript.core/types/toml.d.ts new file mode 100644 index 00000000..14f8437c --- /dev/null +++ b/pyscript.core/types/toml.d.ts @@ -0,0 +1,12 @@ +/*! (c) Jak Wings - MIT */ declare class e extends SyntaxError { + constructor(r: any, { offset: t, line: e, column: n }: { + offset: any; + line: any; + column: any; + }); + offset: any; + line: any; + column: any; +} +declare function n(n: any): any; +export { e as SyntaxError, n as parse }; diff --git a/pyscript.core/types/types.d.ts b/pyscript.core/types/types.d.ts new file mode 100644 index 00000000..1190776e --- /dev/null +++ b/pyscript.core/types/types.d.ts @@ -0,0 +1,2 @@ +declare const _default: Map; +export default _default; diff --git a/pyscript.core/types/utils.d.ts b/pyscript.core/types/utils.d.ts new file mode 100644 index 00000000..266953e3 --- /dev/null +++ b/pyscript.core/types/utils.d.ts @@ -0,0 +1 @@ +export function htmlDecode(html: any): string; diff --git a/pyscriptjs/.eslintrc.js b/pyscriptjs/.eslintrc.js deleted file mode 100644 index 9c12d37d..00000000 --- a/pyscriptjs/.eslintrc.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - env: { - es6: true, - browser: true, - }, - plugins: ['@typescript-eslint'], - ignorePatterns: ['node_modules', 'src/interpreter_worker/*'], - rules: { - // ts-ignore is already an explicit override, no need to have a second lint - '@typescript-eslint/ban-ts-comment': 'off', - - // any related lints - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - - // other rules - 'no-prototype-builtins': 'error', - '@typescript-eslint/no-unused-vars': ['error', { args: 'none' }], - '@typescript-eslint/no-floating-promises': 'error', - '@typescript-eslint/restrict-plus-operands': 'error', - '@typescript-eslint/no-empty-function': 'error', - '@typescript-eslint/restrict-template-expressions': ['error', { allowBoolean: true }], - }, - overrides: [ - { - files: ['src/components/pyscript.ts'], - rules: { - '@typescript-eslint/unbound-method': 'off', - }, - }, - ], -}; diff --git a/pyscriptjs/.prettierignore b/pyscriptjs/.prettierignore deleted file mode 100644 index 0a170957..00000000 --- a/pyscriptjs/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -build -node_modules - - -# Ignore all HTML files -*.html diff --git a/pyscriptjs/.prettierrc.js b/pyscriptjs/.prettierrc.js deleted file mode 100644 index 01d6f2da..00000000 --- a/pyscriptjs/.prettierrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - arrowParens: 'avoid', - bracketSameLine: true, - singleQuote: true, - printWidth: 120, - semi: true, - tabWidth: 4, - trailingComma: 'all', -}; diff --git a/pyscriptjs/Makefile b/pyscriptjs/Makefile deleted file mode 100644 index cb4a7193..00000000 --- a/pyscriptjs/Makefile +++ /dev/null @@ -1,137 +0,0 @@ -tag := latest -git_hash ?= $(shell git log -1 --pretty=format:%h) - -base_dir ?= $(shell git rev-parse --show-toplevel) -src_dir ?= $(base_dir)/pyscriptjs/src -examples ?= ../$(base_dir)/examples -app_dir ?= $(shell git rev-parse --show-prefix) - -CONDA_EXE := conda -CONDA_ENV ?= $(base_dir)/pyscriptjs/env -env := $(CONDA_ENV) -conda_run := $(CONDA_EXE) run -p $(env) -PYTEST_EXE := $(CONDA_ENV)/bin/pytest -GOOD_NODE_VER := 14 -GOOD_NPM_VER := 6 -NODE_VER := $(shell node -v | cut -d. -f1 | sed 's/^v\(.*\)/\1/') -NPM_VER := $(shell npm -v | cut -d. -f1) - -ifeq ($(shell uname -s), Darwin) - SED_I_ARG := -i '' -else - SED_I_ARG := -i -endif - -GOOD_NODE := $(shell if [ $(NODE_VER) -ge $(GOOD_NODE_VER) ]; then echo true; else echo false; fi) -GOOD_NPM := $(shell if [ $(NPM_VER) -ge $(GOOD_NPM_VER) ]; then echo true; else echo false; fi) - -.PHONY: check-node -check-node: - @echo Build requires Node $(GOOD_NODE_VER).x or higher: $(NODE_VER) detected && $(GOOD_NODE) - -.PHONY: check-npm -check-npm: - @echo Build requires npm $(GOOD_NPM_VER).x or higher: $(NPM_VER) detected && $(GOOD_NPM) - -setup: - make check-node - make check-npm - npm install - $(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml - $(conda_run) playwright install - $(CONDA_EXE) install -c anaconda pytest -y - -clean: - find . -name \*.py[cod] -delete - rm -rf .pytest_cache .coverage coverage.xml - -clean-all: clean - rm -rf $(env) *.egg-info - -shell: - @export CONDA_ENV_PROMPT='<{name}>' - @echo 'conda activate $(env)' - -dev: - npm run dev - -build: - npm run build - -build-fast: - node esbuild.mjs - -# use the following rule to do all the checks done by precommit: in -# particular, use this if you want to run eslint. -precommit-check: - pre-commit run --all-files - -examples: - mkdir -p ./examples - cp -r ../examples/* ./examples - chmod -R 755 examples - find ./examples/toga -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../../build/+g {} \; - find ./examples/webgl -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../../../build/+g {} \; - find ./examples -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../build/+g {} \; - npm run build - rm -rf ./examples/build - mkdir -p ./examples/build - cp -R ./build/* ./examples/build - @echo "To serve examples run: $(conda_run) python -m http.server 8080 --directory examples" - -# run prerequisites and serve pyscript examples at http://localhost:8000/examples/ -run-examples: setup build examples - make examples - npm install - make dev - -test: - make test-ts - make test-py - make test-integration-parallel - make test-examples - -# run all integration tests *including examples* sequentially -test-integration: - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml - -# run all integration tests *except examples* in parallel (examples use too much memory) -test-integration-parallel: - mkdir -p test_results - $(PYTEST_EXE) --numprocesses auto -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'not zz_examples' - -# run integration tests on only examples sequentially (to avoid running out of memory) -test-examples: - make examples - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'zz_examples' - -test-py: - @echo "Tests from $(src_dir)" - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/py-unit/ --log-cli-level=warning --junitxml=test_results/py-unit.xml - -test-ts: - npm run test - -fmt: fmt-py fmt-ts - @echo "Format completed" - -fmt-check: fmt-ts-check fmt-py-check - @echo "Format check completed" - -fmt-ts: - npm run format - -fmt-ts-check: - npm run format:check - -fmt-py: - $(conda_run) black --skip-string-normalization . - $(conda_run) isort --profile black . - -fmt-py-check: - $(conda_run) black -l 88 --check . - -.PHONY: $(MAKECMDGOALS) diff --git a/pyscriptjs/README.md b/pyscriptjs/README.md deleted file mode 100644 index afbcd9e4..00000000 --- a/pyscriptjs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# PyScript Demonstrator - -[A simple webapp to demonstrate the capabilities of PyScript.](https://github.com/pyscript/pyscript/blob/main/docs/development/setting-up-environment.md#pyscript-demonstrator) diff --git a/pyscriptjs/__mocks__/_pyscript.js b/pyscriptjs/__mocks__/_pyscript.js deleted file mode 100644 index 5ea00107..00000000 --- a/pyscriptjs/__mocks__/_pyscript.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * this file mocks the `src/python/pyscript.py` file - * since importing of `.py` files isn't usually supported - * inside JS/TS files. - * - * It sets the value of whatever is imported from - * `src/python/pyscript.py` the contents of that file - * - * This is needed since the imported object is further - * passed to a function which only accepts a string. - */ - -const fs = require('fs'); -module.exports = fs.readFileSync('./src/python/pyscript.py', 'utf8'); diff --git a/pyscriptjs/__mocks__/cssMock.js b/pyscriptjs/__mocks__/cssMock.js deleted file mode 100644 index 9dc5fc1e..00000000 --- a/pyscriptjs/__mocks__/cssMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = ''; diff --git a/pyscriptjs/__mocks__/fileMock.js b/pyscriptjs/__mocks__/fileMock.js deleted file mode 100644 index 1fce9017..00000000 --- a/pyscriptjs/__mocks__/fileMock.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * this file mocks python files that are not explicitly - * matched by a regex in jest.config.js, since importing of - * `.py` files isn't usually supported inside JS/TS files. - * - * This is needed since the imported object is further - * passed to a function which only accepts a string. - * - * The mocked contents of the `.py` file will be "", e.g. - * nothing. - */ - -console.warn(`.py files that are not explicitly mocked in \ - jest.config.js and /__mocks__/ are mocked as empty strings`); - -module.exports = ''; diff --git a/pyscriptjs/directoryManifest.mjs b/pyscriptjs/directoryManifest.mjs deleted file mode 100644 index ef8a1000..00000000 --- a/pyscriptjs/directoryManifest.mjs +++ /dev/null @@ -1,53 +0,0 @@ -// This logic split out because it is shared by: -// 1. esbuild.mjs -// 2. Jest setup.ts - -import path, { join } from 'path'; -import { opendir, readFile } from 'fs/promises'; - -/** - * List out everything in a directory, but skip __pycache__ directory. Used to - * list out the directory paths and the [file path, file contents] pairs in the - * Python package. All paths are relative to the directory we are listing. The - * directories are sorted topologically so that a parent directory always - * appears before its children. - * - * This is consumed in main.ts which calls mkdir for each directory and then - * writeFile to create each file. - * - * @param {string} dir The path to the directory we want to list out - * @returns {dirs: string[], files: [string, string][]} - */ -export async function directoryManifest(dir) { - const result = { dirs: [], files: [] }; - await _directoryManifestHelper(dir, '.', result); - return result; -} - -/** - * Recursive helper function for directoryManifest - */ -async function _directoryManifestHelper(root, dir, result) { - const dirObj = await opendir(join(root, dir)); - for await (const d of dirObj) { - const entry = join(dir, d.name); - if (d.isDirectory()) { - if (d.name === '__pycache__') { - continue; - } - result.dirs.push(entry); - await _directoryManifestHelper(root, entry, result); - } else if (d.isFile()) { - result.files.push([normalizePath(entry), await readFile(join(root, entry), { encoding: 'utf-8' })]); - } - } -} - -/** - * Normalize paths under different operating systems to - * the correct path that will be used for src on browser. - * @param {string} originalPath - */ -function normalizePath(originalPath) { - return path.normalize(originalPath).replace(/\\/g, '/'); -} diff --git a/pyscriptjs/environment.yml b/pyscriptjs/environment.yml deleted file mode 100644 index c8bfad30..00000000 --- a/pyscriptjs/environment.yml +++ /dev/null @@ -1,25 +0,0 @@ -channels: - - defaults - - conda-forge - - microsoft -dependencies: - - python=3.11.3 - - pip - - pytest=7.1.2 - - nodejs=16 - - black - - isort - - codespell - - pre-commit - - pillow - - numpy - - markdown - - toml - - pip: - - playwright==1.33.0 - - pytest-playwright==0.3.3 - - pytest-xdist==3.3.0 - # We need Pyodide and micropip so we can import them in our Python - # unit tests - - pyodide_py==0.23.2 - - micropip==0.2.2 diff --git a/pyscriptjs/esbuild.mjs b/pyscriptjs/esbuild.mjs deleted file mode 100644 index cfa694b8..00000000 --- a/pyscriptjs/esbuild.mjs +++ /dev/null @@ -1,138 +0,0 @@ -import { build } from 'esbuild'; -import { spawn } from 'child_process'; -import { join } from 'path'; -import { watchFile } from 'fs'; -import { cp, lstat, readdir } from 'fs/promises'; -import { directoryManifest } from './directoryManifest.mjs'; -import { fileURLToPath } from 'url'; - -const __dirname = fileURLToPath(new URL('.', import.meta.url)); - -const production = !process.env.NODE_WATCH || process.env.NODE_ENV === 'production'; - -const copy_targets = [ - { src: 'public/index.html', dest: 'build' }, - { src: 'src/plugins/python/*', dest: 'build/plugins/python' }, -]; - -if (!production) { - copy_targets.push({ src: 'build/*', dest: 'examples/build' }); -} - -/** - * An esbuild plugin that injects the Pyscript Python package. - * - * It uses onResolve to attach our custom namespace to the import and then uses - * onLoad to inject the file contents. - */ -function bundlePyscriptPythonPlugin() { - const namespace = 'bundlePyscriptPythonPlugin'; - return { - name: namespace, - setup(build) { - // Resolve the pyscript_package to our custom namespace - // The path doesn't really matter, but we need a separate namespace - // or else the file system resolver will raise an error. - build.onResolve({ filter: /^pyscript_python_package.esbuild_injected.json$/ }, args => { - return { path: 'dummy', namespace }; - }); - // Inject our manifest as JSON contents, and use the JSON loader. - // Also tell esbuild to watch the files & directories we've listed - // for updates. - build.onLoad({ filter: /^dummy$/, namespace }, async args => { - const manifest = await directoryManifest('./src/python'); - return { - contents: JSON.stringify(manifest), - loader: 'json', - watchFiles: manifest.files.map(([k, v]) => k), - watchDirs: manifest.dirs, - }; - }); - }, - }; -} - -const pyScriptConfig = { - entryPoints: ['src/main.ts'], - loader: { '.py': 'text' }, - bundle: true, - format: 'iife', - globalName: 'pyscript', - plugins: [bundlePyscriptPythonPlugin()], -}; - -const interpreterWorkerConfig = { - entryPoints: ['src/interpreter_worker/worker.ts'], - loader: { '.py': 'text' }, - bundle: true, - format: 'iife', - plugins: [bundlePyscriptPythonPlugin()], -}; - -const copyPath = (source, dest, ...rest) => cp(join(__dirname, source), join(__dirname, dest), ...rest); - -const esbuild = async () => { - const timer = `\x1b[1mpyscript\x1b[0m \x1b[2m(${production ? 'prod' : 'dev'})\x1b[0m built in`; - console.time(timer); - - await Promise.all([ - build({ - ...pyScriptConfig, - sourcemap: true, - minify: false, - outfile: 'build/pyscript.js', - }), - build({ - ...pyScriptConfig, - sourcemap: true, - minify: true, - outfile: 'build/pyscript.min.js', - }), - // XXX I suppose we should also build a minified version - // TODO (HC): Simplify config a bit - build({ - ...interpreterWorkerConfig, - sourcemap: false, - minify: false, - outfile: 'build/interpreter_worker.js', - }), - ]); - - const copy = []; - for (const { src, dest } of copy_targets) { - if (src.endsWith('/*')) { - copy.push(copyPath(src.slice(0, -2), dest, { recursive: true })); - } else { - copy.push(copyPath(src, dest + src.slice(src.lastIndexOf('/')))); - } - } - await Promise.all(copy); - - console.timeEnd(timer); -}; - -esbuild().then(() => { - if (!production) { - (async function watchPath(path) { - for (const file of await readdir(path)) { - const whole = join(path, file); - if (/\.(js|ts|css|py)$/.test(file)) { - watchFile(whole, async () => { - await esbuild(); - }); - } else if ((await lstat(whole)).isDirectory()) { - watchPath(whole); - } - } - })('src'); - - const server = spawn('python', ['-m', 'http.server', '--directory', './examples', '8080'], { - stdio: 'inherit', - detached: false, - }); - - process.on('exit', () => { - server.kill(); - }); - } -}); diff --git a/pyscriptjs/jest-environment-jsdom.js b/pyscriptjs/jest-environment-jsdom.js deleted file mode 100644 index 4ff695fc..00000000 --- a/pyscriptjs/jest-environment-jsdom.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const { TextEncoder, TextDecoder } = require('util'); -const { MessageChannel } = require('node:worker_threads'); - -const { default: $JSDOMEnvironment, TestEnvironment } = require('jest-environment-jsdom'); - -Object.defineProperty(exports, '__esModule', { - value: true, -}); - -class JSDOMEnvironment extends $JSDOMEnvironment { - constructor(...args) { - const { global } = super(...args); - if (!global.TextEncoder) { - global.TextEncoder = TextEncoder; - } - if (!global.TextDecoder) { - global.TextDecoder = TextDecoder; - } - if (!global.MessageChannel) { - global.MessageChannel = MessageChannel; - } - } -} - -exports.default = JSDOMEnvironment; -exports.TestEnvironment = TestEnvironment === $JSDOMEnvironment ? JSDOMEnvironment : TestEnvironment; diff --git a/pyscriptjs/jest.config.js b/pyscriptjs/jest.config.js deleted file mode 100644 index 788ff3b1..00000000 --- a/pyscriptjs/jest.config.js +++ /dev/null @@ -1,25 +0,0 @@ -//jest.config.js -module.exports = { - preset: 'ts-jest', - setupFilesAfterEnv: ['./tests/unit/setup.ts'], - testEnvironment: './jest-environment-jsdom.js', - extensionsToTreatAsEsm: ['.ts'], - transform: { - '^.+\\.tsx?$': [ - 'ts-jest', - { - tsconfig: 'tsconfig.json', - useESM: true, - }, - ], - }, - verbose: true, - testEnvironmentOptions: { - url: 'http://localhost', - }, - moduleNameMapper: { - '^.*?pyscript.py$': '/__mocks__/_pyscript.js', - '^[./a-zA-Z0-9$_-]+\\.py$': '/__mocks__/fileMock.js', - '\\.(css)$': '/__mocks__/cssMock.js', - }, -}; diff --git a/pyscriptjs/package-lock.json b/pyscriptjs/package-lock.json deleted file mode 100644 index 50639199..00000000 --- a/pyscriptjs/package-lock.json +++ /dev/null @@ -1,10525 +0,0 @@ -{ - "name": "pyscript", - "version": "0.0.1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "pyscript", - "version": "0.0.1", - "dependencies": { - "basic-devtools": "^0.1.6", - "not-so-weak": "^1.0.0" - }, - "devDependencies": { - "@codemirror/commands": "^6.2.2", - "@codemirror/lang-python": "^6.1.2", - "@codemirror/language": "^6.6.0", - "@codemirror/state": "^6.2.0", - "@codemirror/theme-one-dark": "^6.1.1", - "@codemirror/view": "^6.9.3", - "@hoodmane/toml-j0.4": "^1.1.2", - "@jest/globals": "29.1.2", - "@types/codemirror": "^5.60.5", - "@types/jest": "29.1.2", - "@types/node": "18.8.3", - "@typescript-eslint/eslint-plugin": "5.58.0", - "@typescript-eslint/parser": "5.58.0", - "codemirror": "6.0.1", - "cross-env": "7.0.3", - "esbuild": "0.17.12", - "eslint": "8.25.0", - "jest": "29.1.2", - "jest-environment-jsdom": "29.1.2", - "prettier": "2.7.1", - "pyodide": "0.23.2", - "synclink": "0.2.4", - "ts-jest": "29.0.3", - "typescript": "5.0.4", - "xterm": "^5.1.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@babel/core/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/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/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/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz", - "integrity": "sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.6.0", - "@lezer/common": "^1.0.0" - }, - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/commands": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz", - "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.2.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-python": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.2.tgz", - "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==", - "dev": true, - "dependencies": { - "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" - } - }, - "node_modules/@codemirror/language": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", - "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/lint": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.0.tgz", - "integrity": "sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/search": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz", - "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/state": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", - "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", - "dev": true - }, - "node_modules/@codemirror/theme-one-dark": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz", - "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, - "node_modules/@codemirror/view": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.3.tgz", - "integrity": "sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "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": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@hoodmane/toml-j0.4": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@hoodmane/toml-j0.4/-/toml-j0.4-1.1.2.tgz", - "integrity": "sha512-vQvFpjssFt39GcYwsFLDts6eReKSWeDwFt3AufXnM62ACIG2MgvOVomNRo4kQUYV0G3+zpu4LezUWw5JCFgF0Q==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "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/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.1.2.tgz", - "integrity": "sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.1.2", - "@jest/expect": "^29.1.2", - "@jest/types": "^29.1.2", - "jest-mock": "^29.1.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@lezer/common": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", - "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==", - "dev": true - }, - "node_modules/@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dev": true, - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", - "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==", - "dev": true, - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/python": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.3.tgz", - "integrity": "sha512-rUdt5/H8JjVY3YIROZF2ZNUMx7eYB7h0cmC8c4TfkgJt4xcn6vLpjCOCk1usP4vV3YfMC+VDB786dKjJ6tL5Hw==", - "dev": true, - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "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/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/codemirror": { - "version": "5.60.7", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.7.tgz", - "integrity": "sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA==", - "dev": true, - "dependencies": { - "@types/tern": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "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/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.23", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", - "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "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/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/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "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-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, - "dependencies": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.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-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "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/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/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-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/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "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/base-64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", - "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", - "dev": true - }, - "node_modules/basic-devtools": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/basic-devtools/-/basic-devtools-0.1.6.tgz", - "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==" - }, - "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.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001469", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", - "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "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/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dev": true, - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "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/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/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/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "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/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": 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/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.334", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", - "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-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/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/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/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/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/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.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/esquery/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/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/esrecurse/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/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/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/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "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/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/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/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "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/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "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/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "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/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "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-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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-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-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/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/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.1.2", - "@jest/types": "^29.1.2", - "import-local": "^3.0.2", - "jest-cli": "^29.1.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.1.2.tgz", - "integrity": "sha512-D+XNIKia5+uDjSMwL/G1l6N9MCb7LymKI8FpcLo7kkISjc/Sa9w+dXXEa7u1Wijo3f8sVLqfxdGqYtRhmca+Xw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.1.2", - "@jest/fake-timers": "^29.1.2", - "@jest/types": "^29.1.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.1.2", - "jest-util": "^29.1.2", - "jsdom": "^20.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "acorn": "^8.8.1", - "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.2", - "parse5": "^7.1.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "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/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "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/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "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.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "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/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/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/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "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/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "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/node-fetch/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/node-fetch/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/node-fetch/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/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/not-so-weak": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz", - "integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ==" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "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/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "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/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/pyodide": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.23.2.tgz", - "integrity": "sha512-GK4YDZVgzfAXK/7X0IiCI+142k0Ah/HwYTzDHtG8zC47dflWYuPozeFbOngShuL1M9Un5sCmHFqiH3boxJv0pQ==", - "dev": true, - "dependencies": { - "base-64": "^1.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.5.0" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "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-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "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/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "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/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/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/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/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/semver/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/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/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "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": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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/style-mod": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.2.tgz", - "integrity": "sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ==", - "dev": true - }, - "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/symbol-tree": { - "version": "3.2.4", - "dev": true, - "license": "MIT" - }, - "node_modules/synclink": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/synclink/-/synclink-0.2.4.tgz", - "integrity": "sha512-wgG4jQgPe1OPgE7gJgP3/3jCiVkEcXr1jzl+7pbGtBtp7Og2o337YGNYFwCz2ulERKoYzPyYMCDfAYjShgzCTg==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "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/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-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/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "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/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "dev": true - }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "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": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "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/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xterm": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz", - "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "dev": true - }, - "@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", - "dev": true, - "requires": { - "@babel/types": "^7.21.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@codemirror/autocomplete": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz", - "integrity": "sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.6.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/commands": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz", - "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.2.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/lang-python": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.2.tgz", - "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==", - "dev": true, - "requires": { - "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" - } - }, - "@codemirror/language": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", - "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "@codemirror/lint": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.0.tgz", - "integrity": "sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/search": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz", - "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/state": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", - "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", - "dev": true - }, - "@codemirror/theme-one-dark": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz", - "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, - "@codemirror/view": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.3.tgz", - "integrity": "sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow==", - "dev": true, - "requires": { - "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", - "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": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@hoodmane/toml-j0.4": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@hoodmane/toml-j0.4/-/toml-j0.4-1.1.2.tgz", - "integrity": "sha512-vQvFpjssFt39GcYwsFLDts6eReKSWeDwFt3AufXnM62ACIG2MgvOVomNRo4kQUYV0G3+zpu4LezUWw5JCFgF0Q==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@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 - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - } - }, - "@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "requires": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - } - }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3" - } - }, - "@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "@jest/globals": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.1.2.tgz", - "integrity": "sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g==", - "dev": true, - "requires": { - "@jest/environment": "^29.1.2", - "@jest/expect": "^29.1.2", - "@jest/types": "^29.1.2", - "jest-mock": "^29.1.2" - } - }, - "@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - } - }, - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@lezer/common": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", - "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==", - "dev": true - }, - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dev": true, - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", - "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==", - "dev": true, - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/python": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.3.tgz", - "integrity": "sha512-rUdt5/H8JjVY3YIROZF2ZNUMx7eYB7h0cmC8c4TfkgJt4xcn6vLpjCOCk1usP4vV3YfMC+VDB786dKjJ6tL5Hw==", - "dev": true, - "requires": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "@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" - } - }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/codemirror": { - "version": "5.60.7", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.7.tgz", - "integrity": "sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA==", - "dev": true, - "requires": { - "@types/tern": "*" - } - }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "dev": true, - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "@types/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "@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/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.23", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", - "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "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" - } - }, - "@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" - } - }, - "abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "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-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, - "requires": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "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-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "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" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "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-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 - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "requires": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "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 - }, - "base-64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", - "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", - "dev": true - }, - "basic-devtools": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/basic-devtools/-/basic-devtools-0.1.6.tgz", - "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==" - }, - "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.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001469", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", - "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", - "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" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dev": true, - "requires": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "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 - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", - "dev": true - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - } - }, - "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" - } - }, - "decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "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 - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "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" - } - }, - "domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "requires": { - "webidl-conversions": "^7.0.0" - } - }, - "electron-to-chromium": { - "version": "1.4.334", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", - "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": 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 - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "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" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.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" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "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" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "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 - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "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" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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 - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "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 - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "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" - } - }, - "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" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "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 - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "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" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.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 - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "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-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "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-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-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw==", - "dev": true, - "requires": { - "@jest/core": "^29.1.2", - "@jest/types": "^29.1.2", - "import-local": "^3.0.2", - "jest-cli": "^29.1.2" - } - }, - "jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - } - }, - "jest-environment-jsdom": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.1.2.tgz", - "integrity": "sha512-D+XNIKia5+uDjSMwL/G1l6N9MCb7LymKI8FpcLo7kkISjc/Sa9w+dXXEa7u1Wijo3f8sVLqfxdGqYtRhmca+Xw==", - "dev": true, - "requires": { - "@jest/environment": "^29.1.2", - "@jest/fake-timers": "^29.1.2", - "@jest/types": "^29.1.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.1.2", - "jest-util": "^29.1.2", - "jsdom": "^20.0.0" - } - }, - "jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true - }, - "jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true - }, - "jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - } - }, - "jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - } - }, - "jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - } - } - } - }, - "jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - } - }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "acorn": "^8.8.1", - "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.2", - "parse5": "^7.1.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", - "xml-name-validator": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "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" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "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.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "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 - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "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" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "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 - }, - "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" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "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 - }, - "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" - } - } - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "not-so-weak": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz", - "integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "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" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "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" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "requires": { - "entities": "^4.4.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 - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true - }, - "pyodide": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.23.2.tgz", - "integrity": "sha512-GK4YDZVgzfAXK/7X0IiCI+142k0Ah/HwYTzDHtG8zC47dflWYuPozeFbOngShuL1M9Un5sCmHFqiH3boxJv0pQ==", - "dev": true, - "requires": { - "base-64": "^1.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.5.0" - } - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "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-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "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 - }, - "resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", - "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" - } - }, - "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" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "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" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "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 - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "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-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "style-mod": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.2.tgz", - "integrity": "sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ==", - "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 - }, - "symbol-tree": { - "version": "3.2.4", - "dev": true - }, - "synclink": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/synclink/-/synclink-0.2.4.tgz", - "integrity": "sha512-wgG4jQgPe1OPgE7gJgP3/3jCiVkEcXr1jzl+7pbGtBtp7Og2o337YGNYFwCz2ulERKoYzPyYMCDfAYjShgzCTg==", - "dev": true - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "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 - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - } - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-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 - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true - }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "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" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - } - } - }, - "w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "dev": true - }, - "w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "requires": { - "xml-name-validator": "^4.0.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "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": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - }, - "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" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xterm": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz", - "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "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/pyscriptjs/package.json b/pyscriptjs/package.json deleted file mode 100644 index a86c47d3..00000000 --- a/pyscriptjs/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "pyscript", - "version": "0.0.1", - "scripts": { - "build": "npm run tsc && node esbuild.mjs", - "dev": "NODE_WATCH=1 node esbuild.mjs", - "tsc": "tsc --noEmit", - "format:check": "prettier --check './src/**/*.{mjs,js,html,ts}'", - "format": "prettier --write './src/**/*.{mjs,js,html,ts}'", - "lint": "eslint './src/**/*.{mjs,js,html,ts}'", - "lint:fix": "eslint --fix './src/**/*.{mjs,js,html,ts}'", - "xprelint": "npm run format", - "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage", - "test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch" - }, - "devDependencies": { - "@codemirror/commands": "^6.2.2", - "@codemirror/lang-python": "^6.1.2", - "@codemirror/language": "^6.6.0", - "@codemirror/state": "^6.2.0", - "@codemirror/theme-one-dark": "^6.1.1", - "@codemirror/view": "^6.9.3", - "@hoodmane/toml-j0.4": "^1.1.2", - "@jest/globals": "29.1.2", - "@types/codemirror": "^5.60.5", - "@types/jest": "29.1.2", - "@types/node": "18.8.3", - "@typescript-eslint/eslint-plugin": "5.58.0", - "@typescript-eslint/parser": "5.58.0", - "codemirror": "6.0.1", - "cross-env": "7.0.3", - "esbuild": "0.17.12", - "eslint": "8.25.0", - "jest": "29.1.2", - "jest-environment-jsdom": "29.1.2", - "prettier": "2.7.1", - "pyodide": "0.23.2", - "synclink": "0.2.4", - "ts-jest": "29.0.3", - "typescript": "5.0.4", - "xterm": "^5.1.0" - }, - "dependencies": { - "basic-devtools": "^0.1.6", - "not-so-weak": "^1.0.0" - } -} diff --git a/pyscriptjs/public/.gitkeep b/pyscriptjs/public/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/pyscriptjs/src/components/elements.ts b/pyscriptjs/src/components/elements.ts deleted file mode 100644 index 7f3336d7..00000000 --- a/pyscriptjs/src/components/elements.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { InterpreterClient } from '../interpreter_client'; -import type { PyScriptApp } from '../main'; -import { make_PyRepl } from './pyrepl'; - -function createCustomElements(interpreter: InterpreterClient, app: PyScriptApp) { - const PyRepl = make_PyRepl(interpreter, app); - - customElements.define('py-repl', PyRepl); -} - -export { createCustomElements }; diff --git a/pyscriptjs/src/components/pyrepl.ts b/pyscriptjs/src/components/pyrepl.ts deleted file mode 100644 index 20034641..00000000 --- a/pyscriptjs/src/components/pyrepl.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { $, $$ } from 'basic-devtools'; - -import { basicSetup, EditorView } from 'codemirror'; -import { python } from '@codemirror/lang-python'; -import { indentUnit } from '@codemirror/language'; -import { Compartment } from '@codemirror/state'; -import { keymap, Command } from '@codemirror/view'; -import { defaultKeymap } from '@codemirror/commands'; -import { oneDarkTheme } from '@codemirror/theme-one-dark'; - -import { ensureUniqueId, htmlDecode } from '../utils'; -import { pyExec } from '../pyexec'; -import { getLogger } from '../logger'; -import { InterpreterClient } from '../interpreter_client'; -import type { PyScriptApp } from '../main'; -import { Stdio } from '../stdio'; -import { robustFetch } from '../fetch'; -import { _createAlertBanner } from '../exceptions'; - -const logger = getLogger('py-repl'); -const RUNBUTTON = ``; - -export function make_PyRepl(interpreter: InterpreterClient, app: PyScriptApp) { - /* High level structure of py-repl DOM, and the corresponding JS names. - - this - boxDiv
- editorDiv
- outDiv
-
-
- */ - class PyRepl extends HTMLElement { - outDiv: HTMLElement; - editor: EditorView; - stdout_manager: Stdio | null; - stderr_manager: Stdio | null; - static observedAttributes = ['src']; - connectedCallback() { - ensureUniqueId(this); - - if (!this.hasAttribute('exec-id')) { - this.setAttribute('exec-id', '0'); - } - if (!this.hasAttribute('root')) { - this.setAttribute('root', this.id); - } - - const pySrc = htmlDecode(this.innerHTML).trim(); - this.innerHTML = ''; - const boxDiv = this.makeBoxDiv(); - const shadowRoot = $('.py-repl-editor > div', boxDiv).attachShadow({ mode: 'open' }); - // avoid inheriting styles from the outer component - shadowRoot.innerHTML = ``; - this.appendChild(boxDiv); - this.editor = this.makeEditor(pySrc, shadowRoot); - this.editor.focus(); - logger.debug(`element ${this.id} successfully connected`); - } - - get src() { - return this.getAttribute('src'); - } - - set src(value) { - this.setAttribute('src', value); - } - - attributeChangedCallback(name: string, oldVal: string, newVal: string) { - if (name === 'src' && newVal !== oldVal) { - void this.loadReplSrc(); - } - } - - /** - * Fetch url from src attribute of py-repl tags and - * preload the code from fetch response into the Corresponding py-repl tag, - * but please note that they will not be pre-run unless you click the runbotton. - */ - async loadReplSrc() { - try { - const response = await robustFetch(this.src); - if (!response.ok) { - return; - } - const cmcontentElement = $('div.cm-content', this.editor.dom); - const { lastElementChild } = cmcontentElement; - cmcontentElement.replaceChildren(lastElementChild); - lastElementChild.textContent = await response.text(); - logger.info(`loading code from ${this.src} to repl...success`); - } catch (err) { - const e = err as Error; - _createAlertBanner(e.message); - } - } - - /** Create and configure the codemirror editor - */ - makeEditor(pySrc: string, parent: ShadowRoot): EditorView { - const languageConf = new Compartment(); - const extensions = [ - indentUnit.of(' '), - basicSetup, - languageConf.of(python()), - keymap.of([ - ...defaultKeymap, - { key: 'Ctrl-Enter', run: this.execute.bind(this) as Command, preventDefault: true }, - { key: 'Shift-Enter', run: this.execute.bind(this) as Command, preventDefault: true }, - ]), - ]; - - if (this.getAttribute('theme') === 'dark') { - extensions.push(oneDarkTheme); - } - - return new EditorView({ - doc: pySrc, - extensions, - parent, - }); - } - - // ******** main entry point for py-repl DOM building ********** - // - // The following functions are written in a top-down, depth-first - // order (so that the order of code roughly matches the order of - // execution) - makeBoxDiv(): HTMLElement { - const boxDiv = document.createElement('div'); - boxDiv.className = 'py-repl-box'; - - const editorDiv = this.makeEditorDiv(); - this.outDiv = this.makeOutDiv(); - - boxDiv.appendChild(editorDiv); - boxDiv.appendChild(this.outDiv); - - return boxDiv; - } - - makeEditorDiv(): HTMLElement { - const editorDiv = document.createElement('div'); - editorDiv.className = 'py-repl-editor'; - editorDiv.setAttribute('aria-label', 'Python Script Area'); - - const runButton = this.makeRunButton(); - const editorShadowContainer = document.createElement('div'); - - // avoid outer elements intercepting key events (reveal as example) - editorShadowContainer.addEventListener('keydown', event => { - event.stopPropagation(); - }); - - editorDiv.append(editorShadowContainer, runButton); - - return editorDiv; - } - - makeRunButton(): HTMLElement { - const runButton = document.createElement('button'); - runButton.className = 'absolute py-repl-run-button'; - runButton.innerHTML = RUNBUTTON; - runButton.setAttribute('aria-label', 'Python Script Run Button'); - runButton.addEventListener('click', this.execute.bind(this) as (e: MouseEvent) => void); - return runButton; - } - - makeOutDiv(): HTMLElement { - const outDiv = document.createElement('div'); - outDiv.className = 'py-repl-output'; - outDiv.id = this.id + '-repl-output'; - return outDiv; - } - - // ********************* execution logic ********************* - - /** Execute the python code written in the editor, and automatically - * display() the last evaluated expression - */ - async execute(): Promise { - const pySrc = this.getPySrc(); - const outEl = this.outDiv; - - // execute the python code - await app.plugins.beforePyReplExec({ interpreter: interpreter, src: pySrc, outEl: outEl, pyReplTag: this }); - const { result } = await pyExec(interpreter, pySrc, outEl); - await app.plugins.afterPyReplExec({ - interpreter: interpreter, - src: pySrc, - outEl: outEl, - pyReplTag: this, - result, - }); - - this.autogenerateMaybe(); - } - - getPySrc(): string { - return this.editor.state.doc.toString(); - } - - // XXX the autogenerate logic is very messy. We should redo it, and it - // should be the default. - autogenerateMaybe(): void { - if (this.hasAttribute('auto-generate')) { - const allPyRepls = $$(`py-repl[root='${this.getAttribute('root')}'][exec-id]`, document); - const lastRepl = allPyRepls[allPyRepls.length - 1]; - const lastExecId = lastRepl.getAttribute('exec-id'); - const nextExecId = parseInt(lastExecId) + 1; - - const newPyRepl = document.createElement('py-repl'); - - //Attributes to be copied from old REPL to auto-generated REPL - for (const attribute of ['root', 'output-mode', 'output', 'stderr']) { - const attr = this.getAttribute(attribute); - if (attr) { - newPyRepl.setAttribute(attribute, attr); - } - } - - newPyRepl.id = this.getAttribute('root') + '-' + nextExecId.toString(); - - if (this.hasAttribute('auto-generate')) { - newPyRepl.setAttribute('auto-generate', ''); - this.removeAttribute('auto-generate'); - } - - newPyRepl.setAttribute('exec-id', nextExecId.toString()); - if (this.parentElement) { - this.parentElement.appendChild(newPyRepl); - } - } - } - } - - return PyRepl; -} diff --git a/pyscriptjs/src/components/pyscript.ts b/pyscriptjs/src/components/pyscript.ts deleted file mode 100644 index 722ef8ed..00000000 --- a/pyscriptjs/src/components/pyscript.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { $$, $x } from 'basic-devtools'; - -import { shadowRoots } from '../shadow_roots'; -import { ltrim, htmlDecode, ensureUniqueId, createDeprecationWarning } from '../utils'; -import { getLogger } from '../logger'; -import { pyExec, displayPyException } from '../pyexec'; -import { _createAlertBanner } from '../exceptions'; -import { robustFetch } from '../fetch'; -import { PyScriptApp } from '../main'; -import { Stdio } from '../stdio'; -import { InterpreterClient } from '../interpreter_client'; - -const logger = getLogger('py-script'); - -// used to flag already initialized nodes -const knownPyScriptTags: WeakSet = new WeakSet(); - -export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp) { - /** - * A common VS ", -} - - -def eval_formatter(obj, print_method): - """ - Evaluates a formatter method. - """ - if print_method == "__repr__": - return repr(obj) - elif hasattr(obj, print_method): - if print_method == "savefig": - buf = io.BytesIO() - obj.savefig(buf, format="png") - buf.seek(0) - return base64.b64encode(buf.read()).decode("utf-8") - return getattr(obj, print_method)() - elif print_method == "_repr_mimebundle_": - return {}, {} - return None - - -def format_mime(obj): - """ - Formats object using _repr_x_ methods. - """ - if isinstance(obj, str): - return html.escape(obj), "text/plain" - - mimebundle = eval_formatter(obj, "_repr_mimebundle_") - if isinstance(mimebundle, tuple): - format_dict, _ = mimebundle - else: - format_dict = mimebundle - - output, not_available = None, [] - for method, mime_type in reversed(MIME_METHODS.items()): - if mime_type in format_dict: - output = format_dict[mime_type] - else: - output = eval_formatter(obj, method) - - if output is None: - continue - elif mime_type not in MIME_RENDERERS: - not_available.append(mime_type) - continue - break - if output is None: - if not_available: - console.warn( - f"Rendered object requested unavailable MIME renderers: {not_available}" - ) - output = repr(output) - mime_type = "text/plain" - elif isinstance(output, tuple): - output, meta = output - else: - meta = {} - return MIME_RENDERERS[mime_type](output, meta), mime_type diff --git a/pyscriptjs/src/python/pyscript/_plugin.py b/pyscriptjs/src/python/pyscript/_plugin.py deleted file mode 100644 index f870217f..00000000 --- a/pyscriptjs/src/python/pyscript/_plugin.py +++ /dev/null @@ -1,66 +0,0 @@ -from _pyscript_js import define_custom_element -from js import console -from pyodide.ffi import create_proxy - - -class Plugin: - def __init__(self, name=None): - if not name: - name = self.__class__.__name__ - - self.name = name - self._custom_elements = [] - self.app = None - - def init(self, app): - self.app = app - - def configure(self, config): - pass - - def afterSetup(self, interpreter): - pass - - def afterStartup(self, interpreter): - pass - - def beforePyScriptExec(self, interpreter, src, pyScriptTag): - pass - - def afterPyScriptExec(self, interpreter, src, pyScriptTag, result): - pass - - def beforePyReplExec(self, interpreter, src, outEl, pyReplTag): - pass - - def afterPyReplExec(self, interpreter, src, outEl, pyReplTag, result): - pass - - def onUserError(self, error): - pass - - def register_custom_element(self, tag): - """ - Decorator to register a new custom element as part of a Plugin and associate - tag to it. Internally, it delegates the registration to the PyScript internal - [JS] plugin manager, who actually creates the JS custom element that can be - attached to the page and instantiate an instance of the class passing the custom - element to the plugin constructor. - - Exammple: - >> plugin = Plugin("PyTutorial") - >> @plugin.register_custom_element("py-tutor") - >> class PyTutor: - >> def __init__(self, element): - >> self.element = element - """ - # TODO: Ideally would be better to use the logger. - console.info(f"Defining new custom element {tag}") - - def wrapper(class_): - # TODO: this is very pyodide specific but will have to do - # until we have JS interface that works across interpreters - define_custom_element(tag, create_proxy(class_)) # noqa: F821 - - self._custom_elements.append(tag) - return create_proxy(wrapper) diff --git a/pyscriptjs/src/python_package.ts b/pyscriptjs/src/python_package.ts deleted file mode 100644 index beac1ff7..00000000 --- a/pyscriptjs/src/python_package.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file exists because I can only convince jest to mock real file system -// files, not fake modules. This confuses me because jest.mock has a virtual -// option for mocking things that don't live in the file system but it doesn't -// seem to work. - -// @ts-ignore -import python_package from 'pyscript_python_package.esbuild_injected.json'; -declare const python_package: { dirs: string[]; files: [string, string][] }; -export { python_package }; diff --git a/pyscriptjs/src/remote_interpreter.ts b/pyscriptjs/src/remote_interpreter.ts deleted file mode 100644 index 1585f9eb..00000000 --- a/pyscriptjs/src/remote_interpreter.ts +++ /dev/null @@ -1,294 +0,0 @@ -import type { AppConfig } from './pyconfig'; -import { version } from './version'; -import { getLogger } from './logger'; -import { Stdio } from './stdio'; -import { InstallError, ErrorCode } from './exceptions'; -import { robustFetch } from './fetch'; -import type { loadPyodide as loadPyodideDeclaration, PyodideInterface, PyProxy, PyProxyDict } from 'pyodide'; -import type { ProxyMarked } from 'synclink'; -import * as Synclink from 'synclink'; -import { showWarning } from './utils'; -import { define_custom_element } from './plugin'; -import { deepQuerySelector } from './shadow_roots'; - -import { python_package } from './python_package'; - -declare const loadPyodide: typeof loadPyodideDeclaration; -const logger = getLogger('pyscript/pyodide'); - -export type InterpreterInterface = (PyodideInterface & ProxyMarked) | null; - -interface Micropip extends PyProxy { - install(packageName: string | string[]): Promise; -} - -type FSInterface = { - writeFile(path: string, data: Uint8Array | string, options?: { canOwn?: boolean; encoding?: string }): void; - mkdirTree(path: string): void; - mkdir(path: string): void; -} & ProxyMarked; - -type PATHFSInterface = { - resolve(path: string): string; -} & ProxyMarked; - -type PATHInterface = { - dirname(path: string): string; -} & ProxyMarked; - -type PyScriptInternalModule = ProxyMarked & { - set_version_info(ver: string): void; - uses_top_level_await(code: string): boolean; - run_pyscript(code: string, display_target_id?: string): { result: any }; - install_pyscript_loop(): void; - start_loop(): void; - schedule_deferred_tasks(): void; -}; - -/* -RemoteInterpreter class is responsible to process requests from the -`InterpreterClient` class -- these can be requests for installation of -a package, executing code, etc. - -Currently, the only interpreter available is Pyodide as indicated by the -`InterpreterInterface` type above. This serves as a Union of types of -different interpreters which will be added in near future. - -Methods available handle loading of the interpreter, initialization, -running code, loading and installation of packages, loading from files etc. - -The class will be turned `abstract` in future, to support more runtimes -such as MicroPython. - */ -export class RemoteInterpreter extends Object { - src: string; - interface: InterpreterInterface; - FS: FSInterface; - PATH: PATHInterface; - PATH_FS: PATHFSInterface; - pyscript_internal: PyScriptInternalModule; - - globals: PyProxyDict & ProxyMarked; - // TODO: Remove this once `runtimes` is removed! - interpreter: InterpreterInterface & ProxyMarked; - - constructor(src = 'https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js') { - super(); - this.src = src; - } - - /** - * loads the interface for the interpreter and saves an instance of it - * in the `this.interface` property along with calling of other - * additional convenience functions. - * */ - - /** - * Although `loadPyodide` is used below, - * notice that it is not imported i.e. - * import { loadPyodide } from 'pyodide'; - * is not used at the top of this file. - * - * This is because, if it's used, loadPyodide - * behaves mischievously i.e. it tries to load - * additional files but with paths that are wrong such as: - * - * http://127.0.0.1:8080/build/... - * which results in a 404 since `build` doesn't - * contain these files and is clearly the wrong - * path. - */ - async loadInterpreter(config: AppConfig, stdio: Synclink.Remote): Promise { - // TODO: move this to "main thread"! - const _pyscript_js_main = { define_custom_element, showWarning, deepQuerySelector }; - - this.interface = Synclink.proxy( - await loadPyodide({ - stdout: (msg: string) => { - stdio.stdout_writeline(msg).syncify(); - }, - stderr: (msg: string) => { - stdio.stderr_writeline(msg).syncify(); - }, - fullStdLib: false, - }), - ); - this.interface.registerComlink(Synclink); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - this.FS = this.interface.FS; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - this.PATH = (this.interface as any)._module.PATH; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - this.PATH_FS = (this.interface as any)._module.PATH_FS; - - // TODO: Remove this once `runtimes` is removed! - this.interpreter = this.interface; - this.interface.registerJsModule('_pyscript_js', _pyscript_js_main); - - // Write pyscript package into file system - for (const dir of python_package.dirs) { - this.FS.mkdir('/home/pyodide/' + dir); - } - for (const [path, value] of python_package.files) { - this.FS.writeFile('/home/pyodide/' + path, value); - } - //Refresh the module cache so Python consistently finds pyscript module - this.invalidate_module_path_cache(); - - this.globals = Synclink.proxy(this.interface.globals as PyProxyDict); - logger.info('importing pyscript'); - this.pyscript_internal = Synclink.proxy(this.interface.pyimport('pyscript._internal')) as PyProxy & - typeof this.pyscript_internal; - this.pyscript_internal.set_version_info(version); - this.pyscript_internal.install_pyscript_loop(); - - if (config.packages) { - logger.info('Found packages in configuration to install. Loading micropip...'); - await this.loadPackage('micropip'); - } - // import some carefully selected names into the global namespace - this.interface.runPython(` - import js - import pyscript - from pyscript import Element, display, HTML - `); - - logger.info('pyodide loaded and initialized'); - } - - /** - * delegates the registration of JS modules to - * the underlying interface. - * */ - registerJsModule(name: string, module: object): void { - this.interface.registerJsModule(name, module); - } - - /** - * delegates the loading of packages to - * the underlying interface. - * */ - async loadPackage(names: string | string[]): Promise { - logger.info(`pyodide.loadPackage: ${names.toString()}`); - // The signature of `loadPackage` changed in Pyodide 0.22; while we generally - // don't support older versions of Pyodide in any given release of PyScript, this - // significant change is useful in some testing scenarios (for now) - const messageCallback = logger.info.bind(logger) as typeof logger.info; - // Comparing version as number to avoid issues with lexicographic comparison - if (Number(this.interpreter.version.split('.')[1]) >= 22) { - await this.interface.loadPackage(names, { - messageCallback, - errorCallback: messageCallback, - }); - } else { - // @ts-expect-error Types don't include this deprecated call signature - await this.interface.loadPackage(names, messageCallback, messageCallback); - } - } - - /** - * delegates the installation of packages - * (using a package manager, which can be specific to - * the interface) to the underlying interface. - * - * For Pyodide, we use `micropip` - * */ - async installPackage(package_name: string | string[]): Promise { - if (package_name.length > 0) { - logger.info(`micropip install ${package_name.toString()}`); - - const micropip = this.interface.pyimport('micropip') as Micropip; - try { - await micropip.install(package_name); - micropip.destroy(); - } catch (err) { - const e = err as Error; - let fmt_names: string; - if (Array.isArray(package_name)) { - fmt_names = package_name.join(', '); - } else { - fmt_names = package_name; - } - let exceptionMessage = `Unable to install package(s) '${fmt_names}'.`; - - // If we can't fetch `package_name` micropip.install throws a huge - // Python traceback in `e.message` this logic is to handle the - // error and throw a more sensible error message instead of the - // huge traceback. - if (e.message.includes("Can't find a pure Python 3 wheel")) { - exceptionMessage += - ` Reason: Can't find a pure Python 3 Wheel for package(s) '${fmt_names}'.` + - `See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel ` + - `for more information.`; - } else if (e.message.includes("Can't fetch metadata")) { - exceptionMessage += - ' Unable to find package in PyPI. ' + - 'Please make sure you have entered a correct package name.'; - } else { - exceptionMessage += - ` Reason: ${e.message}. Please open an issue at ` + - `https://github.com/pyscript/pyscript/issues/new if you require help or ` + - `you think it's a bug.`; - } - - logger.error(e); - - throw new InstallError(ErrorCode.MICROPIP_INSTALL_ERROR, exceptionMessage); - } - } - } - - /** - * - * @param path : the path in the filesystem - * @param url : the url to be fetched - * - * Given a file available at `url` URL (eg: `http://dummy.com/hi.py`), the - * function downloads the file and saves it to the `path` (eg: - * `a/b/c/foo.py`) on the FS. - * - * Example usage: await loadFromFile(`a/b/c/foo.py`, - * `http://dummy.com/hi.py`) - * - * Write content of `http://dummy.com/hi.py` to `a/b/c/foo.py` - * - * NOTE: The `path` parameter expects to have the `filename` in it i.e. - * `a/b/c/foo.py` is valid while `a/b/c` (i.e. only the folders) are - * incorrect. - * - * The path will be resolved relative to the current working directory, - * which is initially `/home/pyodide`. So by default `a/b.py` will be placed - * in `/home/pyodide/a/b.py`, `../a/b.py` will be placed into `/home/a/b.py` - * and `/a/b.py` will be placed into `/a/b.py`. - */ - async loadFileFromURL(path: string, url: string): Promise { - path = this.PATH_FS.resolve(path); - const dir: string = this.PATH.dirname(path); - this.FS.mkdirTree(dir); - - // `robustFetch` checks for failures in getting a response - const response = await robustFetch(url); - const buffer = await response.arrayBuffer(); - const data = new Uint8Array(buffer); - - this.FS.writeFile(path, data, { canOwn: true }); - } - - /** - * delegates clearing importlib's module path - * caches to the underlying interface - */ - invalidate_module_path_cache(): void { - const importlib = this.interface.pyimport('importlib') as PyProxy & { invalidate_caches(): void }; - importlib.invalidate_caches(); - } - - pyimport(mod_name: string): PyProxy & Synclink.ProxyMarked { - return Synclink.proxy(this.interface.pyimport(mod_name)); - } - - setHandler(func_name: string, handler: any): void { - const pyscript_module = this.interface.pyimport('pyscript'); - pyscript_module[func_name] = handler; - } -} diff --git a/pyscriptjs/src/shadow_roots.ts b/pyscriptjs/src/shadow_roots.ts deleted file mode 100644 index c8307435..00000000 --- a/pyscriptjs/src/shadow_roots.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $ } from 'basic-devtools'; -import { WSet } from 'not-so-weak'; - -// weakly retain shadow root nodes in an iterable way -// so that it's possible to query these and find elements by ID -export const shadowRoots: WSet = new WSet(); - -// returns an element by ID if present within any of the live shadow roots -const findInShadowRoots = (selector: string): Element | null => { - for (const shadowRoot of shadowRoots) { - const element = $(selector, shadowRoot); - if (element) return element; - } - return null; -}; - -// find an element by ID either via document or via any live shadow root -export const deepQuerySelector = (selector: string) => $(selector, document) || findInShadowRoots(selector); diff --git a/pyscriptjs/src/stdio.ts b/pyscriptjs/src/stdio.ts deleted file mode 100644 index 492a6897..00000000 --- a/pyscriptjs/src/stdio.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { $ } from 'basic-devtools'; - -import { createSingularWarning, escape } from './utils'; - -export interface Stdio { - stdout_writeline: (msg: string) => void; - stderr_writeline: (msg: string) => void; -} - -/** Default implementation of Stdio: stdout and stderr are both sent to the - * console - */ -export const DEFAULT_STDIO: Stdio = { - stdout_writeline: console.log, - stderr_writeline: console.log, -}; - -/** Stdio provider which captures and store the messages. - * Useful for tests. - */ -export class CaptureStdio implements Stdio { - captured_stdout: string; - captured_stderr: string; - - constructor() { - this.reset(); - } - - reset() { - this.captured_stdout = ''; - this.captured_stderr = ''; - } - - stdout_writeline(msg: string) { - this.captured_stdout += msg + '\n'; - } - - stderr_writeline(msg: string) { - this.captured_stderr += msg + '\n'; - } -} - -/** Stdio provider for sending output to DOM element - * specified by ID. Used with "output" keyword. - * - */ -export class TargetedStdio implements Stdio { - source_element: HTMLElement; - source_attribute: string; - capture_stdout: boolean; - capture_stderr: boolean; - - constructor(source_element: HTMLElement, source_attribute: string, capture_stdout = true, capture_stderr = true) { - this.source_element = source_element; - this.source_attribute = source_attribute; - this.capture_stdout = capture_stdout; - this.capture_stderr = capture_stderr; - } - - /** Writes the given msg to an element with a given ID. The ID is the value an attribute - * of the source_element specified by source_attribute. - * Both the element to be targeted and the ID of the element to write to - * are determined at write-time, not when the TargetdStdio object is - * created. This way, if either the 'output' attribute of the HTML tag - * or the ID of the target element changes during execution of the Python - * code, the output is still routed (or not) as expected - * - * @param msg The output to be written - */ - writeline_by_attribute(msg: string) { - const target_id = this.source_element.getAttribute(this.source_attribute); - const target = $('#' + target_id, document); - if (target === null) { - // No matching ID - createSingularWarning( - `${this.source_attribute} = "${target_id}" does not match the id of any element on the page.`, - ); - } else { - msg = escape(msg).replace('\n', '
'); - if (!msg.endsWith('
') && !msg.endsWith('
')) { - msg = msg + '
'; - } - target.innerHTML += msg; - } - } - - stdout_writeline(msg: string) { - if (this.capture_stdout) { - this.writeline_by_attribute(msg); - } - } - - stderr_writeline(msg: string) { - if (this.capture_stderr) { - this.writeline_by_attribute(msg); - } - } -} - -/** Redirect stdio streams to multiple listeners - */ -export class StdioMultiplexer implements Stdio { - _listeners: Stdio[]; - - constructor() { - this._listeners = []; - } - - addListener(obj: Stdio) { - this._listeners.push(obj); - } - - removeListener(obj: Stdio) { - const index = this._listeners.indexOf(obj); - if (index > -1) { - this._listeners.splice(index, 1); - } - } - - stdout_writeline(msg: string) { - for (const obj of this._listeners) obj.stdout_writeline(msg); - } - - stderr_writeline(msg: string) { - for (const obj of this._listeners) obj.stderr_writeline(msg); - } -} diff --git a/pyscriptjs/src/styles/pyscript_base.css b/pyscriptjs/src/styles/pyscript_base.css deleted file mode 100644 index f6edd6a1..00000000 --- a/pyscriptjs/src/styles/pyscript_base.css +++ /dev/null @@ -1,349 +0,0 @@ -/* py-config - not a component */ -py-config { - display: none; -} -/* py-{el} - components not defined */ -py-script:not(:defined) { - display: none; -} - -py-repl:not(:defined) { - display: none; -} - -py-title:not(:defined) { - display: none; -} - -py-inputbox:not(:defined) { - display: none; -} - -py-button:not(:defined) { - display: none; -} - -py-box:not(:defined) { - display: none; -} - -html { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', - Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; - line-height: 1.5; -} - -.spinner::after { - content: ''; - box-sizing: border-box; - width: 40px; - height: 40px; - position: absolute; - top: calc(40% - 20px); - left: calc(50% - 20px); - border-radius: 50%; -} - -.spinner.smooth::after { - border-top: 4px solid rgba(255, 255, 255, 1); - border-left: 4px solid rgba(255, 255, 255, 1); - border-right: 4px solid rgba(255, 255, 255, 0); - animation: spinner 0.6s linear infinite; -} - -@keyframes spinner { - to { - transform: rotate(360deg); - } -} - -.label { - text-align: center; - width: 100%; - display: block; - color: rgba(255, 255, 255, 0.8); - font-size: 0.8rem; - margin-top: 6rem; -} - -/* Pop-up second layer begin */ - -.py-overlay { - position: fixed; - display: flex; - justify-content: center; - align-items: center; - color: white; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: rgba(0, 0, 0, 0.5); - transition: opacity 500ms; - visibility: hidden; - color: visible; - opacity: 1; -} - -.py-overlay { - visibility: visible; - opacity: 1; -} - -.py-pop-up { - text-align: center; - width: 600px; -} - -.py-pop-up p { - margin: 5px; -} - -.py-pop-up a { - position: absolute; - color: white; - text-decoration: none; - font-size: 200%; - top: 3.5%; - right: 5%; -} - -/* Pop-up second layer end */ -.alert-banner { - position: relative; - padding: 0.5rem 1.5rem 0.5rem 0.5rem; - margin: 5px 0; -} - -.alert-banner p { - margin: 0; -} - -.py-error { - background-color: #ffe9e8; - border: solid; - border-color: #f0625f; - color: #9d041c; -} - -.py-warning { - background-color: rgb(255, 244, 229); - border: solid; - border-color: #ffa016; - color: #794700; -} - -.alert-banner.py-error > #alert-close-button { - color: #9d041c; -} - -.alert-banner.py-warning > #alert-close-button { - color: #794700; -} - -#alert-close-button { - position: absolute; - right: 0.5rem; - top: 0.5rem; - cursor: pointer; - background: transparent; - border: none; -} - -.py-box { - display: flex; - flex-direction: row; - justify-content: flex-start; -} - -.py-box div.py-box-child * { - max-width: 100%; -} - -.py-repl-box { - flex-direction: column; -} - -.py-repl-editor { - --tw-border-opacity: 1; - border-color: rgba(209, 213, 219, var(--tw-border-opacity)); - border-width: 1px; - position: relative; - --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgba(59, 130, 246, 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - position: relative; - - box-sizing: border-box; - border-width: 1px; - border-style: solid; - border-color: rgb(209, 213, 219); -} - -.editor-box:hover button { - opacity: 1; -} - -.py-repl-run-button { - opacity: 0; - bottom: 0.25rem; - right: 0.25rem; - position: absolute; - padding: 0; - line-height: inherit; - color: inherit; - cursor: pointer; - background-color: transparent; - background-image: none; - -webkit-appearance: button; - text-transform: none; - font-family: inherit; - font-size: 100%; - margin: 0; - text-rendering: auto; - letter-spacing: normal; - word-spacing: normal; - line-height: normal; - text-transform: none; - text-indent: 0px; - text-shadow: none; - display: inline-block; - text-align: center; - align-items: flex-start; - cursor: default; - box-sizing: border-box; - background-color: -internal-light-dark(rgb(239, 239, 239), rgb(59, 59, 59)); - margin: 0em; - padding: 1px 6px; - border: 0; -} - -.py-repl-run-button:hover { - opacity: 1; -} - -.py-title { - text-transform: uppercase; - text-align: center; -} - -.py-title h1 { - font-weight: 700; - font-size: 1.875rem; -} - -.py-input { - padding: 0.5rem; - --tw-border-opacity: 1; - border-color: rgba(209, 213, 219, var(--tw-border-opacity)); - border-width: 1px; - border-radius: 0.25rem; - margin-right: 0.75rem; - border-style: solid; - width: auto; -} - -.py-box input.py-input { - width: -webkit-fill-available; -} - -.central-content { - max-width: 20rem; - margin-left: auto; - margin-right: auto; -} - -input { - text-rendering: auto; - color: -internal-light-dark(black, white); - letter-spacing: normal; - word-spacing: normal; - line-height: normal; - text-transform: none; - text-indent: 0px; - text-shadow: none; - display: inline-block; - text-align: start; - appearance: auto; - -webkit-rtl-ordering: logical; - background-color: -internal-light-dark(rgb(255, 255, 255), rgb(59, 59, 59)); - margin: 0em; - padding: 1px 2px; - border-width: 2px; - border-style: inset; - border-color: -internal-light-dark(rgb(118, 118, 118), rgb(133, 133, 133)); - border-image: initial; -} - -.py-button { - --tw-text-opacity: 1; - color: rgba(255, 255, 255, var(--tw-text-opacity)); - padding: 0.5rem; - --tw-bg-opacity: 1; - background-color: rgba(37, 99, 235, var(--tw-bg-opacity)); - --tw-border-opacity: 1; - border-color: rgba(37, 99, 235, var(--tw-border-opacity)); - border-width: 1px; - border-radius: 0.25rem; - cursor: pointer; -} - -.py-li-element p { - margin: 5px; -} - -.py-li-element p { - display: inline; -} - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - font-size: 100%; - line-height: 1.15; - margin: 0; -} - -.line-through { - text-decoration: line-through; -} - -/* ===== py-terminal plugin ===== */ -/* XXX: it would be nice if these rules were stored in e.g. pyterminal.css and - bundled together at build time (by rollup?) */ - -.py-terminal { - min-height: 10em; - background-color: black; - color: white; - padding: 0.5rem; - overflow: auto; -} - -.py-terminal-hidden { - display: none; -} - -/* avoid changing the page layout when the terminal is docked and hidden */ -html:has(py-terminal[docked]:not(py-terminal[docked].py-terminal-hidden)) { - padding-bottom: 40vh; -} - -py-terminal[docked] { - position: fixed; - bottom: 0; - width: 100vw; - max-height: 40vh; - overflow: auto; -} - -py-terminal[docked] .py-terminal { - margin: 0; -} diff --git a/pyscriptjs/src/utils.ts b/pyscriptjs/src/utils.ts deleted file mode 100644 index ff599801..00000000 --- a/pyscriptjs/src/utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { $$ } from 'basic-devtools'; - -import { _createAlertBanner } from './exceptions'; - -export function escape(str: string): string { - return str.replace(//g, '>'); -} - -export function htmlDecode(input: string): string | null { - const doc = new DOMParser().parseFromString(ltrim(escape(input)), 'text/html'); - return doc.documentElement.textContent; -} - -export function ltrim(code: string): string { - const lines = code.split('\n'); - if (lines.length == 0) return code; - - const lengths = lines - .filter(line => line.trim().length != 0) - .map(line => { - return line.match(/^\s*/)?.pop()?.length; - }); - - const k = Math.min(...lengths); - - return k != 0 ? lines.map(line => line.substring(k)).join('\n') : code; -} - -let _uniqueIdCounter = 0; -export function ensureUniqueId(el: HTMLElement) { - if (el.id === '') el.id = `py-internal-${_uniqueIdCounter++}`; -} - -export function showWarning(msg: string, messageType: 'text' | 'html' = 'text'): void { - _createAlertBanner(msg, 'warning', messageType); -} - -export function readTextFromPath(path: string) { - const request = new XMLHttpRequest(); - request.open('GET', path, false); - request.send(); - const returnValue = request.responseText; - - return returnValue; -} - -export function inJest(): boolean { - return typeof process === 'object' && process.env.JEST_WORKER_ID !== undefined; -} - -export function joinPaths(parts: string[], separator = '/') { - const res = parts - .map(function (part) { - return part.trim().replace(/(^[/]*|[/]*$)/g, ''); - }) - .filter(p => p !== '' && p !== '.') - .join(separator || '/'); - if (parts[0].startsWith('/')) { - return '/' + res; - } - return res; -} - -export function createDeprecationWarning(msg: string, elementName: string): void { - createSingularWarning(msg, elementName); -} - -/** Adds a warning banner with content {msg} at the top of the page if - * and only if no banner containing the {sentinelText} already exists. - * If sentinelText is null, the full text of {msg} is used instead - * - * @param msg {string} The full text content of the warning banner to be displayed - * @param sentinelText {string} [null] The text to match against existing warning banners. - * If null, the full text of 'msg' is used instead. - */ -export function createSingularWarning(msg: string, sentinelText?: string): void { - const banners = $$('.alert-banner, .py-warning', document); - let bannerCount = 0; - for (const banner of banners) { - if (banner.innerHTML.includes(sentinelText || msg)) { - bannerCount++; - } - } - if (bannerCount == 0) { - _createAlertBanner(msg, 'warning'); - } -} - -/** - * @returns A new asynchronous lock - * @private - */ -export function createLock(): () => Promise<() => void> { - // This is a promise that is resolved when the lock is open, not resolved when lock is held. - let _lock = Promise.resolve(); - - /** - * Acquire the async lock - * @returns A zero argument function that releases the lock. - * @private - */ - async function acquireLock() { - const old_lock = _lock; - let releaseLock: () => void; - _lock = new Promise(resolve => (releaseLock = resolve)); - await old_lock; - return releaseLock; - } - return acquireLock; -} diff --git a/pyscriptjs/src/version.ts b/pyscriptjs/src/version.ts deleted file mode 100644 index 28ec30db..00000000 --- a/pyscriptjs/src/version.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @fileoverview Version of pyscript - * The version is based on calver which contains YEAR.MONTH.DAY.MODIFIER. - * The Modifier can be an optional text tag, such as "dev", "rc", etc. - * - * We are adding this file because we can't add version in main.js due to - * circular imports. - */ - -export const version = '2022.12.1.dev'; diff --git a/pyscriptjs/tests/integration/test_02_display.py b/pyscriptjs/tests/integration/test_02_display.py deleted file mode 100644 index 532e1c6b..00000000 --- a/pyscriptjs/tests/integration/test_02_display.py +++ /dev/null @@ -1,428 +0,0 @@ -import base64 -import html -import io -import os -import re - -import numpy as np -from PIL import Image - -from .support import PyScriptTest, skip_worker, wait_for_render - - -class TestDisplay(PyScriptTest): - @skip_worker("FIXME: display()") - def test_simple_display(self): - self.pyscript_run( - """ - - display('hello world') - - """ - ) - node_list = self.page.query_selector_all(r'[id^="py-internal"]') - pattern = r"
hello world
" - assert re.search(pattern, node_list[0].inner_html()) - assert len(node_list) == 1 - - @skip_worker("FIXME: display()") - def test_consecutive_display(self): - self.pyscript_run( - """ - - display('hello 1') - -

hello 2

- - display('hello 3') - - """ - ) - inner_text = self.page.inner_text("body") - lines = inner_text.splitlines() - lines = [line for line in lines if line != ""] # remove empty lines - assert lines == ["hello 1", "hello 2", "hello 3"] - - @skip_worker("FIXME: display()") - def test_target_attribute(self): - self.pyscript_run( - """ - - display('hello world', target="mydiv") - -
- """ - ) - mydiv = self.page.locator("#mydiv") - assert mydiv.inner_text() == "hello world" - - @skip_worker("FIXME: display()") - def test_consecutive_display_target(self): - self.pyscript_run( - """ - - display('hello 1') - -

hello in between 1 and 2

- - display('hello 2', target="second") - - - display('hello 3') - - """ - ) - inner_text = self.page.inner_text("body") - lines = inner_text.splitlines() - lines = [line for line in lines if line != ""] # remove empty lines - assert lines == ["hello 1", "hello in between 1 and 2", "hello 2", "hello 3"] - - @skip_worker("FIXME: display()") - def test_multiple_display_calls_same_tag(self): - self.pyscript_run( - """ - - display('hello') - display('world') - - """ - ) - tag = self.page.locator("py-script") - lines = tag.inner_text().splitlines() - assert lines == ["hello", "world"] - - @skip_worker("FIXME: display()") - def test_implicit_target_from_a_different_tag(self): - self.pyscript_run( - """ - - def say_hello(): - display('hello') - - - - say_hello() - - """ - ) - py1 = self.page.locator("#py1") - py2 = self.page.locator("#py2") - assert py1.inner_text() == "" - assert py2.inner_text() == "hello" - - @skip_worker("FIXME: display()") - def test_no_implicit_target(self): - self.pyscript_run( - """ - - def display_hello(): - # this fails because we don't have any implicit target - # from event handlers - display('hello world') - - - """ - ) - self.page.locator("text=Click me").click() - self.check_py_errors("Implicit target not allowed here") - ## error in console - tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" - assert ( - tb_lines[-1] - == "Exception: Implicit target not allowed here. Please use display(..., target=...)" - ) - - text = self.page.text_content("body") - assert "hello world" not in text - - @skip_worker("FIXME: display()") - def test_explicit_target_pyscript_tag(self): - self.pyscript_run( - """ - - def display_hello(): - display('hello', target='second-pyscript-tag') - - - display_hello() - - """ - ) - text = self.page.locator("id=second-pyscript-tag").inner_text() - assert text == "hello" - - @skip_worker("FIXME: display()") - def test_explicit_target_on_button_tag(self): - self.pyscript_run( - """ - - def display_hello(): - display('hello', target='my-button') - - - """ - ) - self.page.locator("text=Click me").click() - text = self.page.locator("id=my-button").inner_text() - assert "hello" in text - - @skip_worker("FIXME: display()") - def test_explicit_different_target_from_call(self): - self.pyscript_run( - """ - - def display_hello(): - display('hello', target='second-pyscript-tag') - - - print('nothing to see here') - - - display_hello() - - """ - ) - text = self.page.locator("id=second-pyscript-tag").all_inner_texts() - assert "hello" in text - - @skip_worker("FIXME: display()") - def test_append_true(self): - self.pyscript_run( - """ - - display('hello world', append=True) - - """ - ) - node_list = self.page.query_selector_all(r'[id^="py-internal"]') - pattern = r"
hello world
" - assert re.search(pattern, node_list[0].inner_html()) - assert len(node_list) == 1 - - @skip_worker("FIXME: display()") - def test_append_false(self): - self.pyscript_run( - """ - - display('hello world', append=False) - - """ - ) - inner_html = self.page.content() - pattern = r'hello world' - assert re.search(pattern, inner_html) - - @skip_worker("FIXME: display()") - def test_display_multiple_values(self): - self.pyscript_run( - """ - - hello = 'hello' - world = 'world' - display(hello, world) - - """ - ) - inner_text = self.page.inner_text("html") - assert inner_text == "hello\nworld" - - @skip_worker("FIXME: display()") - def test_display_multiple_append_false(self): - self.pyscript_run( - """ - - display('hello', append=False) - display('world', append=False) - - """ - ) - inner_html = self.page.content() - pattern = r'world' - assert re.search(pattern, inner_html) - - @skip_worker("FIXME: display()") - def test_display_multiple_append_false_with_target(self): - self.pyscript_run( - """ -
- - """ - ) - innerhtml = self.page.locator("id=circle-div").inner_html() - assert ( - innerhtml - == '' # noqa: E501 - ) - assert self.console.error.lines == [] - - @skip_worker("FIXME: display()") - def test_display_list_dict_tuple(self): - self.pyscript_run( - """ - - l = ['A', 1, '!'] - d = {'B': 2, 'List': l} - t = ('C', 3, '!') - display(l, d, t) - - """ - ) - inner_text = self.page.inner_text("html") - print(inner_text) - assert ( - inner_text - == "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')" - ) - - @skip_worker("FIXME: display()") - def test_display_should_escape(self): - self.pyscript_run( - """ - - display("

hello world

") -
- """ - ) - out = self.page.locator("py-script > div") - assert out.inner_html() == html.escape("

hello world

") - assert out.inner_text() == "

hello world

" - - @skip_worker("FIXME: display()") - def test_display_HTML(self): - self.pyscript_run( - """ - - display(HTML("

hello world

")) -
- """ - ) - out = self.page.locator("py-script > div") - assert out.inner_html() == "

hello world

" - assert out.inner_text() == "hello world" - - @skip_worker("FIXME: display()") - def test_image_display(self): - self.pyscript_run( - """ - packages = ["matplotlib"] - - import matplotlib.pyplot as plt - xpoints = [3, 6, 9] - ypoints = [1, 2, 3] - plt.plot(xpoints, ypoints) - display(plt) - - """ - ) - wait_for_render(self.page, "*", " - print('print from python') - js.console.log('print from js') - js.console.error('error from js'); -
- """ - ) - inner_html = self.page.content() - assert re.search("", inner_html) - console_text = self.console.all.lines - assert "print from python" in console_text - assert "print from js" in console_text - assert "error from js" in console_text - - @skip_worker("FIXME: display()") - def test_text_HTML_and_console_output(self): - self.pyscript_run( - """ - - display('this goes to the DOM') - print('print from python') - js.console.log('print from js') - js.console.error('error from js'); - - """ - ) - inner_text = self.page.inner_text("py-script") - assert inner_text == "this goes to the DOM" - assert self.console.log.lines[-2:] == [ - "print from python", - "print from js", - ] - print(self.console.error.lines) - assert self.console.error.lines[-1] == "error from js" - - @skip_worker("FIXME: display()") - def test_console_line_break(self): - self.pyscript_run( - """ - - print('1print\\n2print') - print('1console\\n2console') - - """ - ) - console_text = self.console.all.lines - assert console_text.index("1print") == (console_text.index("2print") - 1) - assert console_text.index("1console") == (console_text.index("2console") - 1) - - @skip_worker("FIXME: display()") - def test_image_renders_correctly(self): - """This is just a sanity check to make sure that images are rendered correctly.""" - buffer = io.BytesIO() - img = Image.new("RGB", (4, 4), color=(0, 0, 0)) - img.save(buffer, format="PNG") - - b64_img = base64.b64encode(buffer.getvalue()).decode("utf-8") - expected_img_src = f"data:image/png;charset=utf-8;base64,{b64_img}" - - self.pyscript_run( - """ - - packages = ["pillow"] - - -
- - from PIL import Image - img = Image.new("RGB", (4, 4), color=(0, 0, 0)) - display(img, target='img-target', append=False) - - """ - ) - - rendered_img_src = self.page.locator("img").get_attribute("src") - assert rendered_img_src == expected_img_src diff --git a/pyscriptjs/tests/integration/test_03_element.py b/pyscriptjs/tests/integration/test_03_element.py deleted file mode 100644 index 4c30e78f..00000000 --- a/pyscriptjs/tests/integration/test_03_element.py +++ /dev/null @@ -1,300 +0,0 @@ -from .support import PyScriptTest, skip_worker - - -class TestElement(PyScriptTest): - """Test the Element api""" - - def test_element_id(self): - """Test the element id""" - self.pyscript_run( - """ -
- - from pyscript import Element - el = Element("foo") - print(el.id) - - """ - ) - assert self.console.log.lines[-1] == "foo" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "foo" in py_terminal.inner_text() - - @skip_worker("FIXME: js.document") - def test_element_value(self): - """Test the element value""" - self.pyscript_run( - """ - - - from pyscript import Element - el = Element("foo") - print(el.value) - - """ - ) - assert self.console.log.lines[-1] == "bar" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "bar" in py_terminal.inner_text() - - @skip_worker("FIXME: js.document") - def test_element_innerHtml(self): - """Test the element innerHtml""" - self.pyscript_run( - """ -
bar
- - from pyscript import Element - el = Element("foo") - print(el.innerHtml) - - """ - ) - assert self.console.log.lines[-1] == "bar" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "bar" in py_terminal.inner_text() - - @skip_worker("FIXME: js.document") - def test_element_write_no_append(self): - """Test the element write""" - self.pyscript_run( - """ -
- - from pyscript import Element - el = Element("foo") - el.write("Hello!") - el.write("World!") - - """ - ) - div = self.page.wait_for_selector("#foo") - assert "World!" in div.inner_text() - - @skip_worker("FIXME: js.document") - def test_element_write_append(self): - """Test the element write""" - self.pyscript_run( - """ -
- - from pyscript import Element - el = Element("foo") - el.write("Hello!") - el.write("World!", append=True) - - """ - ) - parent_div = self.page.wait_for_selector("#foo") - - assert "Hello!" in parent_div.inner_text() - # confirm that the second write was appended - assert "Hello!
World!
" in parent_div.inner_html() - - @skip_worker("FIXME: js.document") - def test_element_clear_div(self): - """Test the element clear""" - self.pyscript_run( - """ -
Hello!
- - from pyscript import Element - el = Element("foo") - el.clear() - - """ - ) - div = self.page.locator("#foo") - assert div.inner_text() == "" - - @skip_worker("FIXME: js.document") - def test_element_clear_input(self): - """Test the element clear""" - self.pyscript_run( - """ - - - from pyscript import Element - el = Element("foo") - el.clear() - - """ - ) - input = self.page.wait_for_selector("#foo") - assert input.input_value() == "" - - @skip_worker("FIXME: js.document") - def test_element_select(self): - """Test the element select""" - self.pyscript_run( - """ - - - from pyscript import Element - el = Element("foo") - js.console.log(el.select("option").value) - - """ - ) - assert self.console.log.lines[-1] == "bar" - - @skip_worker("FIXME: js.document") - def test_element_select_content(self): - """Test the element select""" - self.pyscript_run( - """ - - - from pyscript import Element - el = Element("foo") - js.console.log(el.select("div", from_content=True).innerHtml) - - """ - ) - assert self.console.log.lines[-1] == "Bar" - - @skip_worker("FIXME: js.document") - def test_element_clone_no_id(self): - """Test the element clone""" - self.pyscript_run( - """ -
Hello!
- - from pyscript import Element - el = Element("foo") - el.clone() - - """ - ) - divs = self.page.locator("#foo") - assert divs.count() == 2 - assert divs.first.inner_text() == "Hello!" - assert divs.last.inner_text() == "Hello!" - - @skip_worker("FIXME: js.document") - def test_element_clone_with_id(self): - """Test the element clone""" - self.pyscript_run( - """ -
Hello!
- - from pyscript import Element - el = Element("foo") - el.clone(new_id="bar") - - """ - ) - divs = self.page.locator("#foo") - assert divs.count() == 1 - assert divs.inner_text() == "Hello!" - - clone = self.page.locator("#bar") - assert clone.inner_text() == "Hello!" - - @skip_worker("FIXME: js.document") - def test_element_clone_to_other_element(self): - """Test the element clone""" - self.pyscript_run( - """ -
-
- Bond -
-
- James -
-
- - from pyscript import Element - - bond_div = Element("bond") - james_div = Element("james") - - bond_div.clone(new_id="bond-2", to=james_div) - - """ - ) - bond_divs = self.page.locator("#bond") - james_divs = self.page.locator("#james") - bond_2_divs = self.page.locator("#bond-2") - - assert bond_divs.count() == 1 - assert james_divs.count() == 1 - assert bond_2_divs.count() == 1 - - container_div = self.page.locator("#container") - # Make sure that the clones are rendered in the right order - assert container_div.inner_text() == "Bond\nJames\nBond" - - @skip_worker("FIXME: js.document") - def test_element_remove_single_class(self): - """Test the element remove_class""" - self.pyscript_run( - """ -
- - from pyscript import Element - el = Element("foo") - el.remove_class("bar") - - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "baz" - - @skip_worker("FIXME: js.document") - def test_element_remove_multiple_classes(self): - """Test the element remove_class""" - self.pyscript_run( - """ -
- - from pyscript import Element - el = Element("foo") - el.remove_class(["foo", "baz", "bar"]) - - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "" - - @skip_worker("FIXME: js.document") - def test_element_add_single_class(self): - """Test the element add_class""" - self.pyscript_run( - """ - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class("red") - - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "red" - - @skip_worker("FIXME: js.document") - def test_element_add_multiple_class(self): - """Test the element add_class""" - self.pyscript_run( - """ - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class(["red", "bold"]) - - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "red bold" diff --git a/pyscriptjs/tests/integration/test_py_config.py b/pyscriptjs/tests/integration/test_py_config.py deleted file mode 100644 index a43e55ba..00000000 --- a/pyscriptjs/tests/integration/test_py_config.py +++ /dev/null @@ -1,323 +0,0 @@ -import os -import tarfile -import tempfile -from pathlib import Path - -import pytest -import requests - -from .support import PyScriptTest, with_execution_thread - - -@pytest.fixture -def pyodide_0_22_0_tar(request): - """ - Fixture which returns a local copy of pyodide. It uses pytest-cache to - avoid re-downloading it between runs. - """ - URL = "https://github.com/pyodide/pyodide/releases/download/0.22.0/pyodide-core-0.22.0.tar.bz2" - tar_name = Path(URL).name - - val = request.config.cache.get(tar_name, None) - if val is None: - response = requests.get(URL, stream=True) - TMP_DIR = tempfile.mkdtemp() - TMP_TAR_LOCATION = os.path.join(TMP_DIR, tar_name) - with open(TMP_TAR_LOCATION, "wb") as f: - f.write(response.raw.read()) - val = TMP_TAR_LOCATION - request.config.cache.set(tar_name, val) - return val - - -def unzip(location, extract_to="."): - file = tarfile.open(name=location, mode="r:bz2") - file.extractall(path=extract_to) - - -# Disable the main/worker dual testing, for two reasons: -# -# 1. the logic happens before we start the worker, so there is -# no point in running these tests twice -# -# 2. the logic to inject execution_thread into works only with -# plain tags, but here we want to test all weird combinations -# of config -@with_execution_thread(None) -class TestConfig(PyScriptTest): - def test_py_config_inline(self): - self.pyscript_run( - """ - - name = "foobar" - - - - import js - config = js.pyscript_get_config() - js.console.log("config name:", config.name) - - """ - ) - assert self.console.log.lines[-1] == "config name: foobar" - - def test_py_config_external(self): - pyconfig_toml = """ - name = "app with external config" - """ - self.writefile("pyconfig.toml", pyconfig_toml) - self.pyscript_run( - """ - - - - - import js - config = js.pyscript_get_config() - js.console.log("config name:", config.name) - - """ - ) - assert self.console.log.lines[-1] == "config name: app with external config" - - # The default pyodide version is newer than - # the one we are loading below (after downloading locally) - # which is 0.22.0 - - # The test checks if loading a different interpreter is possible - # and that too from a locally downloaded file without needing - # the use of explicit `indexURL` calculation. - def test_interpreter_config(self, pyodide_0_22_0_tar): - unzip(pyodide_0_22_0_tar, extract_to=self.tmpdir) - self.pyscript_run( - """ - - { - "interpreters": [{ - "src": "/pyodide/pyodide.js", - "name": "my-own-pyodide", - "lang": "python" - }] - } - - - - import sys, js - pyodide_version = sys.modules["pyodide"].__version__ - js.console.log("version", pyodide_version) - display(pyodide_version) - - """, - ) - - assert self.console.log.lines[-1] == "version 0.22.0" - version = self.page.locator("py-script").inner_text() - assert version == "0.22.0" - - def test_runtime_still_works_but_shows_deprecation_warning( - self, pyodide_0_22_0_tar - ): - unzip(pyodide_0_22_0_tar, extract_to=self.tmpdir) - self.pyscript_run( - """ - - { - "runtimes": [{ - "src": "/pyodide/pyodide.js", - "name": "my-own-pyodide", - "lang": "python" - }] - } - - - - import sys, js - pyodide_version = sys.modules["pyodide"].__version__ - js.console.log("version", pyodide_version) - display(pyodide_version) - - """, - ) - - assert self.console.log.lines[-1] == "version 0.22.0" - version = self.page.locator("py-script").inner_text() - assert version == "0.22.0" - - deprecation_banner = self.page.wait_for_selector(".alert-banner") - expected_message = ( - "The configuration option `config.runtimes` is deprecated. " - "Please use `config.interpreters` instead." - ) - assert deprecation_banner.inner_text() == expected_message - - def test_invalid_json_config(self): - # we need wait_for_pyscript=False because we bail out very soon, - # before being able to write 'PyScript page fully initialized' - self.pyscript_run( - """ - - [[ - - """, - wait_for_pyscript=False, - ) - banner = self.page.wait_for_selector(".py-error") - assert "SyntaxError: Unexpected end of JSON input" in self.console.error.text - expected = ( - "(PY1000): The config supplied: [[ is an invalid JSON and cannot be " - "parsed: SyntaxError: Unexpected end of JSON input" - ) - assert banner.inner_text() == expected - - def test_invalid_toml_config(self): - # we need wait_for_pyscript=False because we bail out very soon, - # before being able to write 'PyScript page fully initialized' - self.pyscript_run( - """ - - [[ - - """, - wait_for_pyscript=False, - ) - banner = self.page.wait_for_selector(".py-error") - assert "SyntaxError: Expected DoubleQuote" in self.console.error.text - expected = ( - "(PY1000): The config supplied: [[ is an invalid TOML and cannot be parsed: " - "SyntaxError: Expected DoubleQuote, Whitespace, or [a-z], [A-Z], " - '[0-9], "-", "_" but "\\n" found.' - ) - assert banner.inner_text() == expected - - def test_multiple_py_config(self): - self.pyscript_run( - """ - - name = "foobar" - - - - this is ignored and won't even be parsed - - - - import js - config = js.pyscript_get_config() - js.console.log("config name:", config.name) - - """ - ) - banner = self.page.wait_for_selector(".py-warning") - expected = ( - "Multiple tags detected. Only the first " - "is going to be parsed, all the others will be ignored" - ) - assert banner.text_content() == expected - - def test_no_interpreter(self): - snippet = """ - - { - "interpreters": [] - } - - """ - self.pyscript_run(snippet, wait_for_pyscript=False) - div = self.page.wait_for_selector(".py-error") - assert ( - div.text_content() == "(PY1000): Fatal error: config.interpreter is empty" - ) - - def test_multiple_interpreter(self): - snippet = """ - - { - "interpreters": [ - { - "src": "https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js", - "name": "pyodide-0.23.2", - "lang": "python" - }, - { - "src": "http://...", - "name": "this will be ignored", - "lang": "this as well" - } - ] - } - - - - import js - js.console.log("hello world"); - - """ - self.pyscript_run(snippet) - banner = self.page.wait_for_selector(".py-warning") - expected = ( - "Multiple interpreters are not supported yet.Only the first will be used" - ) - assert banner.text_content() == expected - assert self.console.log.lines[-1] == "hello world" - - def test_paths(self): - self.writefile("a.py", "x = 'hello from A'") - self.writefile("b.py", "x = 'hello from B'") - self.pyscript_run( - """ - - [[fetch]] - files = ["./a.py", "./b.py"] - - - - import js - import a, b - js.console.log(a.x) - js.console.log(b.x) - - """ - ) - assert self.console.log.lines[-2:] == [ - "hello from A", - "hello from B", - ] - - def test_paths_that_do_not_exist(self): - self.pyscript_run( - """ - - [[fetch]] - files = ["./f.py"] - - """, - wait_for_pyscript=False, - ) - - expected = "(PY0404): Fetching from URL ./f.py failed with " "error 404" - - inner_html = self.page.locator(".py-error").inner_html() - - assert expected in inner_html - assert expected in self.console.error.lines[-1] - - def test_paths_from_packages(self): - self.writefile("utils/__init__.py", "") - self.writefile("utils/a.py", "x = 'hello from A'") - self.pyscript_run( - """ - - [[fetch]] - from = "utils" - to_folder = "pkg" - files = ["__init__.py", "a.py"] - - - - import js - from pkg.a import x - js.console.log(x) - - """ - ) - assert self.console.log.lines[-1] == "hello from A" diff --git a/pyscriptjs/tests/integration/test_py_terminal.py b/pyscriptjs/tests/integration/test_py_terminal.py deleted file mode 100644 index 8b8b5ac6..00000000 --- a/pyscriptjs/tests/integration/test_py_terminal.py +++ /dev/null @@ -1,264 +0,0 @@ -import time - -from playwright.sync_api import expect - -from .support import PyScriptTest, skip_worker - - -class TestPyTerminal(PyScriptTest): - def test_py_terminal(self): - """ - 1. should redirect stdout and stderr to the DOM - - 2. they also go to the console as usual - """ - self.pyscript_run( - """ - - - - import sys - print('hello world') - print('this goes to stderr', file=sys.stderr) - print('this goes to stdout') - - """ - ) - term = self.page.locator("py-terminal") - term_lines = term.inner_text().splitlines() - assert term_lines == [ - "hello world", - "this goes to stderr", - "this goes to stdout", - ] - assert self.console.log.lines[-3:] == [ - "hello world", - "this goes to stderr", - "this goes to stdout", - ] - - @skip_worker("FIXME: js.document") - def test_two_terminals(self): - """ - Multiple s can cohexist. - A receives only output from the moment it is added to - the DOM. - """ - self.pyscript_run( - """ - - - - import js - print('one') - term2 = js.document.createElement('py-terminal') - term2.id = 'term2' - js.document.body.append(term2) - - print('two') - print('three') - - """ - ) - term1 = self.page.locator("#term1") - term2 = self.page.locator("#term2") - term1_lines = term1.inner_text().splitlines() - term2_lines = term2.inner_text().splitlines() - assert term1_lines == ["one", "two", "three"] - assert term2_lines == ["two", "three"] - - def test_auto_attribute(self): - self.pyscript_run( - """ - - - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_hidden() - self.page.locator("button").click() - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_auto(self): - """ - config.terminal == "auto" is the default: a is - automatically added to the page - """ - self.pyscript_run( - """ - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_hidden() - assert "No found, adding one" in self.console.info.text - # - self.page.locator("button").click() - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_true(self): - """ - If we set config.terminal == true, a is automatically added - """ - self.pyscript_run( - """ - - terminal = true - - - - print('hello world') - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_false(self): - """ - If we set config.terminal == false, no is added - """ - self.pyscript_run( - """ - - terminal = false - - """ - ) - term = self.page.locator("py-terminal") - assert term.count() == 0 - - def test_config_docked(self): - """ - config.docked == "docked" is also the default: a is - automatically added to the page - """ - self.pyscript_run( - """ - - """ - ) - term = self.page.locator("py-terminal") - self.page.locator("button").click() - expect(term).to_be_visible() - assert term.get_attribute("docked") == "" - - def test_xterm_function(self): - """Test a few basic behaviors of the xtermjs terminal. - - This test isn't meant to capture all of the behaviors of an xtermjs terminal; - rather, it confirms with a few basic formatting sequences that (1) the xtermjs - terminal is functioning/loaded correctly and (2) that output toward that terminal - isn't being escaped in a way that prevents it reacting to escape seqeunces. The - main goal is preventing regressions. - """ - self.pyscript_run( - """ - - xterm = true - - - print("\x1b[33mYellow\x1b[0m") - print("\x1b[4mUnderline\x1b[24m") - print("\x1b[1mBold\x1b[22m") - print("\x1b[3mItalic\x1b[23m") - print("done") - - """ - ) - - # Wait for "done" to actually appear in the xterm; may be delayed, - # since xtermjs processes its input buffer in chunks - last_line = self.page.get_by_text("done") - last_line.wait_for() - - # Yes, this is not ideal. However, per http://xtermjs.org/docs/guides/hooks/ - # "It is not possible to conclude, whether or when a certain chunk of data - # will finally appear on the screen," which is what we'd really like to know. - # By waiting for the "done" test to appear above, we get close, however it is - # possible for the text to appear and not be 'processed' (i.e.) formatted. This - # small delay should avoid that. - time.sleep(1) - - rows = self.page.locator(".xterm-rows") - - # The following use locator.evaluate() and getComputedStyle to get - # the computed CSS values; this tests that the lines are rendering - # properly in a better way than just testing whether they - # get the right css classes from xtermjs - - # First line should be yellow - first_line = rows.locator("div").nth(0) - first_char = first_line.locator("span").nth(0) - color = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('color')" - ) - assert color == "rgb(196, 160, 0)" - - # Second line should be underlined - second_line = rows.locator("div").nth(1) - first_char = second_line.locator("span").nth(0) - text_decoration = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('text-decoration')" - ) - assert "underline" in text_decoration - - # We'll make sure the 'bold' font weight is more than the - # default font weight without specifying a specific value - baseline_font_weight = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('font-weight')" - ) - - # Third line should be bold - third_line = rows.locator("div").nth(2) - first_char = third_line.locator("span").nth(0) - font_weight = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('font-weight')" - ) - assert int(font_weight) > int(baseline_font_weight) - - # Fourth line should be italic - fourth_line = rows.locator("div").nth(3) - first_char = fourth_line.locator("span").nth(0) - font_style = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('font-style')" - ) - assert font_style == "italic" - - def test_xterm_multiple(self): - """Test whether multiple x-terms on the page all function""" - self.pyscript_run( - """ - - xterm = true - - - print("\x1b[33mYellow\x1b[0m") - print("done") - - - - """ - ) - - # Wait for "done" to actually appear in the xterm; may be delayed, - # since xtermjs processes its input buffer in chunks - last_line = self.page.get_by_test_id("b").get_by_text("done") - last_line.wait_for() - - # Yes, this is not ideal. See note in `test_xterm_function` - time.sleep(1) - - rows = self.page.locator("#a .xterm-rows") - - # First line should be yellow - first_line = rows.locator("div").nth(0) - first_char = first_line.locator("span").nth(0) - color = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('color')" - ) - assert color == "rgb(196, 160, 0)" diff --git a/pyscriptjs/tests/integration/test_runtime_attributes.py b/pyscriptjs/tests/integration/test_runtime_attributes.py deleted file mode 100644 index 91f23c79..00000000 --- a/pyscriptjs/tests/integration/test_runtime_attributes.py +++ /dev/null @@ -1,62 +0,0 @@ -from .support import PyScriptTest, skip_worker - - -class TestPyScriptRuntimeAttributes(PyScriptTest): - @skip_worker("FIXME: js.document") - def test_injected_html_with_py_event(self): - self.pyscript_run( - r""" -
- - import js - - py_button = Element("py-button-container") - py_button.element.innerHTML = '' - - def print_hello(): - js.console.log("hello pyscript") - - """ - ) - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] - - @skip_worker("FIXME: js.document") - def test_added_py_event(self): - self.pyscript_run( - r""" - - - import js - - py_button = Element("py-button") - py_button.element.setAttribute("py-click", "print_hello()") - - def print_hello(): - js.console.log("hello pyscript") - - """ - ) - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] - - @skip_worker("FIXME: js.document") - def test_added_then_removed_py_event(self): - self.pyscript_run( - r""" - - - import js - - py_button = Element("py-button") - py_button.element.setAttribute("py-click", "print_hello()") - - def print_hello(): - js.console.log("hello pyscript") - py_button.element.removeAttribute("py-click") - - """ - ) - self.page.locator("button").click() - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] diff --git a/pyscriptjs/tests/integration/test_style.py b/pyscriptjs/tests/integration/test_style.py deleted file mode 100644 index 54c28704..00000000 --- a/pyscriptjs/tests/integration/test_style.py +++ /dev/null @@ -1,41 +0,0 @@ -from playwright.sync_api import expect - -from .support import PyScriptTest, skip_worker - - -class TestStyle(PyScriptTest): - def test_pyscript_not_defined(self): - """Test raw elements that are not defined for display:none""" - doc = """ - - - - - - hello - hello - hello - - - """ - self.writefile("test-not-defined-css.html", doc) - self.goto("test-not-defined-css.html") - expect(self.page.locator("py-config")).to_be_hidden() - expect(self.page.locator("py-script")).to_be_hidden() - expect(self.page.locator("py-repl")).to_be_hidden() - - @skip_worker("FIXME: display()") - def test_pyscript_defined(self): - """Test elements have visibility that should""" - self.pyscript_run( - """ - - name = "foo" - - display("hello") - display("hello") - """ - ) - expect(self.page.locator("py-config")).to_be_hidden() - expect(self.page.locator("py-script")).to_be_visible() - expect(self.page.locator("py-repl")).to_be_visible() diff --git a/pyscriptjs/tests/integration/test_warnings_and_banners.py b/pyscriptjs/tests/integration/test_warnings_and_banners.py deleted file mode 100644 index 3e001376..00000000 --- a/pyscriptjs/tests/integration/test_warnings_and_banners.py +++ /dev/null @@ -1,28 +0,0 @@ -from .support import PyScriptTest - - -class TestWarningsAndBanners(PyScriptTest): - # Test the behavior of generated warning banners - - def test_create_singular_warning(self): - # Use a script tag with an invalid output attribute to generate a warning, but only one - self.pyscript_run( - """ - - print("one.") - print("two.") - - - print("three.") - - """ - ) - - loc = self.page.locator(".alert-banner") - - # Only one banner should appear - assert loc.count() == 1 - assert ( - loc.text_content() - == 'output = "foo" does not match the id of any element on the page.' - ) diff --git a/pyscriptjs/tests/integration/test_zzz_docs_snippets.py b/pyscriptjs/tests/integration/test_zzz_docs_snippets.py deleted file mode 100644 index 0c857304..00000000 --- a/pyscriptjs/tests/integration/test_zzz_docs_snippets.py +++ /dev/null @@ -1,301 +0,0 @@ -import re - -from .support import PyScriptTest, skip_worker - - -class TestDocsSnippets(PyScriptTest): - @skip_worker("FIXME: js.document") - def test_tutorials_py_click(self): - self.pyscript_run( - """ - -

- - - from pyscript import Element - import datetime - - def current_time(): - now = datetime.datetime.now() - - # Get paragraph element by id - paragraph = Element("current-time") - - # Add current time to the paragraph element - paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S")) - - """ - ) - - btn = self.page.wait_for_selector("#get-time") - btn.click() - - current_time = self.page.wait_for_selector("#current-time") - - pattern = "\\d+-\\d+-\\d+\\s\\d+:\\d+:\\d+" # e.g. 08-09-2022 15:57:32 - assert re.search(pattern, current_time.inner_text()) - self.assert_no_banners() - - def test_tutorials_requests(self): - self.pyscript_run( - """ - - packages = ["requests", "pyodide-http"] - - - - import requests - import pyodide_http - - # Patch the Requests library so it works with Pyscript - pyodide_http.patch_all() - - # Make a request to the JSON Placeholder API - response = requests.get("https://jsonplaceholder.typicode.com/todos") - print(response.json()) - - """ - ) - - py_terminal = self.page.wait_for_selector("py-terminal") - # Just a small check to confirm that the response was received - assert "userId" in py_terminal.inner_text() - self.assert_no_banners() - - @skip_worker("FIXME: js.document") - def test_tutorials_py_config_fetch(self): - # flake8: noqa - self.pyscript_run( - """ - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - - from todo import add_task, add_task_event - -
-
-

- To Do List -

-
-
- - -
-
- Fold laundry

' - in first_task.inner_html() - ) - self.assert_no_banners() - - def test_tutorials_py_config_interpreter(self): - """Load a previous version of Pyodide""" - self.pyscript_run( - """ - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - import pyodide - print(pyodide.__version__) - - """ - ) - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "0.23.0" in py_terminal.inner_text() - self.assert_no_banners() - - @skip_worker("FIXME: display()") - def test_tutorials_writing_to_page(self): - self.pyscript_run( - """ -
- -
- -
- -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") - - def print_to_page(): - print("I print things!") -
- """ - ) - btn_manual = self.page.wait_for_selector("#manual") - btn_display = self.page.wait_for_selector("#display") - btn_print = self.page.wait_for_selector("#print") - - btn_manual.click() - manual_write_div = self.page.wait_for_selector("#manual-write") - assert "

Hello World

" in manual_write_div.inner_html() - - btn_display.click() - display_write_div = self.page.wait_for_selector("#display-write") - assert "I display things!" in display_write_div.inner_text() - - btn_print.click() - py_terminal = self.page.wait_for_selector("py-terminal") - assert "I print things!" in py_terminal.inner_text() - self.assert_no_banners() - - def test_guides_asyncio(self): - self.pyscript_run( - """ - - import asyncio - - async def main(): - for i in range(3): - print(i) - - asyncio.ensure_future(main()) - - """ - ) - py_terminal = self.page.wait_for_selector("py-terminal") - - assert "0\n1\n2\n" in py_terminal.inner_text() - - @skip_worker("FIXME: js.document") - def test_reference_pyterminal_xterm(self): - self.pyscript_run( - """ - - xterm = true - - - print("HELLO!") - import js - import asyncio - - async def adjust_term_size(columns, rows): - xterm = await js.document.querySelector('py-terminal').xtermReady - xterm.resize(columns, rows) - print("test-done") - - asyncio.ensure_future(adjust_term_size(40, 10)) - - """ - ) - self.page.get_by_text("test-done").wait_for() - - py_terminal = self.page.locator("py-terminal") - print(dir(py_terminal)) - print(type(py_terminal)) - assert py_terminal.evaluate("el => el.xterm.cols") == 40 - assert py_terminal.evaluate("el => el.xterm.rows") == 10 - - @skip_worker(reason="FIXME: js.document (@when decorator)") - def test_reference_when_simple(self): - self.pyscript_run( - """ - - - from pyscript import when - @when("click", selector="#my_btn") - def say_hello(): - print(f"Hello, world!") - - """ - ) - self.page.get_by_text("Click Me to Say Hi").click() - self.wait_for_console("Hello, world!") - assert ("Hello, world!") in self.console.log.lines - - @skip_worker(reason="FIXME: js.document (@when decorator)") - def test_reference_when_complex(self): - self.pyscript_run( - """ -
- - - -
- - from pyscript import when - import js - - @when("click", selector="#container button") - def highlight(evt): - #Set the clicked button's background to green - evt.target.style.backgroundColor = 'green' - - #Set the background of all buttons to red - other_buttons = (button for button in js.document.querySelectorAll('button') if button != evt.target) - for button in other_buttons: - button.style.backgroundColor = 'red' - - print("set") # Test Only - - """ - ) - - def getBackgroundColor(locator): - return locator.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('background-color')" - ) - - first_button = self.page.get_by_text("First") - assert getBackgroundColor(first_button) == "rgb(239, 239, 239)" - - first_button.click() - self.wait_for_console("set") - - assert getBackgroundColor(first_button) == "rgb(0, 128, 0)" - assert getBackgroundColor(self.page.get_by_text("Second")) == "rgb(255, 0, 0)" - assert getBackgroundColor(self.page.get_by_text("Third")) == "rgb(255, 0, 0)" diff --git a/pyscriptjs/tests/py-unit/_pyscript_js.py b/pyscriptjs/tests/py-unit/_pyscript_js.py deleted file mode 100644 index 41f4927c..00000000 --- a/pyscriptjs/tests/py-unit/_pyscript_js.py +++ /dev/null @@ -1,10 +0,0 @@ -from unittest.mock import Mock - -import js - -showWarning = Mock() -define_custom_element = Mock() - - -def deepQuerySelector(selector): - return js.document.querySelector(selector) diff --git a/pyscriptjs/tests/py-unit/conftest.py b/pyscriptjs/tests/py-unit/conftest.py deleted file mode 100644 index 464d883a..00000000 --- a/pyscriptjs/tests/py-unit/conftest.py +++ /dev/null @@ -1,29 +0,0 @@ -"""All data required for testing examples""" -import sys -from pathlib import Path - -import pytest - -pyscriptjs = Path(__file__).parents[2] - -# add pyscript folder to path -python_source = pyscriptjs / "src" / "python" -sys.path.append(str(python_source)) - -# add Python plugins folder to path -python_plugins_source = pyscriptjs / "src" / "plugins" / "python" -sys.path.append(str(python_plugins_source)) - - -# patch pyscript module where needed -import pyscript_plugins_tester as ppt # noqa: E402 -from pyscript import _plugin # noqa: E402 - -_plugin.define_custom_element = ppt.define_custom_element - - -@pytest.fixture() -def plugins_manager(): - """return a new instance of a Test version the PyScript application plugins manager""" - yield ppt.plugins_manager # PluginsManager() - ppt.plugins_manager.reset() diff --git a/pyscriptjs/tests/py-unit/js.py b/pyscriptjs/tests/py-unit/js.py deleted file mode 100644 index f1e4cd82..00000000 --- a/pyscriptjs/tests/py-unit/js.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Mock module that emulates some of the pyodide js module features for the sake of tests""" -from unittest.mock import Mock - -document = Mock() -console = Mock() -setTimeout = Mock() -Object = Mock() diff --git a/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py b/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py deleted file mode 100644 index 288347fa..00000000 --- a/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py +++ /dev/null @@ -1,120 +0,0 @@ -import xml.dom -from xml.dom.minidom import Node # nosec - -import js -import pyscript - - -class classList: - """Class that (lightly) emulates the behaviour of HTML Nodes ClassList""" - - def __init__(self): - self._classes = [] - - def add(self, classname: str): - """Add classname to the classList""" - self._classes.append(classname) - - def remove(self, classname: str): - """Remove classname from the classList""" - self._classes.remove(classname) - - -class PluginsManager: - """ - Emulator of PyScript PluginsManager that can be used to simulate plugins lifecycle events - - TODO: Currently missing most of the lifecycle events in PluginsManager implementation. Need - to add more than just addPythonPlugin - """ - - def __init__(self): - self.plugins = [] - - # mapping containing all the custom elements createed by plugins - self._custom_elements = {} - - def addPythonPlugin(self, pluginInstance: pyscript.Plugin): - """ - Add a pluginInstance to the plugins managed by the PluginManager and calls - pluginInstance.init(self) to initialized the plugin with the manager - """ - pluginInstance.init(self) - self.plugins.append(pluginInstance) - - def reset(self): - """ - Unregister all plugins and related custom elements. - """ - for plugin in self.plugins: - plugin.app = None - - self.plugins = [] - self._custom_elements = {} - - -class CustomElement: - def __init__(self, plugin_class: pyscript.Plugin): - self.pyPluginInstance = plugin_class(self) - self.attributes = {} - self.innerHTML = "" - - def connectedCallback(self): - return self.pyPluginInstance.connect() - - def getAttribute(self, attr: str): - return self.attributes.get(attr) - - -def define_custom_element(tag, plugin_class: pyscript.Plugin): - """ - Mock method to emulate the behaviour of the PyScript `define_custom_element` - that basically creates a new CustomElement passing plugin_class as Python - proxy object. For more info check out the logic of the original implementation at: - - src/plugin.ts:define_custom_element - """ - ce = CustomElement(plugin_class) - plugins_manager._custom_elements[tag] = ce - - -plugins_manager = PluginsManager() - -# Init pyscript testing mocks -impl = xml.dom.getDOMImplementation() - - -class Node: - """ - Represent an HTML Node. - - This classes us an abstraction on top of xml.dom.minidom.Node - """ - - def __init__(self, el: Node): - self._el = el - self.classList = classList() - - # Automatic delegation is a simple and short boilerplate: - def __getattr__(self, attr: str): - return getattr(self._el, attr) - - def createElement(self, *args, **kws): - newEl = self._el.createElement(*args, **kws) - return Node(newEl) - - -class Document(Node): - """ - Represent an HTML Document. - - This classes us an abstraction on top of xml.dom.minidom.Document - """ - - def __init__(self): - self._el = impl.createDocument(None, "document", None) - - -js.document = doc = Document() -js.document.head = doc.createElement("head") -js.document.body = doc.createElement("body") diff --git a/pyscriptjs/tests/py-unit/test_pyscript.py b/pyscriptjs/tests/py-unit/test_pyscript.py deleted file mode 100644 index 532b0efa..00000000 --- a/pyscriptjs/tests/py-unit/test_pyscript.py +++ /dev/null @@ -1,207 +0,0 @@ -import sys -import textwrap -from unittest.mock import Mock - -import js -import pyscript -from pyscript import HTML, Element -from pyscript._deprecated_globals import DeprecatedGlobal -from pyscript._internal import set_version_info, uses_top_level_await -from pyscript._mime import format_mime - - -class TestElement: - def test_id_is_correct(self): - el = Element("something") - assert el.id == "something" - - def test_element(self, monkeypatch): - el = Element("something") - document = Mock() - call_result = "some_result" - document.querySelector = Mock(return_value=call_result) - monkeypatch.setattr(js, "document", document) - assert not el._element - real_element = el.element - assert real_element - assert document.querySelector.call_count == 1 - document.querySelector.assert_called_with("#something") - assert real_element == call_result - - -def test_format_mime_str(): - obj = "just a string" - out, mime = format_mime(obj) - assert out == obj - assert mime == "text/plain" - - -def test_format_mime_str_escaping(): - obj = "

hello

" - out, mime = format_mime(obj) - assert out == "<p>hello</p>" - assert mime == "text/plain" - - -def test_format_mime_repr_escaping(): - out, mime = format_mime(sys) - assert out == "<module 'sys' (built-in)>" - assert mime == "text/plain" - - -def test_format_mime_HTML(): - obj = HTML("

hello

") - out, mime = format_mime(obj) - assert out == "

hello

" - assert mime == "text/html" - - -def test_uses_top_level_await(): - # Basic Case - src = "x = 1" - assert uses_top_level_await(src) is False - - # Comments are not top-level await - src = textwrap.dedent( - """ - #await async for async with asyncio - """ - ) - - assert uses_top_level_await(src) is False - - # Top-level-await cases - src = textwrap.dedent( - """ - async def foo(): - pass - await foo - """ - ) - assert uses_top_level_await(src) is True - - src = textwrap.dedent( - """ - async with object(): - pass - """ - ) - assert uses_top_level_await(src) is True - - src = textwrap.dedent( - """ - async for _ in range(10): - pass - """ - ) - assert uses_top_level_await(src) is True - - # Acceptable await/async for/async with cases - src = textwrap.dedent( - """ - async def foo(): - await foo() - """ - ) - assert uses_top_level_await(src) is False - - src = textwrap.dedent( - """ - async def foo(): - async with object(): - pass - """ - ) - assert uses_top_level_await(src) is False - - src = textwrap.dedent( - """ - async def foo(): - async for _ in range(10): - pass - """ - ) - assert uses_top_level_await(src) is False - - -def test_set_version_info(): - version_string = "1234.56.78.ABCD" - set_version_info(version_string) - assert pyscript.__version__ == version_string - assert pyscript.version_info == (1234, 56, 78, "ABCD") - - -class MyDeprecatedGlobal(DeprecatedGlobal): - """ - A subclass of DeprecatedGlobal, for tests. - - Instead of showing warnings into the DOM (which we don't have inside unit - tests), we record the warnings into a field. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.warnings = [] - - def _show_warning(self, message): - self.warnings.append(message) - - -class TestDeprecatedGlobal: - def test_repr(self): - glob = MyDeprecatedGlobal("foo", None, "my message") - assert repr(glob) == "" - - def test_show_warning_override(self): - """ - Test that our overriding of _show_warning actually works. - """ - glob = MyDeprecatedGlobal("foo", None, "my message") - glob._show_warning("foo") - glob._show_warning("bar") - assert glob.warnings == ["foo", "bar"] - - def test_getattr(self): - class MyFakeObject: - name = "FooBar" - - glob = MyDeprecatedGlobal("MyFakeObject", MyFakeObject, "this is my warning") - assert glob.name == "FooBar" - assert glob.warnings == ["this is my warning"] - - def test_dont_show_warning_twice(self): - class MyFakeObject: - name = "foo" - surname = "bar" - - glob = MyDeprecatedGlobal("MyFakeObject", MyFakeObject, "this is my warning") - assert glob.name == "foo" - assert glob.surname == "bar" - assert len(glob.warnings) == 1 - - def test_call(self): - def foo(x, y): - return x + y - - glob = MyDeprecatedGlobal("foo", foo, "this is my warning") - assert glob(1, y=2) == 3 - assert glob.warnings == ["this is my warning"] - - def test_iter(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - assert list(glob) == ["a", "b", "c"] - assert glob.warnings == ["this is my warning"] - - def test_getitem(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - assert glob["a"] == 1 - assert glob.warnings == ["this is my warning"] - - def test_setitem(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - glob["a"] = 100 - assert glob.warnings == ["this is my warning"] - assert glob["a"] == 100 diff --git a/pyscriptjs/tests/py-unit/test_python_plugins.py b/pyscriptjs/tests/py-unit/test_python_plugins.py deleted file mode 100644 index d60707ab..00000000 --- a/pyscriptjs/tests/py-unit/test_python_plugins.py +++ /dev/null @@ -1,171 +0,0 @@ -import html -from unittest.mock import Mock - -import js -import py_markdown -import py_tutor -import pyscript_plugins_tester as ppt - -TUTOR_SOURCE = """ - - packages = [ - "folium", - "pandas" - ] - plugins = [ - "../build/plugins/python/py_tutor.py" - ] - - - -import folium -import json -import pandas as pd - -from pyodide.http import open_url - -# the rest of the code goes one - -""" - - -class TestPyMarkdown: - def test_plugin_hooks(self, monkeypatch): - console_mock = Mock() - monkeypatch.setattr(py_markdown, "console", console_mock) - config = "just a config" - interpreter = "just an interpreter" - - py_markdown.plugin.configure(config) - console_mock.log.assert_called_with("configuration received: just a config") - - py_markdown.plugin.afterStartup(interpreter) - console_mock.log.assert_called_with( - "interpreter received:", "just an interpreter" - ) - - -class TestPyTutor: - def check_prism_added(self): - """ - Assert that the add_prism method has been correctly executed and the - related prism assets have been added to the page head - """ - # GIVEN a previous call to py_tutor.plugin.append_script_to_page - head = js.document.head - - # EXPECT the head to contain a link element pointing to the prism.min.css - links = head.getElementsByTagName("link") - assert len(links) == 1 - link = links[0] - assert link.type == "text/css" - assert link.rel == "stylesheet" - assert link.href == "./assets/prism/prism.min.css" - - # EXPECT the head to contain a script src == prism.min.js - scripts = head.getElementsByTagName("script") - assert len(scripts) == 1 - script = scripts[0] - assert script.type == "text/javascript" - assert script.src == "./assets/prism/prism.min.js" - - def check_append_script_to_page(self): - """ - Assert that the append_script_to_page has been correctly executed and the - py_tutor.PAGE_SCRIPT code needed for the plugin JS animation has been added - to the page body - """ - # GIVEN a previous call to py_tutor.plugin.append_script_to_page - body = js.document.body - - # EXPECT the body of the page to contain a script of type text/javascript - # and that contains the py_tutor.PAGE_SCRIPT script - scripts = body.getElementsByTagName("script") - assert len(scripts) == 1 - script = scripts[0] - assert script.type == "text/javascript" - - # Check the actual JS script code - # To do so we have 2 methods (it depends on browser support so we check either...) - if script.childNodes: - # in this case it means the content has been added as a child element - node = script.childNodes[0] - assert node.data == py_tutor.PAGE_SCRIPT - else: - assert script.text == py_tutor.PAGE_SCRIPT - - def check_create_code_section(self): - """ - Assert that the create_code_section has been correctly executed and the - related code section has been created and added to the page. - """ - # GIVEN a previous call to py_tutor.plugin.check_create_code_section - console = py_tutor.js.console - - # EXPECT the console to have the messages printed by the plugin while - # executing the plugin operations - console.info.assert_any_call("Creating code introspection section.") - console.info.assert_any_call("Creating new code section element.") - - # EXPECT the page body to contain a section with the input source code - body = js.document.body - sections = body.getElementsByTagName("section") - section = sections[0] - assert "code" in section.classList._classes - section_innerHTML = py_tutor.TEMPLATE_CODE_SECTION.format( - source=html.escape(TUTOR_SOURCE), modules_section="" - ) - assert html.escape(TUTOR_SOURCE) in section.innerHTML - assert section.innerHTML == section_innerHTML - - def test_connected_calls(self, plugins_manager: ppt.PluginsManager): - """ - Test that all parts of the plugin have been added to the page body and head - properly. This test effectively calls `self.check_prism_added`, - `self.check_append_script_to_page` and `check_create_code_section` assert - the new nodes have been added properly. - """ - # GIVEN THAT we add the plugin to the app plugin manager - # this will: - # - init the plugin instance passing the plugins_manager as parent app - # - add the plugin instance to plugins_manager.plugins - assert not py_tutor.plugin.app - plugins_manager.addPythonPlugin(py_tutor.plugin) - - # EXPECT: the plugin app to now be the plugin manager - assert py_tutor.plugin.app == plugins_manager - tutor_ce = plugins_manager._custom_elements["py-tutor"] - # tutor_ce_python_instance = tutor_ce.pyPluginInstance - # GIVEN: The following innerHTML on the ce elements - tutor_ce.innerHTML = TUTOR_SOURCE - - # GIVEN: the CustomElement connectedCallback gets called - tutor_ce.connectedCallback() - - # EXPECT: the - self.check_prism_added() - - self.check_append_script_to_page() - - self.check_create_code_section() - - def test_plugin_registered(self, plugins_manager: ppt.PluginsManager): - """ - Test that, when registered, plugin actually has an app attribute set - and that it's present in plugins manager plugins list. - """ - # EXPECT py_tutor.plugin to not have any app associate - assert not py_tutor.plugin.app - - # EXPECT: the plugin manager to not have any plugin registered - assert not plugins_manager.plugins - - # GIVEN THAT we add the plugin to the app plugin manager - plugins_manager.addPythonPlugin(py_tutor.plugin) - - # EXPECT: the plugin app to now be the plugin manager - assert py_tutor.plugin.app == plugins_manager - assert "py-tutor" in py_tutor.plugin._custom_elements - - # EXPECT: the pytutor.plugin manager to be part of - assert py_tutor.plugin in plugins_manager.plugins diff --git a/pyscriptjs/tests/unit/calculateFetchPaths.test.ts b/pyscriptjs/tests/unit/calculateFetchPaths.test.ts deleted file mode 100644 index 31a4d8d7..00000000 --- a/pyscriptjs/tests/unit/calculateFetchPaths.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { calculateFetchPaths } from '../../src/plugins/calculateFetchPaths'; -import { FetchConfig } from '../../src/pyconfig'; - -describe('CalculateFetchPaths', () => { - it('should calculate paths when only from is provided', () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://a.com/data.csv' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([{ url: 'http://a.com/data.csv', path: 'data.csv' }]); - }); - - it('should calculate paths when only files is provided', () => { - const fetch_cfg: FetchConfig[] = [{ files: ['foo/__init__.py', 'foo/mod.py', 'foo2/mod.py'] }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'foo/__init__.py', path: 'foo/__init__.py' }, - { url: 'foo/mod.py', path: 'foo/mod.py' }, - { url: 'foo2/mod.py', path: 'foo2/mod.py' }, - ]); - }); - - it('should calculate paths when files and to_folder is provided', () => { - const fetch_cfg: FetchConfig[] = [{ files: ['foo/__init__.py', 'foo/mod.py'], to_folder: '/my/lib/' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'foo/__init__.py', path: '/my/lib/foo/__init__.py' }, - { url: 'foo/mod.py', path: '/my/lib/foo/mod.py' }, - ]); - }); - - it('should calculate paths when from and files and to_folder is provided', () => { - const fetch_cfg: FetchConfig[] = [ - { from: 'http://a.com/download/', files: ['foo/__init__.py', 'foo/mod.py'], to_folder: '/my/lib/' }, - ]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'http://a.com/download/foo/__init__.py', path: '/my/lib/foo/__init__.py' }, - { url: 'http://a.com/download/foo/mod.py', path: '/my/lib/foo/mod.py' }, - ]); - }); - - it("should error out while calculating paths when filename cannot be determined from 'from'", () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://google.com/', to_folder: '/tmp' }]; - expect(() => calculateFetchPaths(fetch_cfg)).toThrowError( - "Couldn't determine the filename from the path http://google.com/", - ); - }); - - it('should calculate paths when to_file is explicitly supplied', () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://a.com/data.csv?version=1', to_file: 'pkg/tmp/data.csv' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([{ path: 'pkg/tmp/data.csv', url: 'http://a.com/data.csv?version=1' }]); - }); - - it('should error out when both to_file and files parameters are provided', () => { - const fetch_cfg: FetchConfig[] = [ - { from: 'http://a.com/data.csv?version=1', to_file: 'pkg/tmp/data.csv', files: ['a.py', 'b.py'] }, - ]; - expect(() => calculateFetchPaths(fetch_cfg)).toThrowError( - "Cannot use 'to_file' and 'files' parameters together!", - ); - }); -}); diff --git a/pyscriptjs/tests/unit/exceptions.test.ts b/pyscriptjs/tests/unit/exceptions.test.ts deleted file mode 100644 index fc276e4f..00000000 --- a/pyscriptjs/tests/unit/exceptions.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { expect, it, jest, describe, afterEach } from '@jest/globals'; -import { _createAlertBanner, UserError, FetchError, ErrorCode } from '../../src/exceptions'; - -describe('Test _createAlertBanner', () => { - afterEach(() => { - // Ensure we always have a clean body - document.body.innerHTML = `
Hello World
`; - }); - - it("error level shouldn't contain close button", async () => { - _createAlertBanner('Something went wrong!', 'error'); - - const banner = document.getElementsByClassName('alert-banner'); - const closeButton = document.getElementById('alert-close-button'); - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe('Something went wrong!'); - expect(closeButton).toBeNull(); - }); - - it('warning level should contain close button', async () => { - _createAlertBanner('This is a warning', 'warning'); - - const banner = document.getElementsByClassName('alert-banner'); - const closeButton = document.getElementById('alert-close-button'); - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toContain('This is a warning'); - expect(closeButton).not.toBeNull(); - }); - - it('error level banner should log to console', async () => { - const logSpy = jest.spyOn(console, 'error'); - - _createAlertBanner('Something went wrong!'); - - expect(logSpy).toHaveBeenCalledWith('Something went wrong!'); - }); - - it('warning level banner should log to console', async () => { - const logSpy = jest.spyOn(console, 'warn'); - - _createAlertBanner('This warning', 'warning'); - - expect(logSpy).toHaveBeenCalledWith('This warning'); - }); - - it('close button should remove element from page', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - _createAlertBanner('Warning!', 'warning'); - - // Just a sanity check - banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(1); - - const closeButton = document.getElementById('alert-close-button'); - if (closeButton) { - closeButton.click(); - // Confirm that clicking the close button, removes the element - banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - } else { - fail('Unable to find close button on the page, but should exist'); - } - }); - - it("toggling logging off on error alert shouldn't log to console", async () => { - const errorLogSpy = jest.spyOn(console, 'error'); - - _createAlertBanner('Test error', 'error', 'text', false); - expect(errorLogSpy).not.toHaveBeenCalledWith('Test error'); - }); - - it("toggling logging off on warning alert shouldn't log to console", async () => { - const warnLogSpy = jest.spyOn(console, 'warn'); - _createAlertBanner('Test warning', 'warning', 'text', false); - expect(warnLogSpy).not.toHaveBeenCalledWith('Test warning'); - }); - - it('_createAlertbanner messageType text writes message to content', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - const message = '

Test message

'; - _createAlertBanner(message, 'error', 'text'); - banner = document.getElementsByClassName('alert-banner'); - - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe('<p>Test message</p>'); - expect(banner[0].textContent).toBe(message); - }); - - it('_createAlertbanner messageType html writes message to innerHTML', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - const message = '

Test message

'; - _createAlertBanner(message, 'error', 'html'); - banner = document.getElementsByClassName('alert-banner'); - - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe(message); - expect(banner[0].textContent).toBe('Test message'); - }); -}); - -describe('Test Exceptions', () => { - it('UserError contains errorCode and shows in message', async () => { - const errorCode = ErrorCode.BAD_CONFIG; - const message = 'Test error'; - const userError = new UserError(ErrorCode.BAD_CONFIG, message); - expect(userError.errorCode).toBe(errorCode); - expect(userError.message).toBe(`(${errorCode}): ${message}`); - }); - - it('FetchError contains errorCode and shows in message', async () => { - const errorCode = ErrorCode.FETCH_NOT_FOUND_ERROR; - const message = 'Test error'; - const fetchError = new FetchError(errorCode, message); - expect(fetchError.errorCode).toBe(errorCode); - expect(fetchError.message).toBe(`(${errorCode}): ${message}`); - }); -}); diff --git a/pyscriptjs/tests/unit/fetch.test.ts b/pyscriptjs/tests/unit/fetch.test.ts deleted file mode 100644 index 21bb7604..00000000 --- a/pyscriptjs/tests/unit/fetch.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { describe, it, expect, jest } from '@jest/globals'; -import { FetchError, ErrorCode } from '../../src/exceptions'; -import { robustFetch } from '../../src/fetch'; -import { Response } from 'node-fetch'; - -describe('robustFetch', () => { - it('should return a response object', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response((status = '200'), 'Hello World'))); - - const response = await robustFetch('https://pyscript.net'); - expect(response).toBeInstanceOf(Response); - expect(response.status).toBe(200); - }); - - it('receiving a 404 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 404 }))); - - const url = 'https://pyscript.net/non-existent-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_NOT_FOUND_ERROR, - `Fetching from URL ${url} failed with error 404 (Not Found). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 401 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('', { status: 401 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_UNAUTHORIZED_ERROR, - `Fetching from URL ${url} failed with error 401 (Unauthorized). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 403 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('', { status: 403 }))); - - const url = 'https://pyscript.net/secret-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_FORBIDDEN_ERROR, - `Fetching from URL ${url} failed with error 403 (Forbidden). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 500 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 500 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_SERVER_ERROR, - `Fetching from URL ${url} failed with error 500 (Internal Server Error). ` + - `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 503 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 503 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_UNAVAILABLE_ERROR, - `Fetching from URL ${url} failed with error 503 (Service Unavailable). ` + - `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('handle TypeError when using a bad url', async () => { - global.fetch = jest.fn(() => Promise.reject(new TypeError('Failed to fetch'))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_ERROR, - `Fetching from URL ${url} failed with error 'Failed to fetch'. Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('handle failed to fetch when using local file', async () => { - global.fetch = jest.fn(() => Promise.reject(new TypeError('Failed to fetch'))); - - const url = './my-awesome-pyscript.py'; - - const expectedError = new FetchError( - ErrorCode.FETCH_ERROR, - `PyScript: Access to local files - (using [[fetch]] configurations in <py-config>) - is not available when directly opening a HTML file; - you must use a webserver to serve the additional files. - See this reference - on starting a simple webserver with Python. - `, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); -}); diff --git a/pyscriptjs/tests/unit/logger.test.ts b/pyscriptjs/tests/unit/logger.test.ts deleted file mode 100644 index 64132740..00000000 --- a/pyscriptjs/tests/unit/logger.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { jest } from '@jest/globals'; -import { getLogger } from '../../src/logger'; - -describe('getLogger', () => { - it('getLogger caches results', () => { - let a1 = getLogger('a'); - let b = getLogger('b'); - let a2 = getLogger('a'); - - expect(a1).not.toBe(b); - expect(a1).toBe(a2); - }); - - it('logger.info prints to console.info', () => { - console.info = jest.fn(); - - const logger = getLogger('prefix1'); - logger.info('hello world'); - expect(console.info).toHaveBeenCalledWith('[prefix1] hello world'); - }); - - it('logger.info handles multiple args', () => { - console.info = jest.fn(); - - const logger = getLogger('prefix2'); - logger.info('hello', 'world', 1, 2, 3); - expect(console.info).toHaveBeenCalledWith('[prefix2] hello', 'world', 1, 2, 3); - }); - - it('logger.{debug,warn,error} also works', () => { - console.info = jest.fn(); - console.debug = jest.fn(); - console.warn = jest.fn(); - console.error = jest.fn(); - - const logger = getLogger('prefix3'); - logger.debug('this is a debug'); - logger.warn('this is a warning'); - logger.error('this is an error'); - - expect(console.info).not.toHaveBeenCalled(); - expect(console.debug).toHaveBeenCalledWith('[prefix3] this is a debug'); - expect(console.warn).toHaveBeenCalledWith('[prefix3] this is a warning'); - expect(console.error).toHaveBeenCalledWith('[prefix3] this is an error'); - }); -}); diff --git a/pyscriptjs/tests/unit/main.test.ts b/pyscriptjs/tests/unit/main.test.ts deleted file mode 100644 index 2fa9c829..00000000 --- a/pyscriptjs/tests/unit/main.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { describe, it, beforeEach, expect } from '@jest/globals'; -import { UserError, ErrorCode } from '../../src/exceptions'; -import { PyScriptApp } from '../../src/main'; - -describe('Test withUserErrorHandler', () => { - class MyApp extends PyScriptApp { - myRealMain: any; - - constructor(myRealMain) { - super(); - this.myRealMain = myRealMain; - } - - async _realMain() { - this.myRealMain(); - } - } - - beforeEach(() => { - // Ensure we always have a clean body - document.body.innerHTML = `
Hello World
`; - }); - - it("userError doesn't stop execution", async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'Computer says no'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): Computer says no'); - }); - - it('userError escapes by default', async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'hello
'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): hello <br>'); - }); - - it("userError messageType=html don't escape", async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'hello
', 'html'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): hello
'); - }); - - it('any other exception should stop execution and raise', async () => { - function myRealMain() { - throw new Error('Explosions!'); - } - - const app = new MyApp(myRealMain); - expect(app.main()).rejects.toThrow(new Error('Explosions!')); - }); -}); diff --git a/pyscriptjs/tests/unit/plugin.test.ts b/pyscriptjs/tests/unit/plugin.test.ts deleted file mode 100644 index b349e0ad..00000000 --- a/pyscriptjs/tests/unit/plugin.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { validateConfigParameter, validateConfigParameterFromArray } from '../../src/plugin'; -import { UserError } from '../../src/exceptions'; - -describe('validateConfigParameter', () => { - const validator = a => a.charAt(0) === 'a'; - - it('should not change a matching config option', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(pyconfig).toStrictEqual({ a: 'a1', dummy: 'dummy' }); - }); - - it('should set the default value if no value is present', () => { - const pyconfig = { dummy: 'dummy' }; - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(pyconfig).toStrictEqual({ a: 'a_default', dummy: 'dummy' }); - }); - - it('should error if the provided value is not valid', () => { - const pyconfig = { a: 'NotValidValue', dummy: 'dummy' }; - const func = () => - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(func).toThrow(UserError); - expect(func).toThrow('(PY1000): Invalid value "NotValidValue" for config.a. Should start with \'a\''); - }); - - it('should error if the provided default is not valid', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - const func = () => - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'NotValidDefault', - hintMessage: "Should start with 'a'", - }); - expect(func).toThrow(Error); - expect(func).toThrow( - 'Default value "NotValidDefault" for a is not a valid argument, according to the provided validator function. Should start with \'a\'', - ); - }); -}); - -describe('validateConfigParameterFromArray', () => { - const possibilities = ['a1', 'a2', true, 42, 'a_default']; - - it('should not change a matching config option', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(pyconfig).toStrictEqual({ a: 'a1', dummy: 'dummy' }); - }); - - it('should set the default value if no value is present', () => { - const pyconfig = { dummy: 'dummy' }; - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(pyconfig).toStrictEqual({ a: 'a_default', dummy: 'dummy' }); - }); - - it('should error if the provided value is not in possible_values', () => { - const pyconfig = { a: 'NotValidValue', dummy: 'dummy' }; - const func = () => - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(func).toThrow(Error); - expect(func).toThrow( - '(PY1000): Invalid value "NotValidValue" for config.a. The only accepted values are: ["a1", "a2", true, 42, "a_default"]', - ); - }); - - it('should error if the provided default is not in possible_values', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - const func = () => - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'NotValidDefault', - }); - expect(func).toThrow(Error); - expect(func).toThrow( - 'Default value "NotValidDefault" for a is not a valid argument, according to the provided validator function. The only accepted values are: ["a1", "a2", true, 42, "a_default"]', - ); - }); -}); diff --git a/pyscriptjs/tests/unit/pyconfig.test.ts b/pyscriptjs/tests/unit/pyconfig.test.ts deleted file mode 100644 index 78e29660..00000000 --- a/pyscriptjs/tests/unit/pyconfig.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { jest, describe, it, expect } from '@jest/globals'; -import { loadConfigFromElement, defaultConfig } from '../../src/pyconfig'; -import { version } from '../../src/version'; -import { UserError } from '../../src/exceptions'; - -// inspired by trump typos -const covfefeConfig = { - name: 'covfefe', - interpreters: [ - { - src: '/demo/covfefe.js', - name: 'covfefe', - lang: 'covfefe', - }, - ], - wonderful: 'disgrace', -}; - -const covfefeConfigToml = ` -name = "covfefe" - -wonderful = "hijacked" - -[[interpreters]] -src = "/demo/covfefe.js" -name = "covfefe" -lang = "covfefe" -`; - -// ideally, I would like to be able to just do "new HTMLElement" in the tests -// below, but it is not permitted. The easiest work around is to create a fake -// custom element: not that we are not using any specific feature of custom -// elements: the sole purpose to FakeElement is to be able to instantiate them -// in the tests. -class FakeElement extends HTMLElement { - constructor() { - super(); - } -} -customElements.define('fake-element', FakeElement); - -function make_config_element(attrs) { - const el = new FakeElement(); - for (const [key, value] of Object.entries(attrs)) { - el.setAttribute(key, value as string); - } - return el; -} - -describe('loadConfigFromElement', () => { - const xhrMockClass = () => ({ - open: jest.fn(), - send: jest.fn(), - responseText: JSON.stringify(covfefeConfig), - }); - // @ts-ignore - window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass); - - it('should load the default config', () => { - const config = loadConfigFromElement(null); - expect(config).toBe(defaultConfig); - expect(config.pyscript.version).toBe(version); - }); - - it('an empty should load the default config', () => { - const el = make_config_element({}); - let config = loadConfigFromElement(el); - expect(config).toBe(defaultConfig); - expect(config.pyscript.version).toBe(version); - }); - - it('should load the JSON config from inline', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = JSON.stringify(covfefeConfig); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // schema_version wasn't present in `inline config` but is still set due to merging with default - expect(config.schema_version).toBe(1); - }); - - it('should load the JSON config from src attribute', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // wonderful is an extra key supplied by the user and is unaffected by merging process - expect(config.wonderful).toBe('disgrace'); - // schema_version wasn't present in `config from src` but is still set due to merging with default - expect(config.schema_version).toBe(1); - }); - - it('should load the JSON config from both inline and src', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - el.innerHTML = JSON.stringify({ version: '0.2a', wonderful: 'hijacked' }); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // config from src had an extra key "wonderful" with value "disgrace" - // inline config had the same extra key "wonderful" with value "hijacked" - // the merge process works for extra keys that clash as well - // so the final value is "hijacked" since inline takes precedence over src - expect(config.wonderful).toBe('hijacked'); - // version wasn't present in `config from src` but is still set due to merging with default and inline - expect(config.version).toBe('0.2a'); - }); - - it('should be able to load an inline TOML config', () => { - // TOML is the default type - const el = make_config_element({}); - el.innerHTML = covfefeConfigToml; - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // schema_version wasn't present in `inline config` but is still set due to merging with default - expect(config.schema_version).toBe(1); - expect(config.wonderful).toBe('hijacked'); - }); - - it('should NOT be able to load an inline config in JSON format with type as TOML', () => { - const el = make_config_element({}); - el.innerHTML = JSON.stringify(covfefeConfig); - expect(() => loadConfigFromElement(el)).toThrow( - /config supplied: {.*} is an invalid TOML and cannot be parsed/, - ); - }); - - it('should NOT be able to load an inline config in TOML format with type as JSON', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should NOT be able to load an inline TOML config with a JSON config from src with type as toml', () => { - const el = make_config_element({ src: '/covfefe.json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow( - /config supplied: {.*} is an invalid TOML and cannot be parsed/, - ); - }); - - it('should NOT be able to load an inline TOML config with a JSON config from src with type as json', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should error out when passing an invalid JSON', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = '[['; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should error out when passing an invalid TOML', () => { - const el = make_config_element({}); - el.innerHTML = '[['; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should not escape characters like &', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = JSON.stringify({ - fetch: [{ from: 'https://datausa.io/api/data?drilldowns=Nation&measures=Population' }], - }); - const config = loadConfigFromElement(el); - expect(config.fetch[0].from).toBe('https://datausa.io/api/data?drilldowns=Nation&measures=Population'); - }); -}); diff --git a/pyscriptjs/tests/unit/pyodide.test.ts b/pyscriptjs/tests/unit/pyodide.test.ts deleted file mode 100644 index 2b382ae7..00000000 --- a/pyscriptjs/tests/unit/pyodide.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { AppConfig } from '../../src/pyconfig'; -import { InterpreterClient } from '../../src/interpreter_client'; -import { CaptureStdio } from '../../src/stdio'; -import * as Synclink from 'synclink'; -import { describe, beforeAll, afterAll, it, expect } from '@jest/globals'; -// We can't import RemoteInterpreter at top level because we need to mock the -// Python package in setup.ts -// But we can import the types at top level. -// TODO: is there a better way to handle this? -import type { RemoteInterpreter } from '../../src/remote_interpreter'; - -describe('RemoteInterpreter', () => { - let interpreter: InterpreterClient; - let stdio: CaptureStdio = new CaptureStdio(); - let RemoteInterpreter; - const { port1, port2 } = new Synclink.FakeMessageChannel() as unknown as MessageChannel; - beforeAll(async () => { - const SRC = '../pyscriptjs/node_modules/pyodide/pyodide.js'; - const config: AppConfig = { interpreters: [{ src: SRC }], packages: [] }; - // Dynamic import of RemoteInterpreter sees our mocked Python package. - ({ RemoteInterpreter } = await import('../../src/remote_interpreter')); - const remote_interpreter = new RemoteInterpreter(SRC); - - port1.start(); - port2.start(); - Synclink.expose(remote_interpreter, port2); - const wrapped_remote_interpreter = Synclink.wrap(port1); - interpreter = new InterpreterClient( - config, - stdio, - wrapped_remote_interpreter as Synclink.Remote, - ); - - /** - * Since import { loadPyodide } from 'pyodide'; - * is not used inside `src/pyodide.ts`, the function - * `interpreter.loadInterpreter();` below which calls - * `loadPyodide()` results in an expected issue of: - * ReferenceError: loadPyodide is not defined - * - * To make jest happy, while also not importing - * explicitly inside `src/pyodide.ts`, the - * following lines - so as to dynamically import - * and make it available in the global namespace - * - are used. - * - * Pyodide uses a "really hacky" method to get the - * URL/Path where packages/package data are stored; - * it throws an error, catches it, and parses it. In - * Jest, this calculated path is different than in - * the browser/Node, so files cannot be found and the - * test fails. We set indexURL below the correct location - * to fix this. - * See https://github.com/pyodide/pyodide/blob/7dfee03a82c19069f714a09da386547aeefef242/src/js/pyodide.ts#L161-L179 - */ - const pyodideSpec = await import('pyodide'); - global.loadPyodide = async options => - pyodideSpec.loadPyodide(Object.assign({ indexURL: '../pyscriptjs/node_modules/pyodide/' }, options)); - await interpreter.initializeRemote(); - }); - - afterAll(async () => { - port1.close(); - port2.close(); - }); - - it('should check if interpreter is an instance of abstract Interpreter', async () => { - expect(interpreter).toBeInstanceOf(InterpreterClient); - }); - - it('should check if interpreter can run python code asynchronously', async () => { - expect((await interpreter.run('2+3')).result).toBe(5); - }); - - it('should capture stdout', async () => { - stdio.reset(); - await interpreter.run("print('hello')"); - expect(stdio.captured_stdout).toBe('hello\n'); - }); - - it('should check if interpreter is able to load a package', async () => { - stdio.reset(); - await interpreter._remote.loadPackage('numpy'); - await interpreter.run('import numpy as np'); - await interpreter.run('x = np.ones((10,))'); - await interpreter.run('print(x)'); - expect(stdio.captured_stdout).toBe('[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n'); - }); -}); diff --git a/pyscriptjs/tests/unit/setup.ts b/pyscriptjs/tests/unit/setup.ts deleted file mode 100644 index a2c21c0e..00000000 --- a/pyscriptjs/tests/unit/setup.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { jest } from '@jest/globals'; -import { directoryManifest } from '../../directoryManifest.mjs'; - -jest.unstable_mockModule('../../src/python_package', async () => ({ - python_package: await directoryManifest('./src/python/'), -})); - -globalThis.jest = jest; diff --git a/pyscriptjs/tests/unit/stdio.test.ts b/pyscriptjs/tests/unit/stdio.test.ts deleted file mode 100644 index 56297776..00000000 --- a/pyscriptjs/tests/unit/stdio.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { expect } from '@jest/globals'; -import { type Stdio, CaptureStdio, StdioMultiplexer, TargetedStdio } from '../../src/stdio'; - -describe('CaptureStdio', () => { - it('captured streams are initialized to empty string', () => { - let stdio = new CaptureStdio(); - expect(stdio.captured_stdout).toBe(''); - expect(stdio.captured_stderr).toBe(''); - }); - - it('stdout() and stderr() captures', () => { - let stdio = new CaptureStdio(); - stdio.stdout_writeline('hello'); - stdio.stdout_writeline('world'); - stdio.stderr_writeline('this is an error'); - expect(stdio.captured_stdout).toBe('hello\nworld\n'); - expect(stdio.captured_stderr).toBe('this is an error\n'); - }); - - it('reset() works', () => { - let stdio = new CaptureStdio(); - stdio.stdout_writeline('aaa'); - stdio.stderr_writeline('bbb'); - stdio.reset(); - expect(stdio.captured_stdout).toBe(''); - expect(stdio.captured_stderr).toBe(''); - }); -}); - -describe('StdioMultiplexer', () => { - let a: CaptureStdio; - let b: CaptureStdio; - let multi: StdioMultiplexer; - - beforeEach(() => { - a = new CaptureStdio(); - b = new CaptureStdio(); - multi = new StdioMultiplexer(); - }); - - it('works without listeners', () => { - // no listeners, messages are ignored - multi.stdout_writeline('out 1'); - multi.stderr_writeline('err 1'); - expect(a.captured_stdout).toBe(''); - expect(a.captured_stderr).toBe(''); - expect(b.captured_stdout).toBe(''); - expect(b.captured_stderr).toBe(''); - }); - - it('redirects to multiple listeners', () => { - multi.addListener(a); - multi.stdout_writeline('out 1'); - multi.stderr_writeline('err 1'); - - multi.addListener(b); - multi.stdout_writeline('out 2'); - multi.stderr_writeline('err 2'); - - expect(a.captured_stdout).toBe('out 1\nout 2\n'); - expect(a.captured_stderr).toBe('err 1\nerr 2\n'); - - expect(b.captured_stdout).toBe('out 2\n'); - expect(b.captured_stderr).toBe('err 2\n'); - }); -}); - -describe('TargetedStdio', () => { - let capture: CaptureStdio; - let targeted: TargetedStdio; - let error_targeted: TargetedStdio; - let multi: StdioMultiplexer; - - beforeEach(() => { - //DOM element to capture stdout and stderr - let target_div = document.getElementById('output-id'); - - if (target_div === null) { - target_div = document.createElement('div'); - target_div.id = 'output-id'; - document.body.appendChild(target_div); - } else { - target_div.innerHTML = ''; - } - - //DOM element to capture stderr - let error_div = document.getElementById('error-id'); - - if (error_div === null) { - error_div = document.createElement('div'); - error_div.id = 'error-id'; - document.body.appendChild(error_div); - } else { - error_div.innerHTML = ''; - } - - const tag = document.createElement('div'); - tag.setAttribute('output', 'output-id'); - tag.setAttribute('stderr', 'error-id'); - - capture = new CaptureStdio(); - targeted = new TargetedStdio(tag, 'output', true, true); - error_targeted = new TargetedStdio(tag, 'stderr', false, true); - - multi = new StdioMultiplexer(); - multi.addListener(capture); - multi.addListener(targeted); - multi.addListener(error_targeted); - }); - - it('targeted id is set by constructor', () => { - expect(targeted.source_attribute).toBe('output'); - }); - - it('targeted stdio/stderr also goes to multiplexer', () => { - multi.stdout_writeline('out 1'); - multi.stderr_writeline('out 2'); - expect(capture.captured_stdout).toBe('out 1\n'); - expect(capture.captured_stderr).toBe('out 2\n'); - expect(document.getElementById('output-id')?.innerHTML).toBe('out 1
out 2
'); - expect(document.getElementById('error-id')?.innerHTML).toBe('out 2
'); - }); - - it('Add and remove targeted listener', () => { - multi.stdout_writeline('out 1'); - multi.removeListener(targeted); - multi.stdout_writeline('out 2'); - multi.addListener(targeted); - multi.stdout_writeline('out 3'); - - //all three should be captured by multiplexer - expect(capture.captured_stdout).toBe('out 1\nout 2\nout 3\n'); - //out 2 should not be present in the DOM element - expect(document.getElementById('output-id')?.innerHTML).toBe('out 1
out 3
'); - }); -}); diff --git a/pyscriptjs/tests/unit/utils.test.ts b/pyscriptjs/tests/unit/utils.test.ts deleted file mode 100644 index 848cd8f8..00000000 --- a/pyscriptjs/tests/unit/utils.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { beforeEach, expect, describe, it } from '@jest/globals'; -import { ensureUniqueId, joinPaths, createSingularWarning } from '../../src/utils'; - -describe('Utils', () => { - let element: HTMLElement; - - beforeEach(() => { - element = document.createElement('div'); - }); - - it('ensureUniqueId sets unique id on element', async () => { - expect(element.id).toBe(''); - - ensureUniqueId(element); - - expect(element.id).toBe('py-internal-0'); - }); - - it('ensureUniqueId sets unique id with increasing counter', async () => { - const secondElement = document.createElement('div'); - - expect(element.id).toBe(''); - expect(secondElement.id).toBe(''); - - ensureUniqueId(element); - ensureUniqueId(secondElement); - - // The counter will have been incremented on - // the previous test, make sure it keeps increasing - expect(element.id).toBe('py-internal-1'); - expect(secondElement.id).toBe('py-internal-2'); - }); -}); - -describe('JoinPaths', () => { - it('should remove trailing slashes from the beginning and the end', () => { - const paths: string[] = ['///abc/d/e///']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('/abc/d/e'); - }); - - it('should not remove slashes from the middle to preserve protocols such as http', () => { - const paths: string[] = ['http://google.com', '///data.txt']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('http://google.com/data.txt'); - }); - - it('should not join paths when they are empty strings', () => { - const paths: string[] = ['', '///hhh/ll/pp///', '', 'kkk']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('hhh/ll/pp/kkk'); - }); - - describe('createSingularBanner', () => { - it('should create one and new banner containing the sentinel text, and not duplicate it', () => { - //One warning banner with the desired text should be created - createSingularWarning('A unique error message', 'unique'); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - - //Should still only be one banner, since the second uses the existing sentinel value "unique" - createSingularWarning('This banner should not appear', 'unique'); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - - //If the sentinel value is not provided, the entire msg is used as the sentinel - createSingularWarning('A unique error message', null); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - }); - }); -}); diff --git a/pyscriptjs/tsconfig.json b/pyscriptjs/tsconfig.json deleted file mode 100644 index d9c7d053..00000000 --- a/pyscriptjs/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "_version": "3.0.0", - - "include": ["src/**/*"], - "exclude": ["node_modules/*", "__sapper__/*", "public/*", "src/interpreter_worker/*"], - "compilerOptions": { - "moduleResolution": "node", - "target": "ES2020", - "module": "ES2020", - "types": ["jest", "node"], - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "isolatedModules": true, - "forceConsistentCasingInFileNames": true, - "lib": ["es2017", "dom", "DOM.Iterable"] - } -} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..3dac3eb9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +black +isort +pytest==7.1.2 +pre-commit +playwright==1.33.0 +pytest-playwright==0.3.3 +pytest-xdist==3.3.0 +pexpect +pyodide_py==0.24.1 +micropip +toml +numpy +pillow