diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 2c19cbee348..2e178927525 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -11,7 +11,9 @@ body: There will always be more issues than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so we can focus our time on helping people like you who fill out the issue form completely. Thank you for your collaboration! - There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists + There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists. + + Finally, if you are opening **a bug report related to PyScript.com** please [use this repository instead](https://github.com/anaconda/pyscript-dot-com-issues/issues/new/choose). Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐! - type: checkboxes diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3d816e9750b..591e81853a0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,12 +4,9 @@ ## Changes - + ## Checklist - - -- [ ] All tests pass locally -- [ ] I have updated `CHANGELOG.md` -- [ ] I have created documentation for this(if applicable) +- [ ] I have checked `make build` works locally. +- [ ] I have created / updated documentation for this change (if applicable). diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..e29bff2bead --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + groups: + github-actions: + patterns: + - "*" # Group all Actions updates into a single larger pull request + schedule: + interval: weekly diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 6bbb666f2cd..43fe719dbf1 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -7,7 +7,7 @@ on: defaults: run: - working-directory: ./pyscript.core + working-directory: ./core jobs: prepare-release: @@ -17,12 +17,27 @@ jobs: uses: actions/checkout@v4 - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.x + + - name: Python venv + run: python -m venv env + + - name: Activate Python + run: source env/bin/activate + + - name: Update pip + run: pip install --upgrade pip + + - name: Install PyMinifier + run: pip install --ignore-requires-python python-minifier + + - name: Install Setuptools + run: pip install setuptools - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: @@ -35,20 +50,20 @@ jobs: ${{ runner.os }}- - name: NPM Install - run: npm install && npx playwright install + run: npm install && npx playwright install chromium - name: Build run: npm run build - name: Generate index.html working-directory: . - run: sed 's#_PATH_#./#' ./public/index.html > ./pyscript.core/dist/index.html + run: sed -e 's#_PATH_#./#' -e 's#_DOC_VERSION_#latest#' -e 's#_TAG_VERSION_##' -e 's#_VERSION_#latest#' ./public/index.html > ./core/dist/index.html - name: Zip dist folder run: zip -r -q ./build.zip ./dist - name: Prepare Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: draft: true prerelease: true diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 36828477dc5..5c605299dbc 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -6,7 +6,7 @@ on: defaults: run: - working-directory: ./pyscript.core + working-directory: ./core jobs: publish-release: @@ -19,12 +19,27 @@ jobs: uses: actions/checkout@v4 - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.x + + - name: Python venv + run: python -m venv env + + - name: Activate Python + run: source env/bin/activate + + - name: Update pip + run: pip install --upgrade pip + + - name: Install PyMinifier + run: pip install --ignore-requires-python python-minifier + + - name: Install Setuptools + run: pip install setuptools - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: @@ -37,14 +52,18 @@ jobs: ${{ runner.os }}- - name: npm install - run: npm install && npx playwright install + run: npm install && npx playwright install chromium - name: build run: npm run build - 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 + run: sed -e 's#_PATH_#https://pyscript.net/releases/${{ github.ref_name }}/#' -e 's#_DOC_VERSION_#${{ github.ref_name }}#' -e 's#_TAG_VERSION_#/tag/${{ github.ref_name }}#' -e 's#_VERSION_#${{ github.ref_name }}#' ./public/index.html > ./core/dist/index.html + + - name: Generate release.tar from snapshot and put it in dist/ + working-directory: . + run: tar -cvf ../release.tar * && mv ../release.tar . - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 944a26f3981..b7f51d52ae7 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -10,7 +10,7 @@ on: defaults: run: - working-directory: ./pyscript.core + working-directory: ./core jobs: publish-snapshot: @@ -23,12 +23,27 @@ jobs: uses: actions/checkout@v4 - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.x + + - name: Python venv + run: python -m venv env + + - name: Activate Python + run: source env/bin/activate + + - name: Update pip + run: pip install --upgrade pip + + - name: Install PyMinifier + run: pip install --ignore-requires-python python-minifier + + - name: Install Setuptools + run: pip install setuptools - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: @@ -41,7 +56,7 @@ jobs: ${{ runner.os }}- - name: Install Dependencies - run: npm install && npx playwright install + run: npm install && npx playwright install chromium - name: Build Pyscript.core run: npm run build @@ -54,7 +69,7 @@ jobs: - 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 + run: sed -e 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' -e 's#_DOC_VERSION_#${{ inputs.snapshot_version }}#' -e 's#_TAG_VERSION_#/tag/${{ inputs.snapshot_version }}#' -e 's#_VERSION_#${{ inputs.snapshot_version }}#' ./public/index.html > ./core/dist/index.html - name: Copy to Snapshot run: > diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index f2a1df45491..89a0e2b8902 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -1,11 +1,11 @@ name: "Publish Unstable" on: - push: # Only run on merges into main that modify files under pyscript.core/ and examples/ + push: # Only run on merges into main that modify files under core/ and examples/ branches: - main paths: - - pyscript.core/** + - core/** - examples/** workflow_dispatch: @@ -18,18 +18,33 @@ jobs: contents: read defaults: run: - working-directory: ./pyscript.core + working-directory: ./core steps: - name: Checkout uses: actions/checkout@v4 - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.x + + - name: Python venv + run: python -m venv env + + - name: Activate Python + run: source env/bin/activate + + - name: Update pip + run: pip install --upgrade pip + + - name: Install PyMinifier + run: pip install --ignore-requires-python python-minifier + + - name: Install Setuptools + run: pip install setuptools - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: @@ -42,14 +57,14 @@ jobs: ${{ runner.os }}- - name: NPM Install - run: npm install && npx playwright install + run: npm install && npx playwright install chromium - 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 + run: sed -e 's#_PATH_#./#' -e 's#_DOC_VERSION_#latest#' -e 's#_TAG_VERSION_##' -e 's#_VERSION_#latest#' ./public/index.html > ./core/dist/index.html - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f7b83be7730..785b7cbbf3f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,20 +5,20 @@ on: branches: - main paths: - - pyscript.core/** + - core/** - .github/workflows/test.yml pull_request: # Only run on merges into main that modify certain files branches: - main paths: - - pyscript.core/** + - core/** - .github/workflows/test.yml workflow_dispatch: jobs: BuildAndTest: - runs-on: ubuntu-latest-8core + runs-on: ubuntu-latest env: MINICONDA_PYTHON_VERSION: py38 MINICONDA_VERSION: 4.11.0 @@ -37,12 +37,12 @@ jobs: run: git log --graph -3 - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: @@ -55,7 +55,7 @@ jobs: ${{ runner.os }}- - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 - name: Create and activate virtual environment run: | @@ -69,24 +69,12 @@ jobs: make setup - name: Build - run: make build + run: make build # Integration tests run in the build step. - - name: Integration Tests - #run: make test-integration-parallel - run: | - make test-integration - - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: pyscript path: | - pyscript.core/dist/ + 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 deleted file mode 100644 index 6debdbdce4d..00000000000 --- a/.github/workflows/test_report.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Test Report -on: - workflow_run: - workflows: ['\[CI\] Test'] - types: - - completed -jobs: - report: - runs-on: ubuntu-latest-8core - steps: - - uses: dorny/test-reporter@v1.6.0 - with: - artifact: test_results - name: Test reports - path: "*.xml" - reporter: java-junit diff --git a/.gitignore b/.gitignore index d19ac9a9b6d..6ccef40cf9e 100644 --- a/.gitignore +++ b/.gitignore @@ -142,10 +142,11 @@ coverage/ 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 +core/test-results/* +core/core.* +core/dist +core/dist.zip +core/src/plugins.js +core/src/stdlib/pyscript.js +core/src/3rd-party/* +!core/src/3rd-party/READMEmd diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5ae4bdb5fc6..b18b22ee168 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,10 +4,10 @@ ci: #skip: [eslint] autoupdate_schedule: monthly -default_stages: [commit] +default_stages: [pre-commit] repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-builtin-literals - id: check-case-conflict @@ -21,33 +21,33 @@ repos: - id: check-yaml - id: detect-private-key - id: end-of-file-fixer - exclude: pyscript\.core/dist|\.min\.js$ + exclude: core/dist|\.min\.js$ - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.11.0 + rev: 25.1.0 hooks: - id: black - exclude: pyscript\.core/src/stdlib/pyscript/__init__\.py + exclude: core/tests + args: ["-l", "88", "--skip-string-normalization"] - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.4.1 hooks: - id: codespell # See 'pyproject.toml' for args - exclude: \.js\.map$ + exclude: fs\.py|\.js\.map$ additional_dependencies: - tomli + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.8 + hooks: + - id: ruff + exclude: core/tests + - repo: https://github.com/hoodmane/pyscript-prettier-precommit rev: "v3.0.0-alpha.6" hooks: - id: prettier - exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/|pyscript.core/src/3rd-party + exclude: core/tests|core/dist|core/types|core/src/stdlib/pyscript.js|pyscript\.sw/|core/src/3rd-party args: [--tab-width, "4"] - - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - name: isort (python) - args: [--profile, black] diff --git a/.prettierignore b/.prettierignore index bff93a895e5..32b310b5153 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,3 @@ ISSUE_TEMPLATE *.min.* package-lock.json -docs -examples/panel.html diff --git a/.readthedocs.yml b/.readthedocs.yml deleted file mode 100644 index b5324a7e886..00000000000 --- a/.readthedocs.yml +++ /dev/null @@ -1,28 +0,0 @@ -# .readthedocs.yaml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the version of Python and other tools you might need -build: - os: ubuntu-20.04 - tools: - python: miniconda3-4.7 - -# Build documentation in the docs/ directory with Sphinx -sphinx: - configuration: docs/conf.py - -conda: - environment: docs/environment.yml - -# If using Sphinx, optionally build your docs in additional formats such as PDF -# formats: -# - pdf - -# Optionally declare the Python requirements required to build your docs -python: - install: - - requirements: docs/requirements.txt diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index c536d8c4907..00000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,87 +0,0 @@ -# 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 ` + + + + + + +``` + +PyScript enables the creation of rich Python applications in the browser using +[Pyodide](https://pyodide.org/en/stable/) (a version of +[CPython](https://python.org/)), [MicroPython](https://micropython.org/), +[WASM](https://webassembly.org/), and modern web technologies. It means Python +now runs anywhere a browser runs: desktop, laptop, mobile, tablet, or any other +browser enabled device. -To get started see the [Beginning PyScript tutorial](https://docs.pyscript.net/latest/beginning-pyscript/). +To start building, read the +[Beginning PyScript tutorial](https://docs.pyscript.net/latest/beginning-pyscript/). -For examples see [here](https://pyscript.com/@examples). +For example applications, see [here](https://pyscript.com/@examples). Other useful resources: +- Our [Home Page](https://pyscript.net/) as an open source project. - The [official technical docs](https://docs.pyscript.net/). -- Our current [Home Page](https://pyscript.net/) on the web. -- A free-to-use [online editor](https://pyscript.com/) for trying PyScript. -- Our community [Discord Channel](https://discord.gg/BYB2kvyFwm), to keep in touch . +- A [YouTube channel](https://www.youtube.com/@PyScriptTV) with helpful videos + and community content. +- A free-to-use [online IDE](https://pyscript.com/) for trying PyScript. +- Our community [Discord Channel](https://discord.gg/BYB2kvyFwm), to keep in + touch . -Every Tuesday at 15:30 UTC there is the _PyScript Community Call_ on zoom, where we can talk about PyScript development in the open. Most of the maintainers regularly participate in the call, and everybody is welcome to join. +Every Tuesday at 15:30 UTC there is the _PyScript Community Call_ on zoom, +where we can talk about PyScript development in the open. Most of the +maintainers regularly participate in the call, and everybody is welcome to +join. This meeting is recorded and uploaded to our YouTube channel. -Every other Thursday at 16:00 UTC there is the _PyScript FUN_ call: this is a call in which everybody is encouraged to show what they did with PyScript. +Every other Thursday at 16:00 UTC there is the _PyScript FUN_ call: the focus +of this call is to share fun projects, goofy hacks or clever uses of PyScript. +It's a supportive, energetic and entertaining meeting. This meeting is also +recorded and uploaded to our YouTube channel. -For more details on how to join the calls and up to date schedule, consult the official calendar: +For more details on how to join the calls and up to date schedule, consult the +official calendar: - [Google calendar](https://calendar.google.com/calendar/u/0/embed?src=d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0@group.calendar.google.com&ctz=UTC) in UTC time; - [iCal format](https://calendar.google.com/calendar/ical/d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0%40group.calendar.google.com/public/basic.ics). -### Longer Version +## Contribute -PyScript is a meta project that aims to combine multiple open technologies into a framework that allows users to create sophisticated browser applications with Python. It integrates seamlessly with the way the DOM works in the browser and allows users to add Python logic in a way that feels natural both to web and Python developers. +For technical details of the code, please see the [README](core/README.md) in +the `core` directory. -## Try PyScript +Read the [contributing guide](https://docs.pyscript.net/latest/contributing/) +to learn about our development process, reporting bugs and improvements, +creating issues and asking questions. -To try PyScript, import the appropriate pyscript files into the `` tag of your html page: - -```html - - - - - - - -``` +Check out the [development process](https://docs.pyscript.net/latest/developers/) +documentation for more information on how to setup your development environment. -You can then use PyScript components in your html page. PyScript currently offers various ways of running Python code: - -- ` + + + + + +``` + +Once set up, you should be able to run the most common activities via the +`make` command: + +``` +$ make + +There is no default Makefile target right now. Try: + +make setup - check your environment and install the dependencies. +make update - update dependencies. +make clean - clean up auto-generated assets. +make build - build PyScript. +make precommit-check - run the precommit checks (run eslint). +make test - run all automated tests in playwright. +make fmt - format the code. +make fmt-check - check the code formatting. +``` + +## Artifacts + +There are two main artifacts in this project: + +- **stdlib** and its content: `src/stdlib/pyscript.js` exposes, as a + JavaScript object literal, all the _Python_ content within the folder + (recursively). +- **plugins** and its content: `src/plugins.js` exposes all available + _dynamic imports_, and is able to instrument the bundler to create files + apart from the `_dist/_` folder, so that by default _core_ remains as small + as possible. + +Accordingly, whenever a file contains this warning at its first line, **please +do not change such file directly before submitting a merge request**, as that +file will be overwritten at the next `npm run build` command, either here or +in _CI_: + +```js +// ⚠️ This file is an artifact: DO NOT MODIFY +``` + +## Plugins + +While community or third party plugins don't need to be part of this repository +and can be added just importing `@pyscript/core` as module, there are a few +plugins that we would like to make available by default and these are +considered _core plugins_. + +To add a _core plugin_ to this project define the plugin entry-point and name +in the `src/plugins` folder (see the `error.js` example) and create, if +necessary, a folder with the same name where extra files or dependencies can be +added. + +The _build_ command will include plugins by name as artifacts so that the +bundler can create ad-hoc files within the `dist/` folder. + +## Python + +The `pyscript` package available in _Python_ lives in the folder +`src/stdlib/pyscript/`. + +All _Python_ files will be embedded automatically whenever `npm run build` +happens and reflected into the `src/stdlib/pyscript.js` file. + +Its _core_ responsibility is to ensure those files will be available through +the filesystem in either the _main_ thread, or any _worker_. + +## Release + +To cut a new release of PyScript simply +[add a new release](https://github.com/pyscript/pyscript/releases) while +remembering to write a comprehensive changelog. A +[GitHub action](https://github.com/pyscript/pyscript/blob/main/.github/workflows/publish-release.yml) +will kick in and ensure the release is described and deployed to a URL with the +pattern: https://pyscript.net/releases/YYYY.M.v/ (year/month/version - as per +our [CalVer](https://calver.org/) versioning scheme). + +Then, the following three separate repositories need updating: + +- [Documentation](https://github.com/pyscript/docs) - Change the `version.json` + file in the root of the directory and then `node version-update.js`. +- [Homepage](https://github.com/pyscript/pyscript.net) - Ensure the version + referenced in `index.html` is the latest version. +- [PSDC](https://pyscript.com) - Use discord or Anaconda Slack (if you work at + Anaconda) to let the PSDC team know there's a new version, so they can update + their project templates. diff --git a/pyscript.core/dev.cjs b/core/dev.cjs similarity index 100% rename from pyscript.core/dev.cjs rename to core/dev.cjs diff --git a/core/eslint.config.mjs b/core/eslint.config.mjs new file mode 100644 index 00000000000..9b9cc86349b --- /dev/null +++ b/core/eslint.config.mjs @@ -0,0 +1,22 @@ +import globals from "globals"; +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + { + ignores: ["**/3rd-party/"], + }, + { + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.browser, + ...globals.es2021, + }, + }, + rules: { + "no-implicit-globals": ["error"], + }, + }, +]; diff --git a/pyscript.core/index.js b/core/index.js similarity index 100% rename from pyscript.core/index.js rename to core/index.js diff --git a/pyscript.core/jsdelivr.js b/core/jsdelivr.js similarity index 100% rename from pyscript.core/jsdelivr.js rename to core/jsdelivr.js diff --git a/pyscript.core/package-lock.json b/core/package-lock.json similarity index 67% rename from pyscript.core/package-lock.json rename to core/package-lock.json index f834954070f..6ce7af03450 100644 --- a/pyscript.core/package-lock.json +++ b/core/package-lock.json @@ -1,100 +1,102 @@ { "name": "@pyscript/core", - "version": "0.3.18", + "version": "0.6.53", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.3.18", + "version": "0.6.53", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", + "@webreflection/idb-map": "^0.3.2", + "@webreflection/utils": "^0.1.0", + "add-promise-listener": "^0.1.3", "basic-devtools": "^0.1.6", - "polyscript": "^0.6.13", + "polyscript": "^0.17.20", "sticky-module": "^0.1.1", "to-json-callback": "^0.1.1", "type-checked-collections": "^0.1.7" }, "devDependencies": { - "@codemirror/commands": "^6.3.3", - "@codemirror/lang-python": "^6.1.3", - "@codemirror/language": "^6.10.0", - "@codemirror/state": "^6.4.0", - "@codemirror/view": "^6.23.0", - "@playwright/test": "^1.41.1", - "@rollup/plugin-commonjs": "^25.0.7", - "@rollup/plugin-node-resolve": "^15.2.3", + "@codemirror/commands": "^6.8.1", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/language": "^6.11.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.8", + "@playwright/test": "^1.52.0", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-terser": "^0.4.4", - "@webreflection/toml-j0.4": "^1.1.3", - "@xterm/addon-fit": "^0.9.0-beta.1", - "chokidar": "^3.5.3", + "@webreflection/toml-j0.4": "^1.1.4", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/xterm": "^5.5.0", + "bun": "^1.2.13", + "chokidar": "^4.0.3", + "codedent": "^0.1.2", "codemirror": "^6.0.1", - "eslint": "^8.56.0", - "rollup": "^4.9.6", + "eslint": "^9.27.0", + "flatted": "^3.3.3", + "rollup": "^4.41.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", - "static-handler": "^0.4.3", - "typescript": "^5.3.3", - "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, + "static-handler": "^0.5.3", + "string-width": "^7.2.0", + "typescript": "^5.8.3", + "xterm-readline": "^1.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=20" } }, "node_modules/@codemirror/autocomplete": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.12.0.tgz", - "integrity": "sha512-r4IjdYFthwbCQyvqnSlx0WBHRHi8nBvU+WjJxFUij81qsBfhNudf/XKKmmC2j3m0LaOYUQTf3qiEK1J8lO1sdg==", + "version": "6.18.6", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", + "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.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.3.3", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz", - "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz", + "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", - "@codemirror/view": "^6.0.0", + "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "node_modules/@codemirror/lang-python": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.3.tgz", - "integrity": "sha512-S9w2Jl74hFlD5nqtUMIaXAq9t5WlM0acCkyuQWUUSvZclk1sV+UfnpFiZzuZSG+hfEaOmxKR5UxY/Uxswn7EhQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz", + "integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.3.2", "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", "@lezer/python": "^1.1.4" } }, "node_modules/@codemirror/language": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.0.tgz", - "integrity": "sha512-2vaNn9aPGCRFKWcHPFksctzJ8yS5p7YoaT+jHpc0UGKzNuAIx4qy6R5wiqbP+heEEdyaABA582mNqSHzSoYdmg==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.0.tgz", + "integrity": "sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -105,21 +107,23 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.2.tgz", - "integrity": "sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==", + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", + "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", + "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "node_modules/@codemirror/search": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.5.tgz", - "integrity": "sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==", + "version": "6.5.10", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.10.tgz", + "integrity": "sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", @@ -127,56 +131,118 @@ } }, "node_modules/@codemirror/state": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.0.tgz", - "integrity": "sha512-hm8XshYj5Fo30Bb922QX9hXB/bxOAVH+qaqHBzw5TKa72vOeslyGwd4X8M0c1dJ9JqxlaMceOQ8RsL9tC7gU0A==", - "dev": true + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } }, "node_modules/@codemirror/view": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.23.0.tgz", - "integrity": "sha512-/51px9N4uW8NpuWkyUX+iam5+PM6io2fm+QmRnzwqBy5v/pwGg9T0kILFtYeum8hjuvENtgsGNKluOfqIICmeQ==", + "version": "6.36.8", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.8.tgz", + "integrity": "sha512-yoRo4f+FdnD01fFt4XpfpMCcCAo9QvZOtbrXExn4SqzH32YC6LgzqxfLZw/r6Ge65xyY03mK/UfUqrVw1gFiFg==", "dev": true, + "license": "MIT", "dependencies": { - "@codemirror/state": "^6.4.0", + "@codemirror/state": "^6.5.0", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "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==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/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, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -184,33 +250,85 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -218,6 +336,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -226,170 +345,317 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "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==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", - "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@lezer/common": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", - "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==", - "dev": true + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "dev": true, + "license": "MIT" }, "node_modules/@lezer/highlight": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", - "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", "dev": true, + "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" } }, "node_modules/@lezer/lr": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.14.tgz", - "integrity": "sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", "dev": true, + "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" } }, "node_modules/@lezer/python": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.11.tgz", - "integrity": "sha512-C3QeLCcdAKJDUOsYjfFP6a1wdn8jhUNX200bgFm8TpKH1eM2PlgYQS5ugw6E38qGeEx7CP21I1Q52SoybXt0OQ==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz", + "integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==", "dev": true, + "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", "@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==", + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } + "license": "MIT" }, - "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==", + "node_modules/@oven/bun-darwin-aarch64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.2.13.tgz", + "integrity": "sha512-AOU4O9jxRp2TXeqoEfOjEaUNZb3+SUPBN8TIEnUjpnyLWPoYJGCeNdQuCDcUkmF3MJEmEuJdyF1IeOITozpC6A==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">= 8" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "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==", + "node_modules/@oven/bun-darwin-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64/-/bun-darwin-x64-1.2.13.tgz", + "integrity": "sha512-kJ2iOvxY8uz5/nu+8zIjKf4LmRIHBH9pJJM2q+tA47U04Tod6k6rtntDOI8SdmRe2M5c87RfbadWdxhpYHFIWQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64-baseline": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.2.13.tgz", + "integrity": "sha512-bZpIUOvx9np07AmH5MVXGYHWZ40m2vCpNV74fma6sCzBlssJclS2V3BZgO+lLvtUKSqnW3HAyJBGsRF34wPbNw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-linux-aarch64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.2.13.tgz", + "integrity": "sha512-hocSJmblX4CCjP1HpaM64I65erB+CONUCCwKzGGOfLGLobVi+vn/G56UaYWsje1y/Z7WlVaUSgKYVWl7EJ6T9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-aarch64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.2.13.tgz", + "integrity": "sha512-P56m718KXeyu4Vq5fsESFktfu+0Us1jhu/ZzgHYFRYJcm/hjs6AUA/RJtUAifFy5PNAM5IJdrYl3xPsE8Wa+pg==", + "cpu": [ + "aarch64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-1.2.13.tgz", + "integrity": "sha512-pf8+Kn2GLrFKLcb8JSLM6Z147Af6L9GQODpnOHM4gvXQv6E/GwQg47/o+7f1XCfzib3fdzOTJlDPvvO1rnXOTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-baseline": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.2.13.tgz", + "integrity": "sha512-9n1ai2ejEpxEMqpbHQMWFyvacq3MYsB7gh5mxRlFwhNFPCWu/Sv6gyrO+q2vkOYgcEIGhJb6dqJ6L9vBNaL61A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-w5Ob+GM3Ww4yRA6f1N845o6wEvuwHSmipFUGaRaVp4UELrFnIV9G3pmrlBbYHFnWhk13o8Q7H1/4ZphOkCRJmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl-baseline": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.2.13.tgz", + "integrity": "sha512-VI8hVdfqk0QmbAbyrsIdo2O95n3fkbt72E0h3Wu69cHD1iKJqRXG28R8QoHdehoLSJnKVzRTwsUzHp764nefWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-windows-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64/-/bun-windows-x64-1.2.13.tgz", + "integrity": "sha512-sArgbRmT7V3mUdNFaAdUcuJsuS+oeMDZLPWFSg0gtQZpRrURs9nPzEnZMmVCFo4+kPF9Tb5ujQT9uDySh6/qVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64-baseline": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.2.13.tgz", + "integrity": "sha512-Aiezu99fOUJJpzGuylOJryd6w9Syg2TBigHeXV2+RJsouBzvAnIEYIBA94ZspRq1ulD26Wmkk8Ae+jZ4edk9GA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@playwright/test": { - "version": "1.41.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.1.tgz", - "integrity": "sha512-9g8EWTjiQ9yFBXc6HjCWe41msLpxEX0KhmfmPl9RPLJdfzL4F0lg2BdJ91O9azFdl11y1pmpwdjBiSxvqc+btw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright": "1.41.1" + "playwright": "1.52.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "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==", + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz", + "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", - "glob": "^8.0.3", + "fdir": "^6.2.0", "is-reference": "1.2.1", - "magic-string": "^0.30.3" + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" @@ -401,15 +667,15 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "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==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", "is-module": "^1.0.0", "resolve": "^1.22.1" }, @@ -430,6 +696,7 @@ "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "dev": true, + "license": "MIT", "dependencies": { "serialize-javascript": "^6.0.1", "smob": "^1.0.0", @@ -448,14 +715,15 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" @@ -470,169 +738,280 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", - "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", + "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", - "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", + "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", - "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", + "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", - "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", + "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", + "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", + "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", - "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", + "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", + "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", - "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", + "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", - "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", + "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", + "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", + "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", - "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", + "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", + "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", + "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", - "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", + "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", - "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", + "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", - "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", + "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", - "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", + "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", - "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", + "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -643,52 +1022,96 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10.13.0" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "dev": true, + "license": "MIT" }, "node_modules/@ungap/with-resolvers": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@ungap/with-resolvers/-/with-resolvers-0.1.0.tgz", - "integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw==" + "integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw==", + "license": "ISC" + }, + "node_modules/@webreflection/fetch": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@webreflection/fetch/-/fetch-0.1.5.tgz", + "integrity": "sha512-zCcqCJoNLvdeF41asAK71XPlwSPieeRDsE09albBunJEksuYPYNillKNQjf8p5BqSoTKTuKrW3lUm3MNodUC4g==", + "license": "MIT" + }, + "node_modules/@webreflection/idb-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@webreflection/idb-map/-/idb-map-0.3.2.tgz", + "integrity": "sha512-VLBTx6EUYF/dPdLyyjWWKxQmTWnVXTT1YJekrJUmfGxBcqEVL0Ih2EQptNG/JezkTYgJ0uSTb0yAum/THltBvQ==", + "license": "MIT" }, "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 + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@webreflection/toml-j0.4/-/toml-j0.4-1.1.4.tgz", + "integrity": "sha512-mZI7Oig3IFv7zzwnBLTw/GGSu4ZlUY/3WZdOy7FEjEVJMV0xHNlHhfb3mZ9PAaq1qDyixU2Yd2X52wVvPDaO2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webreflection/utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@webreflection/utils/-/utils-0.1.0.tgz", + "integrity": "sha512-PLug+LMwQbtYasHsJ8JykII02c1drRszSNe2tLl9DuMWaP9ARm8sKty0QejNR2q8VPpFq5/iYExsKd5OT7Hx6A==", + "license": "MIT" }, "node_modules/@xterm/addon-fit": { - "version": "0.9.0-beta.1", - "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.9.0-beta.1.tgz", - "integrity": "sha512-HmGRUMMamUpQYuQBF2VP1LJ0xzqF85LMFfpaNu84t1Tsrl1lPKJWtqX9FDZ22Rf5q6bnKdbj44TRVAUHgDRbLA==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", + "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-web-links": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", + "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", "dev": true, + "license": "MIT", "peerDependencies": { - "xterm": "^5.0.0" + "@xterm/xterm": "^5.0.0" } }, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", + "dev": true, + "license": "MIT" + }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -701,15 +1124,23 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/add-promise-listener": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/add-promise-listener/-/add-promise-listener-0.1.3.tgz", + "integrity": "sha512-hQ6IgGJ7NvvlPYbwdekhdVwPb4QzEptNZ5v7B4XRKz7FukUPDuF/v+R5EFHArWmhmq4d+xv0G4/B5bu2GSiz9Q==", + "license": "MIT" + }, "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, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -722,12 +1153,16 @@ } }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -735,6 +1170,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -745,77 +1181,48 @@ "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 + "dev": true, + "license": "Python-2.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 + "dev": true, + "license": "MIT" }, "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" - } + "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==", + "license": "ISC" }, "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 + "dev": true, + "license": "ISC" }, "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, + "license": "MIT", "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.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", "dev": true, "funding": [ { @@ -831,11 +1238,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -848,18 +1256,42 @@ "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 + "dev": true, + "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "node_modules/bun": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/bun/-/bun-1.2.13.tgz", + "integrity": "sha512-EhP1MhFbicqtaRSFCbEZdkcFco8Ov47cNJcB9QmKS8U4cojKHfLU+dQR14lCvLYmtBvGgwv/Lp+9SSver2OPzQ==", + "cpu": [ + "arm64", + "x64", + "aarch64" + ], "dev": true, - "engines": { - "node": ">=6" + "hasInstallScript": true, + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32" + ], + "bin": { + "bun": "bin/bun.exe", + "bunx": "bin/bun.exe" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@oven/bun-darwin-aarch64": "1.2.13", + "@oven/bun-darwin-x64": "1.2.13", + "@oven/bun-darwin-x64-baseline": "1.2.13", + "@oven/bun-linux-aarch64": "1.2.13", + "@oven/bun-linux-aarch64-musl": "1.2.13", + "@oven/bun-linux-x64": "1.2.13", + "@oven/bun-linux-x64-baseline": "1.2.13", + "@oven/bun-linux-x64-musl": "1.2.13", + "@oven/bun-linux-x64-musl-baseline": "1.2.13", + "@oven/bun-windows-x64": "1.2.13", + "@oven/bun-windows-x64-baseline": "1.2.13" } }, "node_modules/callsites": { @@ -867,6 +1299,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -876,6 +1309,7 @@ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", @@ -884,9 +1318,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001578", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001578.tgz", - "integrity": "sha512-J/jkFgsQ3NEl4w2lCoM9ZPxrD+FoBNJ7uJUpGVjIg/j0OwJosWM36EPDv+Yyi0V4twBk9pPmlFS+PLykgEvUmg==", + "version": "1.0.30001717", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz", + "integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==", "dev": true, "funding": [ { @@ -901,13 +1335,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -920,36 +1356,26 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/codedent": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/codedent/-/codedent-0.1.2.tgz", "integrity": "sha512-qEqzcy5viM3UoCN0jYHZeXZoyd4NZQzYFg0kOBj8O1CgoGG9WYYTF+VeQRsN0OSKFjF3G1u4WDUOtOsWEx6N2w==", + "license": "ISC", "dependencies": { "plain-tag": "^0.1.3" } @@ -959,6 +1385,7 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", "dev": true, + "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", @@ -970,17 +1397,14 @@ } }, "node_modules/coincident": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/coincident/-/coincident-1.1.0.tgz", - "integrity": "sha512-FXl7/KToJmtaWWEHOJljbco6NKuM9Hzo249p5gI+lvmxv1JRUCoS14SP195zeEW2WypBfTARGkmnE9MwJ1j0Yg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/coincident/-/coincident-3.0.5.tgz", + "integrity": "sha512-caQv9P+P1keF6QGmVn82StddFu3hnpm/Tox1NxbFJe26m4ad0bSKmnAcQNoVnZNVtnLF5xUv2h1jgsXqoetaiA==", + "license": "MIT", "dependencies": { - "@ungap/structured-clone": "^1.2.0", - "@ungap/with-resolvers": "^0.1.0", - "gc-hook": "^0.2.5", - "proxy-target": "^3.0.1" - }, - "optionalDependencies": { - "ws": "^8.14.2" + "gc-hook": "^0.4.1", + "js-proxy": "^0.5.2", + "next-resolver": "^0.1.2" } }, "node_modules/color-convert": { @@ -988,6 +1412,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -999,19 +1424,22 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -1020,19 +1448,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", "dev": true, + "license": "ISC", "dependencies": { "source-map": "^0.6.1" } @@ -1041,13 +1472,15 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1062,6 +1495,7 @@ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >=14" }, @@ -1074,6 +1508,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -1090,6 +1525,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.14", "source-map": "^0.6.1" @@ -1103,6 +1539,7 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -1115,6 +1552,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -1127,6 +1565,7 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", "dev": true, + "license": "MIT", "dependencies": { "cssnano-preset-default": "^5.2.14", "lilconfig": "^2.0.3", @@ -1148,6 +1587,7 @@ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", "dev": true, + "license": "MIT", "dependencies": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^3.1.0", @@ -1191,6 +1631,7 @@ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -1203,6 +1644,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "^1.1.2" }, @@ -1211,12 +1653,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1231,34 +1674,25 @@ "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 + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "engines": { "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", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -1278,13 +1712,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -1300,6 +1736,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -1310,31 +1747,35 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.635", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.635.tgz", - "integrity": "sha512-iu/2D0zolKU3iDGXXxdOzNf72Jnokn+K1IN6Kk4iV6l1Tr2g/qy+mvmtfAiBwZe5S3aB5r92vp+zSZ69scYRrg==", - "dev": true + "version": "1.5.150", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.150.tgz", + "integrity": "sha512-rOOkP2ZUMx1yL4fCxXQKDHQ8ZXwisb2OycOQVKHgvB3ZI4CvehOd4y2tfnnLDieJ3Zs1RL1Dlp3cMkyIn7nnXA==", + "dev": true, + "license": "ISC" }, "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 + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1344,6 +1785,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1352,122 +1794,120 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "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", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "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" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "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==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -1480,6 +1920,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -1492,6 +1933,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1500,13 +1942,15 @@ "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 + "dev": true, + "license": "MIT" }, "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, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -1515,57 +1959,56 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } + "license": "MIT" }, - "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==", + "node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "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==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, "node_modules/find-up": { @@ -1573,6 +2016,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1585,37 +2029,33 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "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 + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1629,111 +2069,82 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gc-hook": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.2.5.tgz", - "integrity": "sha512-808B9hJ1T7ak4HRYdXgQjDaHexlaUOBuNFuqOnYotxfKjOHTDxAy8r1Oe7LI+KBeb/H6XUBKzuYi626DjxhxIg==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.4.1.tgz", + "integrity": "sha512-uiF+uUftDVLr+VRdudsdsT3/LQYnv2ntwhRH964O7xXDI57Smrek5olv75Wb8Nnz6U+7iVTRXsBlxKcsaDTJTQ==", + "license": "ISC" }, "node_modules/generic-names": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^3.2.0" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, "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/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "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, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=10" + "node": ">=10.13.0" } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "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-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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -1744,19 +2155,22 @@ "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==" + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" }, "node_modules/icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -1765,10 +2179,11 @@ } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -1778,6 +2193,7 @@ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", "dev": true, + "license": "MIT", "dependencies": { "import-from": "^3.0.0" }, @@ -1786,10 +2202,11 @@ } }, "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==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1806,6 +2223,7 @@ "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -1818,6 +2236,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1827,60 +2246,22 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "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", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "builtin-modules": "^3.3.0" + "hasown": "^2.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1891,6 +2272,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1900,6 +2282,7 @@ "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, + "license": "MIT", "engines": { "node": ">=8" } @@ -1909,6 +2292,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1920,31 +2304,15 @@ "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" - } + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "@types/estree": "*" } @@ -1953,13 +2321,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/js-proxy": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/js-proxy/-/js-proxy-0.5.2.tgz", + "integrity": "sha512-gywYozJo2nfzlnYtBZXZCzbcMX8TfEJJtuUcj/uIE6xwqx9UoiOUeZcBb1Gy1IFxs3Tf+1kos8Aiv45P9HAkyQ==", + "license": "MIT", + "dependencies": { + "gc-hook": "^0.4.1", + "proxy-target": "^3.0.2" + } }, "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, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1971,25 +2351,29 @@ "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 + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -1999,6 +2383,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -2012,15 +2397,17 @@ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" } @@ -2030,6 +2417,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -2044,70 +2432,53 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "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", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "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" - } + "license": "MIT" }, - "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==", + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true, + "license": "CC0-1.0" + }, "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, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2116,15 +2487,16 @@ } }, "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 + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -2132,6 +2504,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -2144,28 +2517,31 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "node_modules/next-resolver": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/next-resolver/-/next-resolver-0.1.3.tgz", + "integrity": "sha512-z5KPZ7LERFcc3GZuMlDzTmjfFLM5SeMZFY4kUEuI1oJp9uB+9RtIA6fI8REXcqJ6mid97zR+fMX0jf4YdFihKA==", + "license": "MIT", + "dependencies": { + "@webreflection/utils": "^0.1.0" + } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2178,6 +2554,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -2185,27 +2562,19 @@ "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==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "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" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -2216,6 +2585,7 @@ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -2225,6 +2595,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -2240,6 +2611,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -2255,6 +2627,7 @@ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" @@ -2271,6 +2644,7 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", "dev": true, + "license": "MIT", "dependencies": { "p-finally": "^1.0.0" }, @@ -2283,6 +2657,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -2295,24 +2670,17 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "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, + "license": "MIT", "engines": { "node": ">=8" } @@ -2321,21 +2689,24 @@ "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 + "dev": true, + "license": "MIT" }, "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 + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -2346,6 +2717,7 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2356,72 +2728,64 @@ "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==" + "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==", + "license": "ISC" }, "node_modules/playwright": { - "version": "1.41.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.1.tgz", - "integrity": "sha512-gdZAWG97oUnbBdRL3GuBvX3nDDmUOuqzV/D24dytqlKt+eI5KbwusluZRGljx1YoJKZ2NRPaeWiFTeGZO7SosQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.41.1" + "playwright-core": "1.52.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.41.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.1.tgz", - "integrity": "sha512-/KPO5DzXSMlxSX77wy+HihKGOunh3hqndhqeo/nMxfigiKzogn8kfL0ZBDu0L1RKgan5XHCPmn6zXd2NUJgjhg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", "dev": true, + "license": "Apache-2.0", "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": ">=18" } }, "node_modules/polyscript": { - "version": "0.6.13", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.6.13.tgz", - "integrity": "sha512-VlRLIf6KGqZRVqqiA6eUbepxOe5Sfc2OAirlrzMBM/uzD62+MTUwJsr0CP/pU+u3Gozk15DUYpV2wez3CbCzUQ==", + "version": "0.17.20", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.17.20.tgz", + "integrity": "sha512-aqNHp/IjkYk2t+JDaX4IOE3Xv0yO/SFmXGwzXBJoLTknRttJlALvHf8Kx2b3vyKHs6ZRdaXCVCVDmXEwsQVkkQ==", + "license": "APACHE-2.0", "dependencies": { - "@ungap/structured-clone": "^1.2.0", - "@ungap/with-resolvers": "^0.1.0", + "@webreflection/fetch": "^0.1.5", + "@webreflection/idb-map": "^0.3.2", + "@webreflection/utils": "^0.1.0", "basic-devtools": "^0.1.6", "codedent": "^0.1.2", - "coincident": "^1.1.0", + "coincident": "^3.0.5", + "gc-hook": "^0.4.1", "html-escaper": "^3.0.3", - "proxy-target": "^3.0.1", + "proxy-target": "^3.0.2", "sticky-module": "^0.1.1", "to-json-callback": "^0.1.1" } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { @@ -2437,11 +2801,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -2452,6 +2817,7 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", "dev": true, + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.9", "postcss-value-parser": "^4.2.0" @@ -2465,6 +2831,7 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -2483,6 +2850,7 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -2499,6 +2867,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -2511,6 +2880,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -2523,6 +2893,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -2535,6 +2906,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -2547,6 +2919,7 @@ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, + "license": "MIT", "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" @@ -2576,6 +2949,7 @@ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^5.1.1" @@ -2592,6 +2966,7 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -2610,6 +2985,7 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2625,6 +3001,7 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", "dev": true, + "license": "MIT", "dependencies": { "colord": "^2.9.1", "cssnano-utils": "^3.1.0", @@ -2642,6 +3019,7 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "cssnano-utils": "^3.1.0", @@ -2659,6 +3037,7 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", "dev": true, + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.5" }, @@ -2674,6 +3053,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", "integrity": "sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==", "dev": true, + "license": "MIT", "dependencies": { "generic-names": "^4.0.0", "icss-replace-symbols": "^1.1.0", @@ -2689,10 +3069,11 @@ } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -2701,13 +3082,14 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -2717,13 +3099,28 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-scope": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.0.tgz", - "integrity": "sha512-SaIbK8XW+MZbd0xHPf7kdfA/3eOt7vxJ72IRecn3EzuZVLr1r0orzf0MX/pN8m+NMDoo6X/SQd8oeKqGZd8PXg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, + "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -2732,11 +3129,26 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-values": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -2752,6 +3164,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", "dev": true, + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -2764,6 +3177,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2779,6 +3193,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2794,6 +3209,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2809,6 +3225,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2824,6 +3241,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2839,6 +3257,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -2855,6 +3274,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", "dev": true, + "license": "MIT", "dependencies": { "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" @@ -2871,6 +3291,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2886,6 +3307,7 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", "dev": true, + "license": "MIT", "dependencies": { "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" @@ -2902,6 +3324,7 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -2918,6 +3341,7 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -2929,10 +3353,11 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.15", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", - "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2946,6 +3371,7 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^2.7.0" @@ -2962,6 +3388,7 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.5" }, @@ -2976,13 +3403,15 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -2992,78 +3421,68 @@ "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", "integrity": "sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12" } }, "node_modules/proxy-target": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/proxy-target/-/proxy-target-3.0.1.tgz", - "integrity": "sha512-EGskR5UV9bsY3eFXBFJqq/rsDUXw/WAjeuW5YuyYaxd+0F2zgMpuZ/l5NQtju4FBHKIJnBXNGEptGqyisUgdcg==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/proxy-target/-/proxy-target-3.0.2.tgz", + "integrity": "sha512-FFE1XNwXX/FNC3/P8HiKaJSy/Qk68RitG/QEcLy/bVnTAPlgTAWPZKh0pARLAnpfXQPKyalBhk009NRTgsk8vQ==", + "license": "MIT" }, "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, + "license": "MIT", "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", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "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==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, + "license": "MIT", "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3073,62 +3492,19 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/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/rollup": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", - "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", + "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -3138,19 +3514,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.6", - "@rollup/rollup-android-arm64": "4.9.6", - "@rollup/rollup-darwin-arm64": "4.9.6", - "@rollup/rollup-darwin-x64": "4.9.6", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", - "@rollup/rollup-linux-arm64-gnu": "4.9.6", - "@rollup/rollup-linux-arm64-musl": "4.9.6", - "@rollup/rollup-linux-riscv64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-musl": "4.9.6", - "@rollup/rollup-win32-arm64-msvc": "4.9.6", - "@rollup/rollup-win32-ia32-msvc": "4.9.6", - "@rollup/rollup-win32-x64-msvc": "4.9.6", + "@rollup/rollup-android-arm-eabi": "4.41.0", + "@rollup/rollup-android-arm64": "4.41.0", + "@rollup/rollup-darwin-arm64": "4.41.0", + "@rollup/rollup-darwin-x64": "4.41.0", + "@rollup/rollup-freebsd-arm64": "4.41.0", + "@rollup/rollup-freebsd-x64": "4.41.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", + "@rollup/rollup-linux-arm-musleabihf": "4.41.0", + "@rollup/rollup-linux-arm64-gnu": "4.41.0", + "@rollup/rollup-linux-arm64-musl": "4.41.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", + "@rollup/rollup-linux-riscv64-gnu": "4.41.0", + "@rollup/rollup-linux-riscv64-musl": "4.41.0", + "@rollup/rollup-linux-s390x-gnu": "4.41.0", + "@rollup/rollup-linux-x64-gnu": "4.41.0", + "@rollup/rollup-linux-x64-musl": "4.41.0", + "@rollup/rollup-win32-arm64-msvc": "4.41.0", + "@rollup/rollup-win32-ia32-msvc": "4.41.0", + "@rollup/rollup-win32-x64-msvc": "4.41.0", "fsevents": "~2.3.2" } }, @@ -3159,6 +3542,7 @@ "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.2.tgz", "integrity": "sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "concat-with-sourcemaps": "^1.1.0", @@ -3186,6 +3570,7 @@ "resolved": "https://registry.npmjs.org/rollup-plugin-string/-/rollup-plugin-string-3.0.0.tgz", "integrity": "sha512-vqyzgn9QefAgeKi+Y4A7jETeIAU1zQmS6VotH6bzm/zmUQEnYkpIGRaOBPY41oiWYV4JyBoGAaBjYMYuv+6wVw==", "dev": true, + "license": "MIT", "dependencies": { "rollup-pluginutils": "^2.4.1" } @@ -3195,6 +3580,7 @@ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", "dev": true, + "license": "MIT", "dependencies": { "estree-walker": "^0.6.1" } @@ -3203,30 +3589,8 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", "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" - } + "license": "MIT" }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -3246,19 +3610,22 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-identifier": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -3268,6 +3635,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3280,30 +3648,34 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" }, "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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "peer": true, "engines": { "node": ">=0.10.0" @@ -3314,6 +3686,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -3324,16 +3697,15 @@ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/static-handler": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/static-handler/-/static-handler-0.4.3.tgz", - "integrity": "sha512-rHi6vtxW/kjC+L18cRVAICAp/ymTjyvZHCPXIrejrlVrRrNxrVGk9FNCg+rC9wM7SpZ9euyjsr7tNVtqpA2iLA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/static-handler/-/static-handler-0.5.3.tgz", + "integrity": "sha512-VSg7+Dd6HkgwjdJ9nRN2mmBZkP/u6ICA7RQuLqBFi3KdzWe9BEQXhMiDw3A8TYcllshIVn5nNP5fRcicOPZhzQ==", "dev": true, - "dependencies": { - "mime-types": "^2.1.35" - }, + "license": "ISC", "bin": { "static-handler": "static-handler.cjs" }, @@ -3344,38 +3716,48 @@ "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==" + "integrity": "sha512-IuYgnyIMUx/m6rtu14l/LR2MaqOLtpXcWkxPmtPsiScRHEo+S4Tojk+DWFHOncSdFX/OsoLOM4+T92yOmI1AMw==", + "license": "ISC" }, "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 + "dev": true, + "license": "CC0-1.0" }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "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==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-json-comments": { @@ -3383,6 +3765,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3394,19 +3777,22 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/style-mod": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz", - "integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==", - "dev": true + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "dev": true, + "license": "MIT" }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" @@ -3423,6 +3809,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3435,6 +3822,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3447,6 +3835,7 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dev": true, + "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -3464,10 +3853,11 @@ } }, "node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -3485,36 +3875,21 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "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 + "dev": true, + "license": "MIT" }, "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" - } + "integrity": "sha512-BzOeinTT3NjE+FJ2iCvWB8HvyuyBzoH3WlSnJ+AYVC4tlePyZWSYdkQIFOARWiq0t35/XhmI0uQsFiUsRksRqg==", + "license": "ISC" }, "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, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -3525,25 +3900,15 @@ "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" - } + "integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A==", + "license": "ISC" }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3553,9 +3918,9 @@ } }, "node_modules/update-browserslist-db": { - "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==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -3571,9 +3936,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -3587,6 +3953,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -3595,19 +3962,22 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -3618,49 +3988,72 @@ "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.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "optional": true, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=0.10.0" + } + }, + "node_modules/xterm-readline": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/xterm-readline/-/xterm-readline-1.1.2.tgz", + "integrity": "sha512-1+W2nVuQvCYz9OUYwFBiolrSQUui51aDDyacKXt4PuxeBHqzvabQEJ2kwdBDzsmOjz5BwlDTAjJmYpH2OGqLFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "@xterm/xterm": "^5.5.0" } }, - "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/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, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "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==", + "node_modules/xterm-readline/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, + "license": "MIT" + }, + "node_modules/xterm-readline/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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/xterm-readline/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, + "license": "MIT", "dependencies": { - "string-width": "^4.0.0" + "ansi-regex": "^5.0.1" }, - "peerDependencies": { - "xterm": "^5.0.0" + "engines": { + "node": ">=8" } }, "node_modules/yaml": { @@ -3668,6 +4061,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 6" } @@ -3677,6 +4071,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/core/package.json b/core/package.json new file mode 100644 index 00000000000..e551ef25ad7 --- /dev/null +++ b/core/package.json @@ -0,0 +1,114 @@ +{ + "name": "@pyscript/core", + "version": "0.6.53", + "type": "module", + "description": "PyScript", + "module": "./index.js", + "unpkg": "./index.js", + "jsdelivr": "./jsdelivr.js", + "browser": "./index.js", + "main": "./index.js", + "engines": { + "node": ">=20" + }, + "files": [ + "./dist/", + "./src/", + "./types/", + "./index.js", + "./jsdelivr.js", + "LICENSE", + "README.md" + ], + "exports": { + ".": { + "types": "./types/core.d.ts", + "import": "./src/core.js" + }, + "./js": { + "types": "./types/core.d.ts", + "import": "./dist/core.js" + }, + "./css": { + "import": "./dist/core.css" + }, + "./storage": { + "import": "./dist/storage.js" + }, + "./service-worker": { + "import": "./dist/service-worker.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "server": "echo \"➡️ TESTS @ $(tput bold)http://localhost:8080/tests/$(tput sgr0)\"; npx static-handler --coi .", + "build": "export ESLINT_USE_FLAT_CONFIG=true;npm run build:3rd-party && npm run build:stdlib && npm run build:plugins && npm run build:core && npm run build:tests-index && if [ -z \"$NO_MIN\" ]; then eslint src/ && npm run ts && npm run test:integration; fi", + "build:core": "rm -rf dist && rollup --config rollup/core.config.js && cp src/3rd-party/*.css dist/", + "build:flatted": "node rollup/flatted.cjs", + "build:plugins": "node rollup/plugins.cjs", + "build:stdlib": "node rollup/stdlib.cjs", + "build:3rd-party": "node rollup/3rd-party.cjs", + "build:tests-index": "node rollup/build_test_index.cjs", + "clean:3rd-party": "rm src/3rd-party/*.js && rm src/3rd-party/*.css", + "test:integration": "npm run test:ws; static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; (playwright test tests/js_tests.spec.js && playwright test tests/py_tests.main.spec.js && playwright test tests/py_tests.worker.spec.js) || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE", + "test:ws": "bun tests/javascript/ws/index.js & playwright test tests/javascript/ws/index.spec.js", + "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 cat $js | brotli > ._; echo -e \"\\033[2m$js:\\033[0m $(du -h --apparent-size ._ | sed -e 's/[[:space:]]*._//')\"; rm ._; done", + "ts": "rm -rf types && tsc -p .", + "zip": "zip -r dist.zip ./dist" + }, + "keywords": [ + "pyscript", + "core" + ], + "author": "Anaconda Inc.", + "license": "APACHE-2.0", + "dependencies": { + "@ungap/with-resolvers": "^0.1.0", + "@webreflection/idb-map": "^0.3.2", + "@webreflection/utils": "^0.1.0", + "add-promise-listener": "^0.1.3", + "basic-devtools": "^0.1.6", + "polyscript": "^0.17.20", + "sticky-module": "^0.1.1", + "to-json-callback": "^0.1.1", + "type-checked-collections": "^0.1.7" + }, + "devDependencies": { + "@codemirror/commands": "^6.8.1", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/language": "^6.11.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.8", + "@playwright/test": "^1.52.0", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", + "@rollup/plugin-terser": "^0.4.4", + "@webreflection/toml-j0.4": "^1.1.4", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/xterm": "^5.5.0", + "bun": "^1.2.13", + "chokidar": "^4.0.3", + "codedent": "^0.1.2", + "codemirror": "^6.0.1", + "eslint": "^9.27.0", + "flatted": "^3.3.3", + "rollup": "^4.41.0", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-string": "^3.0.0", + "static-handler": "^0.5.3", + "string-width": "^7.2.0", + "typescript": "^5.8.3", + "xterm-readline": "^1.1.2" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pyscript/pyscript.git" + }, + "bugs": { + "url": "https://github.com/pyscript/pyscript/issues" + }, + "homepage": "https://github.com/pyscript/pyscript#readme" +} diff --git a/pyscript.core/rollup/3rd-party.cjs b/core/rollup/3rd-party.cjs similarity index 89% rename from pyscript.core/rollup/3rd-party.cjs rename to core/rollup/3rd-party.cjs index 28c34beb9c1..784d54c55c7 100644 --- a/pyscript.core/rollup/3rd-party.cjs +++ b/core/rollup/3rd-party.cjs @@ -46,14 +46,17 @@ const modules = { "toml.js": join(node_modules, "@webreflection", "toml-j0.4", "toml.js"), // xterm - "xterm.js": resolve("xterm"), + "xterm.js": resolve("@xterm/xterm"), "xterm-readline.js": resolve("xterm-readline"), "xterm_addon-fit.js": fetch(`${CDN}/@xterm/addon-fit/+esm`).then((b) => b.text(), ), - "xterm.css": fetch(`${CDN}/xterm@${v("xterm")}/css/xterm.min.css`).then( - (b) => b.text(), - ), + "xterm_addon-web-links.js": fetch( + `${CDN}/@xterm/addon-web-links/+esm`, + ).then((b) => b.text()), + "xterm.css": fetch( + `${CDN}/@xterm/xterm@${v("@xterm/xterm")}/css/xterm.min.css`, + ).then((b) => b.text()), // codemirror "codemirror.js": reBundle("codemirror"), diff --git a/core/rollup/build_test_index.cjs b/core/rollup/build_test_index.cjs new file mode 100644 index 00000000000..e35cd3aff00 --- /dev/null +++ b/core/rollup/build_test_index.cjs @@ -0,0 +1,73 @@ +const { join } = require("node:path"); +const { lstatSync, readdirSync, writeFileSync } = require("node:fs"); + +// folders to not consider while crawling +const EXCLUDE_DIR = new Set(["ws"]); + +const TEST_DIR = join(__dirname, "..", "tests"); + +const TEST_INDEX = join(TEST_DIR, "index.html"); + +const crawl = (path, tree = {}) => { + for (const file of readdirSync(path)) { + const current = join(path, file); + if (current === TEST_INDEX) continue; + if (lstatSync(current).isDirectory()) { + if (EXCLUDE_DIR.has(file)) continue; + const sub = {}; + tree[file] = sub; + crawl(current, sub); + if (!Reflect.ownKeys(sub).length) { + delete tree[file]; + } + } else if (file.endsWith(".html")) { + const name = file === "index.html" ? "." : file.slice(0, -5); + tree[name] = current.replace(TEST_DIR, ""); + } + } + return tree; +}; + +const createList = (tree) => { + const ul = [""); + return ul.join(""); +}; + +writeFileSync( + TEST_INDEX, + ` + + + + + PyScript tests + + + ${createList(crawl(TEST_DIR))} + +`, +); diff --git a/pyscript.core/rollup/core.config.js b/core/rollup/core.config.js similarity index 63% rename from pyscript.core/rollup/core.config.js rename to core/rollup/core.config.js index 16dc822e8c3..0b0933f5cf5 100644 --- a/pyscript.core/rollup/core.config.js +++ b/core/rollup/core.config.js @@ -40,4 +40,28 @@ export default [ warn(warning); }, }, + { + input: "./src/storage.js", + plugins: plugins.concat( + process.env.NO_MIN + ? [nodeResolve(), commonjs()] + : [nodeResolve(), commonjs(), terser()], + ), + output: { + esModule: true, + dir: "./dist", + sourcemap: true, + }, + }, + { + input: "./src/service-worker.js", + plugins: plugins.concat( + process.env.NO_MIN + ? [nodeResolve(), commonjs()] + : [nodeResolve(), commonjs(), terser()], + ), + output: { + file: "./dist/service-worker.js", + }, + }, ]; diff --git a/core/rollup/flatted.cjs b/core/rollup/flatted.cjs new file mode 100644 index 00000000000..22ae1d299a4 --- /dev/null +++ b/core/rollup/flatted.cjs @@ -0,0 +1,17 @@ +const { writeFileSync, readFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const flatted = "# https://www.npmjs.com/package/flatted\n\n"; +const source = join( + __dirname, + "..", + "node_modules", + "flatted", + "python", + "flatted.py", +); +const dest = join(__dirname, "..", "src", "stdlib", "pyscript", "flatted.py"); + +const clear = (str) => String(str).replace(/^#.*/gm, "").trimStart(); + +writeFileSync(dest, flatted + clear(readFileSync(source))); diff --git a/pyscript.core/rollup/plugins.cjs b/core/rollup/plugins.cjs similarity index 80% rename from pyscript.core/rollup/plugins.cjs rename to core/rollup/plugins.cjs index 22572b08ff1..2f8596de751 100644 --- a/pyscript.core/rollup/plugins.cjs +++ b/core/rollup/plugins.cjs @@ -13,7 +13,12 @@ for (const file of readdirSync(join(__dirname, "..", "src", "plugins"))) { 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}),`, + // ⚠️ THIS HAS TO BE LIKE THIS or prettier changes it every single time + ` ${key}: () => + import( + /* webpackIgnore: true */ + ${value} + ),`, ); } } diff --git a/core/rollup/stdlib.cjs b/core/rollup/stdlib.cjs new file mode 100644 index 00000000000..9009cbdca88 --- /dev/null +++ b/core/rollup/stdlib.cjs @@ -0,0 +1,66 @@ +const { + readdirSync, + readFileSync, + statSync, + writeFileSync, +} = require("node:fs"); + +const { spawnSync } = require("node:child_process"); + +const { join } = require("node:path"); + +const dedent = require("codedent"); + +const crawl = (path, json) => { + for (const file of readdirSync(path)) { + const full = join(path, file); + if (/\.py$/.test(file)) { + if (process.env.NO_MIN) json[file] = readFileSync(full).toString(); + else { + try { + const { + output: [error, result], + } = spawnSync("pyminify", [ + "--remove-literal-statements", + full, + ]); + if (error) { + console.error(error); + process.exit(1); + } + json[file] = result.toString(); + } catch (error) { + console.error(error); + console.log( + dedent(` + \x1b[1m⚠️ is your env activated?\x1b[0m + \x1b[2mYou need a Python env to run \x1b[0mpyminify\x1b[2m.\x1b[0m + \x1b[2mTo do so, you can try the following:\x1b[0m + python -m venv env + source env/bin/activate + pip install --upgrade pip + pip install --ignore-requires-python python-minifier + pip install setuptools + \x1b[2mand you can then try \x1b[0mnpm run build\x1b[2m again.\x1b[0m + `), + ); + process.exit(1); + } + } + } 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/core/src/3rd-party-licenses/codemirror.license.txt b/core/src/3rd-party-licenses/codemirror.license.txt new file mode 100644 index 00000000000..d69b9ac5e1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/codemirror_commands.license.txt b/core/src/3rd-party-licenses/codemirror_commands.license.txt new file mode 100644 index 00000000000..4bd5334ad1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror_commands.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/codemirror_lang-python.license.txt b/core/src/3rd-party-licenses/codemirror_lang-python.license.txt new file mode 100644 index 00000000000..4bd5334ad1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror_lang-python.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/codemirror_language.license.txt b/core/src/3rd-party-licenses/codemirror_language.license.txt new file mode 100644 index 00000000000..4bd5334ad1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror_language.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/codemirror_state.license.txt b/core/src/3rd-party-licenses/codemirror_state.license.txt new file mode 100644 index 00000000000..4bd5334ad1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror_state.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/codemirror_view.license.txt b/core/src/3rd-party-licenses/codemirror_view.license.txt new file mode 100644 index 00000000000..4bd5334ad1a --- /dev/null +++ b/core/src/3rd-party-licenses/codemirror_view.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/toml.license.txt b/core/src/3rd-party-licenses/toml.license.txt new file mode 100644 index 00000000000..62b9b39f687 --- /dev/null +++ b/core/src/3rd-party-licenses/toml.license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Jak Wings + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/core/src/3rd-party-licenses/xterm-readline.license.txt b/core/src/3rd-party-licenses/xterm-readline.license.txt new file mode 100644 index 00000000000..dffe82aba51 --- /dev/null +++ b/core/src/3rd-party-licenses/xterm-readline.license.txt @@ -0,0 +1,25 @@ +Copyright 2021 Erik Bremen + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/xterm.license.txt b/core/src/3rd-party-licenses/xterm.license.txt new file mode 100644 index 00000000000..4472336c9f3 --- /dev/null +++ b/core/src/3rd-party-licenses/xterm.license.txt @@ -0,0 +1,21 @@ +Copyright (c) 2017-2019, The xterm.js authors (https://github.com/xtermjs/xterm.js) +Copyright (c) 2014-2016, SourceLair Private Company (https://www.sourcelair.com) +Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/xterm_addon-fit.license.txt b/core/src/3rd-party-licenses/xterm_addon-fit.license.txt new file mode 100644 index 00000000000..1c0bbe0f368 --- /dev/null +++ b/core/src/3rd-party-licenses/xterm_addon-fit.license.txt @@ -0,0 +1,19 @@ +Copyright (c) 2019, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/core/src/3rd-party-licenses/xterm_addon-web-links.lixense.txt b/core/src/3rd-party-licenses/xterm_addon-web-links.lixense.txt new file mode 100644 index 00000000000..1de619d1e8e --- /dev/null +++ b/core/src/3rd-party-licenses/xterm_addon-web-links.lixense.txt @@ -0,0 +1,19 @@ +Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pyscript.core/src/3rd-party/README.md b/core/src/3rd-party/README.md similarity index 83% rename from pyscript.core/src/3rd-party/README.md rename to core/src/3rd-party/README.md index 93cc7fe1a3e..45b1320432f 100644 --- a/pyscript.core/src/3rd-party/README.md +++ b/core/src/3rd-party/README.md @@ -5,3 +5,7 @@ This folder contains artifacts created via [3rd-party.cjs](../../rollup/3rd-part 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. + +## Licenses + +All licenses provided by 3rd-party authors can be found in [3rd-party-licenses](../3rd-party-licenses/) folder. diff --git a/pyscript.core/types/3rd-party/codemirror.d.ts b/core/src/3rd-party/codemirror.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror.d.ts rename to core/src/3rd-party/codemirror.js diff --git a/pyscript.core/types/3rd-party/codemirror_commands.d.ts b/core/src/3rd-party/codemirror_commands.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror_commands.d.ts rename to core/src/3rd-party/codemirror_commands.js diff --git a/pyscript.core/types/3rd-party/codemirror_lang-python.d.ts b/core/src/3rd-party/codemirror_lang-python.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror_lang-python.d.ts rename to core/src/3rd-party/codemirror_lang-python.js diff --git a/pyscript.core/types/3rd-party/codemirror_language.d.ts b/core/src/3rd-party/codemirror_language.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror_language.d.ts rename to core/src/3rd-party/codemirror_language.js diff --git a/pyscript.core/types/3rd-party/codemirror_state.d.ts b/core/src/3rd-party/codemirror_state.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror_state.d.ts rename to core/src/3rd-party/codemirror_state.js diff --git a/pyscript.core/types/3rd-party/codemirror_view.d.ts b/core/src/3rd-party/codemirror_view.js similarity index 100% rename from pyscript.core/types/3rd-party/codemirror_view.d.ts rename to core/src/3rd-party/codemirror_view.js diff --git a/core/src/3rd-party/toml.js b/core/src/3rd-party/toml.js new file mode 100644 index 00000000000..8c635be81b2 --- /dev/null +++ b/core/src/3rd-party/toml.js @@ -0,0 +1,3 @@ +const{SyntaxError:r,parse:t}=function(){function r(t,e,n,u){this.message=t,this.expected=e,this.found=n,this.location=u,this.name="SyntaxError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,r)}return function(r,t){function e(){this.constructor=r}e.prototype=t.prototype,r.prototype=new e}(r,Error),r.buildMessage=function(r,t){var e={literal:function(r){return'"'+u(r.text)+'"'},class:function(r){var t,e="";for(t=0;t0){for(t=1,n=1;t20||20===t.length&&t>n)&&(e=!0)}else{"+"===t[0]&&(t=t.substr(1));var u="9223372036854775807";(t.length>19||19===t.length&&t>u)&&(e=!0)}return e&&Dt(r+" is not a 64-bit signed integer."),t=parseInt(t,10),o(t)||Dt(r+" is not a 64-bit signed integer."),{type:"Integer",value:t}},kr="+",Br=jt("+",!1),Jr="-",Pr=jt("-",!1),Vr=/^[0-9]/,Wr=Ht([["0","9"]],!1,!1),qr="T",Gr=jt("T",!1),Kr=function(){var r=Tt(),t=new Date(r);return o(t.getTime())||Dt("Date-time "+r+" is invalid. It does not conform to RFC 3339 or this is a browser-specific problem."),{type:"DateTime",value:t}},Lr=Mt("FullDate (YYYY-mm-dd)"),Xr=":",$r=jt(":",!1),rt=Mt("Hour (HH)"),tt=Mt("Minute (MM)"),et=Mt("Second (SS)"),nt=Mt("TimeOffset (Z or +/-HH:MM)"),ut="Z",ot=jt("Z",!1),at="[",it=jt("[",!1),ct=",",ft=jt(",",!1),st="]",lt=jt("]",!1),ht=function(r){for(var t={type:"Array",value:r?r[0]:[]},e=0,n=t.value,u=n.length;eFt&&(Ft=mt,wt=[]),wt.push(r))}function Zt(){var r,e,n,u,o,a,i,c;for(r=mt,e=[],(n=Rt())===p&&(n=It())===p&&(n=Ut());n!==p;)e.push(n),(n=Rt())===p&&(n=It())===p&&(n=Ut());if(e!==p){if(n=mt,u=function(){var r,e;r=mt,e=function(){var r,e,n,u;r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it));e!==p&&(n=fe())!==p?(93===t.charCodeAt(mt)?(u=st,mt++):(u=p,0===Et&&Nt(lt)),u!==p?(xt=r,r=e=bt(n)):(mt=r,r=p)):(mt=r,r=p);return r}(),e!==p&&(xt=r,e=A(e));r=e,r===p&&(r=mt,(e=fe())!==p&&(xt=r,e=C(e)),(r=e)===p&&(r=mt,(e=zt())!==p&&(xt=r,e=b(e)),r=e));return r}(),u!==p){for(o=[],(a=Rt())===p&&(a=Ut());a!==p;)o.push(a),(a=Rt())===p&&(a=Ut());o!==p?(a=mt,(i=It())!==p&&(c=Zt())!==p?a=i=[i,c]:(mt=a,a=p),a===p&&(a=null),a!==p?n=u=[u,o,a]:(mt=n,n=p)):(mt=n,n=p)}else mt=n,n=p;n===p&&(n=null),n!==p?(xt=r,r=e=g()):(mt=r,r=p)}else mt=r,r=p;return r}function It(){var r;return Et++,10===t.charCodeAt(mt)?(r=m,mt++):(r=p,0===Et&&Nt(x)),r===p&&(t.substr(mt,2)===S?(r=S,mt+=2):(r=p,0===Et&&Nt(F))),Et--,r===p&&0===Et&&Nt(y),r}function Rt(){var r;return Et++,E.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(T)),Et--,r===p&&0===Et&&Nt(w),r}function Ut(){var r,e,n,u,o,a;if(Et++,r=mt,35===t.charCodeAt(mt)?(e=j,mt++):(e=p,0===Et&&Nt(H)),e!==p){for(n=[],u=mt,o=mt,Et++,a=It(),Et--,a===p?o=void 0:(mt=o,o=p),o!==p?(t.length>mt?(a=t.charAt(mt),mt++):(a=p,0===Et&&Nt(M)),a!==p?u=o=[o,a]:(mt=u,u=p)):(mt=u,u=p);u!==p;)n.push(u),u=mt,o=mt,Et++,a=It(),Et--,a===p?o=void 0:(mt=o,o=p),o!==p?(t.length>mt?(a=t.charAt(mt),mt++):(a=p,0===Et&&Nt(M)),a!==p?u=o=[o,a]:(mt=u,u=p)):(mt=u,u=p);n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return Et--,r===p&&(e=p,0===Et&&Nt(D)),r}function zt(){var r,e,n,u,o,a;if(r=mt,(e=Qt())!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p)if(61===t.charCodeAt(mt)?(u=O,mt++):(u=p,0===Et&&Nt(_)),u!==p){for(o=[],a=Rt();a!==p;)o.push(a),a=Rt();o!==p&&(a=Vt())!==p?(xt=r,r=e=N(e,a)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p}else mt=r,r=p;return r}function Qt(){var r;return(r=function(){var r,t,e;if(r=mt,t=[],(e=Yt())!==p)for(;e!==p;)t.push(e),e=Yt();else t=p;t!==p&&(xt=r,t=Z());return r=t,r}())===p&&(r=function(){var r,t,e;if(r=mt,kt()!==p){if(t=[],(e=Wt())!==p)for(;e!==p;)t.push(e),e=Wt();else t=p;t!==p&&(e=kt())!==p?(xt=r,r=z(t)):(mt=r,r=p)}else mt=r,r=p;return r}()),r}function Yt(){var r;return Et++,R.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(U)),Et--,r===p&&0===Et&&Nt(I),r}function kt(){var r;return Et++,34===t.charCodeAt(mt)?(r=Y,mt++):(r=p,0===Et&&Nt(k)),Et--,r===p&&0===Et&&Nt(Q),r}function Bt(){var r;return Et++,39===t.charCodeAt(mt)?(r=J,mt++):(r=p,0===Et&&Nt(P)),Et--,r===p&&0===Et&&Nt(B),r}function Jt(){var r;return Et++,t.substr(mt,3)===W?(r=W,mt+=3):(r=p,0===Et&&Nt(q)),Et--,r===p&&0===Et&&Nt(V),r}function Pt(){var r;return Et++,t.substr(mt,3)===K?(r=K,mt+=3):(r=p,0===Et&&Nt(L)),Et--,r===p&&0===Et&&Nt(G),r}function Vt(){var r;return(r=function(){var r;r=function(){var r,t,e,n;if(r=mt,Jt()!==p)if((t=It())===p&&(t=null),t!==p){for(e=[],n=Xt();n!==p;)e.push(n),n=Xt();e!==p&&(n=Jt())!==p?(xt=r,r=X(e)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}(),r===p&&(r=function(){var r,t,e;if(r=mt,kt()!==p){for(t=[],e=Wt();e!==p;)t.push(e),e=Wt();t!==p&&(e=kt())!==p?(xt=r,r=X(t)):(mt=r,r=p)}else mt=r,r=p;return r}())===p&&(r=function(){var r,t,e,n;if(r=mt,Pt()!==p)if((t=It())===p&&(t=null),t!==p){for(e=[],n=$t();n!==p;)e.push(n),n=$t();e!==p&&(n=Pt())!==p?(xt=r,r=X(e)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}())===p&&(r=function(){var r,t,e;if(r=mt,Bt()!==p){for(t=[],e=Lt();e!==p;)t.push(e),e=Lt();t!==p&&(e=Bt())!==p?(xt=r,r=Ar()):(mt=r,r=p)}else mt=r,r=p;return r}());return r}())===p&&(r=function(){var r,e;r=mt,t.substr(mt,4)===Er?(e=Er,mt+=4):(e=p,0===Et&&Nt(Tr));e!==p&&(xt=r,e=Dr());r=e,r===p&&(r=mt,t.substr(mt,5)===jr?(e=jr,mt+=5):(e=p,0===Et&&Nt(Hr)),e!==p&&(xt=r,e=Mr()),r=e);return r}())===p&&(r=function(){var r,e,n,u;r=mt,e=function(){var r,e,n,u,o,a;Et++,r=mt,e=function(){var r,t,e,n,u;r=mt,(t=ue())!==p&&(e=ue())!==p&&(n=ue())!==p&&(u=ue())!==p?r=t=[t,e,n,u]:(mt=r,r=p);return r}(),e!==p?(45===t.charCodeAt(mt)?(n=Jr,mt++):(n=p,0===Et&&Nt(Pr)),n!==p?(u=function(){var r,t,e;r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);return r}(),u!==p?(45===t.charCodeAt(mt)?(o=Jr,mt++):(o=p,0===Et&&Nt(Pr)),o!==p?(a=function(){var r,t,e;r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);return r}(),a!==p?r=e=[e,n,u,o,a]:(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt(Lr));return r}(),e!==p?(84===t.charCodeAt(mt)?(n=qr,mt++):(n=p,0===Et&&Nt(Gr)),n!==p?(u=function(){var r,e,n;r=mt,e=function(){var r,e,n,u,o,a,i;r=mt,e=oe(),e!==p?(58===t.charCodeAt(mt)?(n=Xr,mt++):(n=p,0===Et&&Nt($r)),n!==p&&(u=ae())!==p?(58===t.charCodeAt(mt)?(o=Xr,mt++):(o=p,0===Et&&Nt($r)),o!==p?(a=function(){var r,t,e;Et++,r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(et));return r}(),a!==p?(i=function(){var r,e,n,u;r=mt,46===t.charCodeAt(mt)?(e=_r,mt++):(e=p,0===Et&&Nt(Nr));if(e!==p){if(n=[],(u=ue())!==p)for(;u!==p;)n.push(u),u=ue();else n=p;n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return r}(),i===p&&(i=null),i!==p?r=e=[e,n,u,o,a,i]:(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);return r}(),e!==p?(n=function(){var r,e,n,u,o;Et++,90===t.charCodeAt(mt)?(r=ut,mt++):(r=p,0===Et&&Nt(ot));r===p&&(r=mt,(e=ee())!==p&&(n=oe())!==p?(58===t.charCodeAt(mt)?(u=Xr,mt++):(u=p,0===Et&&Nt($r)),u!==p&&(o=ae())!==p?r=e=[e,n,u,o]:(mt=r,r=p)):(mt=r,r=p));Et--,r===p&&(e=p,0===Et&&Nt(nt));return r}(),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);return r}(),u!==p?(xt=r,r=e=Kr()):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);return r}())===p&&(r=function(){var r,e,n,u;r=mt,te()!==p?(e=mt,n=function(){var r,e,n,u,o,a,i;r=mt,46===t.charCodeAt(mt)?(e=_r,mt++):(e=p,0===Et&&Nt(Nr));if(e!==p)if((n=ue())!==p){for(u=[],o=mt,95===t.charCodeAt(mt)?(a=Zr,mt++):(a=p,0===Et&&Nt(Ir)),a===p&&(a=null),a!==p&&(i=ue())!==p?o=a=[a,i]:(mt=o,o=p);o!==p;)u.push(o),o=mt,95===t.charCodeAt(mt)?(a=Zr,mt++):(a=p,0===Et&&Nt(Ir)),a===p&&(a=null),a!==p&&(i=ue())!==p?o=a=[a,i]:(mt=o,o=p);u!==p?r=e=[e,n,u]:(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}(),n!==p?((u=re())===p&&(u=null),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p),e===p&&(e=re()),e!==p?(xt=r,r=Or()):(mt=r,r=p)):(mt=r,r=p);return r}())===p&&(r=te())===p&&(r=function(){var r,e,n,u,o,a,i,c,f,s;r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it));if(e!==p){for(n=[],u=ce();u!==p;)n.push(u),u=ce();if(n!==p){if(u=mt,(o=ie())!==p){for(a=[],i=ce();i!==p;)a.push(i),i=ce();if(a!==p){if(i=mt,44===t.charCodeAt(mt)?(c=ct,mt++):(c=p,0===Et&&Nt(ft)),c!==p){for(f=[],s=ce();s!==p;)f.push(s),s=ce();f!==p?i=c=[c,f]:(mt=i,i=p)}else mt=i,i=p;i===p&&(i=null),i!==p?u=o=[o,a,i]:(mt=u,u=p)}else mt=u,u=p}else mt=u,u=p;u===p&&(u=null),u!==p?(93===t.charCodeAt(mt)?(o=st,mt++):(o=p,0===Et&&Nt(lt)),o!==p?(xt=r,r=e=ht(u)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;return r}())===p&&(r=function(){var r,e,n,u,o,a,i,c,f,s,l;r=mt,123===t.charCodeAt(mt)?(e=vt,mt++):(e=p,0===Et&&Nt(dt));if(e!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p){if(u=mt,(o=zt())!==p){for(a=[],i=mt,c=[],f=Rt();f!==p;)c.push(f),f=Rt();if(c!==p)if(44===t.charCodeAt(mt)?(f=ct,mt++):(f=p,0===Et&&Nt(ft)),f!==p){for(s=[],l=Rt();l!==p;)s.push(l),l=Rt();s!==p&&(l=zt())!==p?i=c=[c,f,s,l]:(mt=i,i=p)}else mt=i,i=p;else mt=i,i=p;for(;i!==p;){for(a.push(i),i=mt,c=[],f=Rt();f!==p;)c.push(f),f=Rt();if(c!==p)if(44===t.charCodeAt(mt)?(f=ct,mt++):(f=p,0===Et&&Nt(ft)),f!==p){for(s=[],l=Rt();l!==p;)s.push(l),l=Rt();s!==p&&(l=zt())!==p?i=c=[c,f,s,l]:(mt=i,i=p)}else mt=i,i=p;else mt=i,i=p}if(a!==p){for(i=[],c=Rt();c!==p;)i.push(c),c=Rt();i!==p?u=o=[o,a,i]:(mt=u,u=p)}else mt=u,u=p}else mt=u,u=p;u===p&&(u=null),u!==p?(125===t.charCodeAt(mt)?(o=gt,mt++):(o=p,0===Et&&Nt(At)),o!==p?(xt=r,r=e=Ct(u)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;return r}()),r}function Wt(){var r;return(r=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(rr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(tr)),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt($));return r}())===p&&(r=qt()),r}function qt(){var r,e,n,u;return r=mt,Gt()!==p?(e=function(){var r;Et++,cr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(fr));Et--,r===p&&0===Et&&Nt(ir);return r}(),e===p&&(e=kt())===p&&(e=Gt())===p&&(e=mt,117===t.charCodeAt(mt)?(n=er,mt++):(n=p,0===Et&&Nt(nr)),n!==p?(u=function(){var r,t,e,n,u;Et++,r=mt,t=Kt(),t!==p&&(e=Kt())!==p&&(n=Kt())!==p&&(u=Kt())!==p?r=t=[t,e,n,u]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(pr));return r}(),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p),e===p&&(e=mt,85===t.charCodeAt(mt)?(n=ur,mt++):(n=p,0===Et&&Nt(or)),n!==p?(u=function(){var r,t,e,n,u,o,a,i,c;Et++,r=mt,t=Kt(),t!==p&&(e=Kt())!==p&&(n=Kt())!==p&&(u=Kt())!==p&&(o=Kt())!==p&&(a=Kt())!==p&&(i=Kt())!==p&&(c=Kt())!==p?r=t=[t,e,n,u,o,a,i,c]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(vr));return r}(),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p))),e!==p?(xt=r,r=ar()):(mt=r,r=p)):(mt=r,r=p),r}function Gt(){var r;return Et++,92===t.charCodeAt(mt)?(r=lr,mt++):(r=p,0===Et&&Nt(hr)),Et--,r===p&&0===Et&&Nt(sr),r}function Kt(){var r;return dr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(gr)),r}function Lt(){var r,e,n;return Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p),e!==p?(Cr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(br)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p),Et--,r===p&&(e=p,0===Et&&Nt($)),r}function Xt(){var r,e,n;if(r=function(){var r,e,n;r=mt,e=mt,Et++,n=Jt(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(n=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(mr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(xr)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt($));return r}(),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p);r===p&&(r=qt());return r}(),r===p){if(r=mt,Gt()!==p)if(It()!==p){for(e=[],(n=Rt())===p&&(n=It());n!==p;)e.push(n),(n=Rt())===p&&(n=It());e!==p?(xt=r,r=yr()):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;r===p&&(r=It())}return r}function $t(){var r,e,n;return r=mt,e=mt,Et++,t.substr(mt,3)===K?(n=K,mt+=3):(n=p,0===Et&&Nt(L)),Et--,n===p?e=void 0:(mt=e,e=p),e!==p?(n=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(Fr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(wr)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt(Sr));return r}(),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p),r===p&&(r=It()),r}function re(){var r,e,n,u;return r=mt,101===t.charCodeAt(mt)?(e=Rr,mt++):(e=p,0===Et&&Nt(Ur)),e===p&&(69===t.charCodeAt(mt)?(e=zr,mt++):(e=p,0===Et&&Nt(Qr))),e!==p?((n=ee())===p&&(n=null),n!==p&&(u=ne())!==p?r=e=[e,n,u]:(mt=r,r=p)):(mt=r,r=p),r}function te(){var r,t;return r=mt,(t=ee())===p&&(t=null),t!==p&&ne()!==p?(xt=r,r=t=Yr()):(mt=r,r=p),r}function ee(){var r;return 43===t.charCodeAt(mt)?(r=kr,mt++):(r=p,0===Et&&Nt(Br)),r===p&&(45===t.charCodeAt(mt)?(r=Jr,mt++):(r=p,0===Et&&Nt(Pr))),r}function ne(){var r,e,n,u,o,a;if(r=mt,(e=ue())!==p){for(n=[],u=mt,95===t.charCodeAt(mt)?(o=Zr,mt++):(o=p,0===Et&&Nt(Ir)),o===p&&(o=null),o!==p&&(a=ue())!==p?u=o=[o,a]:(mt=u,u=p);u!==p;)n.push(u),u=mt,95===t.charCodeAt(mt)?(o=Zr,mt++):(o=p,0===Et&&Nt(Ir)),o===p&&(o=null),o!==p&&(a=ue())!==p?u=o=[o,a]:(mt=u,u=p);n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return r}function ue(){var r;return Vr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(Wr)),r}function oe(){var r,t,e;return Et++,r=mt,(t=ue())!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p),Et--,r===p&&(t=p,0===Et&&Nt(rt)),r}function ae(){var r,t,e;return Et++,r=mt,(t=ue())!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p),Et--,r===p&&(t=p,0===Et&&Nt(tt)),r}function ie(){var r,e,n,u,o,a,i;if(r=mt,(e=Vt())!==p){for(n=mt,u=[],o=ce();o!==p;)u.push(o),o=ce();if(u!==p)if(44===t.charCodeAt(mt)?(o=ct,mt++):(o=p,0===Et&&Nt(ft)),o!==p){for(a=[],i=ce();i!==p;)a.push(i),i=ce();a!==p&&(i=ie())!==p?n=u=[u,o,a,i]:(mt=n,n=p)}else mt=n,n=p;else mt=n,n=p;n===p&&(n=null),n!==p?(xt=r,r=e=pt(e,n)):(mt=r,r=p)}else mt=r,r=p;return r}function ce(){var r;return(r=Rt())===p&&(r=It())===p&&(r=Ut()),r}function fe(){var r,e,n,u,o,a,i,c,f,s;if(r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it)),e!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p)if((u=Qt())!==p){for(o=[],a=mt,i=[],c=Rt();c!==p;)i.push(c),c=Rt();if(i!==p)if(46===t.charCodeAt(mt)?(c=_r,mt++):(c=p,0===Et&&Nt(Nr)),c!==p){for(f=[],s=Rt();s!==p;)f.push(s),s=Rt();f!==p&&(s=Qt())!==p?a=i=[i,c,f,s]:(mt=a,a=p)}else mt=a,a=p;else mt=a,a=p;for(;a!==p;){for(o.push(a),a=mt,i=[],c=Rt();c!==p;)i.push(c),c=Rt();if(i!==p)if(46===t.charCodeAt(mt)?(c=_r,mt++):(c=p,0===Et&&Nt(Nr)),c!==p){for(f=[],s=Rt();s!==p;)f.push(s),s=Rt();f!==p&&(s=Qt())!==p?a=i=[i,c,f,s]:(mt=a,a=p)}else mt=a,a=p;else mt=a,a=p}if(o!==p){for(a=[],i=Rt();i!==p;)a.push(i),i=Rt();a!==p?(93===t.charCodeAt(mt)?(i=st,mt++):(i=p,0===Et&&Nt(lt)),i!==p?(xt=r,r=e=yt(u,o)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;else mt=r,r=p}else mt=r,r=p;return r}u=function(r){return"Value for "+r+" should not be redefined in the same table."},o=Number.isFinite||function(r){return"number"==typeof r&&isFinite(r)},a=Array.isArray||function(r){return"[object Array]"===Object.prototype.toString.call(r)},i=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},c="object"==typeof JSON&&JSON?JSON.stringify:function(r){return'"'+String(r).replace(/[\x00-\x1F"\\]/g,(function(r){switch(r){case'"':case"\\":return"\\"+r;case"\t":return"\\t";case"\n":return"\\n";case"\r":return"\\r";case"\b":return"\\b";case"\f":return"\\f";default:var t=r.charCodeAt(0).toString(16);return"\\u"+"0000".substr(t.length)+t}}))+'"'},f=function(r){switch(r){case'"':case"\\":return r;case"t":return"\t";case"n":return"\n";case"r":return"\r";case"b":return"\b";case"f":return"\f";default:Dt(c(r)+" cannot be escaped.")}},s=function(r){if((!o(r)||r<0||r>1114111)&&Dt("U+"+r.toString(16)+" is not a valid Unicode code point."),String.fromCodePoint)return String.fromCodePoint(r);var t="";return r>65535&&(r-=65536,t+=String.fromCharCode(r>>>10&1023|55296),r=56320|1023&r),t+=String.fromCharCode(r)},l=function(r,t){i(r,t)&&Dt(u(c(t)))},h=function(r,t,e){for(var n="",o=0,f=e.length;o{try{return t(n)}catch(t){throw t instanceof r?(t.line=t.location.start.line,t.column=t.location.start.column,t.offset=t.location.start.offset,new e(t.message,t.location.start)):t}};export{e as SyntaxError,n as parse}; +//# sourceMappingURL=toml.js.map diff --git a/core/src/3rd-party/xterm-readline.js b/core/src/3rd-party/xterm-readline.js new file mode 100644 index 00000000000..226009c52e0 --- /dev/null +++ b/core/src/3rd-party/xterm-readline.js @@ -0,0 +1,7 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/xterm-readline@1.1.2/lib/readline.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +import t from"string-width";var e,s="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},i={},r={};Object.defineProperty(r,"__esModule",{value:!0}),r.InputType=void 0,r.parseInput=function(t){return Array.from(function*(t){let s=[];const i=t[Symbol.iterator]();for(let t=i.next();!t.done;t=i.next()){const r=t.value;if(r.length>1){s.push(r);continue}const o=r.charCodeAt(0);if(s.length>0&&(o<32||127===o)&&(yield{inputType:e.Text,data:s},s=[]),27!==o)if(o<32||127===o){let t=e.UnsupportedControlChar;switch(o){case 1:t=e.CtrlA;break;case 3:t=e.CtrlC;break;case 4:t=e.CtrlD;break;case 5:t=e.CtrlE;break;case 11:t=e.CtrlK;break;case 17:t=e.CtrlQ;break;case 19:t=e.CtrlS;break;case 21:t=e.CtrlU;break;case 13:t=e.Enter;break;case 127:t=e.Backspace;break;case 12:t=e.CtrlL}yield{inputType:t,data:[r]}}else s.push(r);else{const t=i.next();if(t.done){s.push("");continue}let r=e.UnsupportedEscape;if("["!==t.value){if("\r"===t.value)r=e.AltEnter;yield{inputType:r,data:["",t.value]};continue}const o=i.next();if(o.done)continue;if(o.value>="0"&&o.value<="9"){let t=o.value;const s=i.next();if(s.done)return;if(s.value>="0"&&s.value<="9")t+=s.value;else if("~"!==s.value)continue;if("3"===t)r=e.Delete;yield{inputType:r,data:["","[",t,"~"]};continue}switch(o.value){case"A":r=e.ArrowUp;break;case"B":r=e.ArrowDown;break;case"C":r=e.ArrowRight;break;case"D":r=e.ArrowLeft;break;case"F":r=e.End;break;case"H":r=e.Home;break;case"\r":r=e.AltEnter}yield{inputType:r,data:["","[",o.value]}}}s.length>0&&(yield{inputType:e.Text,data:s})}(t))},function(t){t[t.Text=0]="Text",t[t.AltEnter=1]="AltEnter",t[t.ArrowUp=2]="ArrowUp",t[t.ArrowDown=3]="ArrowDown",t[t.ArrowLeft=4]="ArrowLeft",t[t.ArrowRight=5]="ArrowRight",t[t.Delete=6]="Delete",t[t.Backspace=7]="Backspace",t[t.CtrlA=8]="CtrlA",t[t.CtrlC=9]="CtrlC",t[t.CtrlD=10]="CtrlD",t[t.CtrlE=11]="CtrlE",t[t.CtrlK=12]="CtrlK",t[t.CtrlL=13]="CtrlL",t[t.CtrlQ=14]="CtrlQ",t[t.CtrlS=15]="CtrlS",t[t.CtrlU=16]="CtrlU",t[t.End=17]="End",t[t.Enter=18]="Enter",t[t.Home=19]="Home",t[t.ShiftEnter=20]="ShiftEnter",t[t.UnsupportedControlChar=21]="UnsupportedControlChar",t[t.UnsupportedEscape=22]="UnsupportedEscape"}(e||(r.InputType=e={}));var o={},h={};Object.defineProperty(h,"__esModule",{value:!0}),h.LineBuffer=void 0;h.LineBuffer=class{constructor(){this.buf="",this.pos=0}buffer(){return this.buf}pos_buffer(){return this.buf.slice(0,this.pos)}length(){return this.buf.length}char_length(){return[...this.buf].length}update(t,e){this.buf=t,this.pos=e}insert(t){const e=t.length,s=this.pos===this.buf.length;return this.buf=s?this.buf+t:this.buf.slice(0,this.pos)+t+this.buf.slice(this.pos),this.pos+=e,s}moveBack(t){const e=this.prevPos(t);return void 0!==e&&(this.pos=e,!0)}moveForward(t){const e=this.nextPos(t);return void 0!==e&&(this.pos=e,!0)}moveHome(){const t=this.startOfLine();return this.pos>t&&(this.pos=t,!0)}moveEnd(){const t=this.endOfLine();return this.pos!==t&&(this.pos=t,!0)}startOfLine(){const t=this.buf.slice(0,this.pos).lastIndexOf("\n");return-1!==t?t+1:0}endOfLine(){const t=this.buf.slice(this.pos).indexOf("\n");return-1!==t?this.pos+t:this.buf.length}moveLineUp(t){const e=this.buf.slice(0,this.pos).lastIndexOf("\n");if(-1===e)return!1;const s=[...this.buf.slice(e+1,this.pos)].length;let i=this.buf.slice(0,e).lastIndexOf("\n");-1===i?i=0:i+=1;let r=e;for(let e=1;e0&&(h=o.map((t=>t.length)).reduce(((t,e)=>t+e),0),h=i+h),this.pos=h,!0}moveLineDown(t){const e=this.buf.slice(this.pos).indexOf("\n");if(-1===e)return!1;let s=this.buf.slice(0,this.pos).lastIndexOf("\n");-1===s?s=0:s+=1;const i=[...this.buf.slice(s,this.pos)].length;let r=this.pos+e+1,o=this.buf.slice(r).indexOf("\n");o=-1===o?this.buf.length:r+o;for(let e=1;et.length)).reduce(((t,e)=>t+e),0)+r:this.pos=o,!0}set_pos(t){this.pos=t}prevPos(t){if(0===this.pos)return;const e=this.buf.slice(0,this.pos);return this.pos-[...e].slice(-t).map((t=>t.length)).reduce(((t,e)=>t+e),0)}nextPos(t){if(this.pos===this.buf.length)return;const e=this.buf.slice(this.pos);return this.pos+[...e].slice(0,t).map((t=>t.length)).reduce(((t,e)=>t+e),0)}backspace(t){const e=this.prevPos(t);return void 0!==e&&(this.buf=this.buf.slice(0,e)+this.buf.slice(this.pos),this.pos=e,!0)}delete(t){const e=this.nextPos(t);return void 0!==e&&(this.buf=this.buf.slice(0,this.pos)+this.buf.slice(e),!0)}deleteEndOfLine(){if(0==this.buf.length||this.pos==this.buf.length)return!1;const t=this.pos,e=this.endOfLine();return t==e?this.delete(1):this.buf=this.buf.slice(0,t)+this.buf.slice(e),!0}};var n=s&&s.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(o,"__esModule",{value:!0}),o.State=o.Layout=o.Position=void 0;const a=h,l=n(t);class u{constructor(t,e){this.row=void 0!==t?t:0,this.col=void 0!==e?e:0}}o.Position=u;class c{constructor(t){this.promptSize=t,this.cursor=new u,this.end=new u}}o.Layout=c;o.State=class{constructor(t,e,s,i){this.line=new a.LineBuffer,this.highlighting=!1,this.prompt=t,this.tty=e,this.highlighter=s,this.history=i,this.promptSize=e.calculatePosition(t,new u),this.layout=new c(this.promptSize)}buffer(){return this.line.buffer()}shouldHighlight(){return this.highlighter.highlightChar(this.line.buf,this.line.pos)?(this.highlighting=!0,!0):!!this.highlighting&&(this.highlighting=!1,!0)}clearScreen(){this.tty.clearScreen(),this.layout.cursor=new u,this.layout.end=new u,this.refresh()}editInsert(t){const e=this.line.insert(t),s=t.includes("\n");if(e&&!s){const e=(0,l.default)(t);e>0&&this.layout.cursor.col+e0)return;const t=this.history.prev();void 0!==t&&this.update(t)}nextHistory(){if(-1===this.history.cursor)return;const t=this.history.next();void 0!==t?this.update(t):this.update("")}moveCursor(){const t=this.tty.calculatePosition(this.line.pos_buffer(),this.promptSize);t!==this.layout.cursor&&(this.shouldHighlight()?this.refresh():(this.tty.moveCursor(this.layout.cursor,t),this.layout.promptSize=Object.assign({},this.promptSize),this.layout.cursor=Object.assign({},t)))}};var p={};Object.defineProperty(p,"__esModule",{value:!0}),p.History=void 0;p.History=class{constructor(t){this.entries=[],this.cursor=-1,this.maxEntries=t}saveToLocalStorage(){const t=null===window||void 0===window?void 0:window.localStorage;void 0!==t&&t.setItem("history",JSON.stringify(this.entries))}restoreFromLocalStorage(){const t=null===window||void 0===window?void 0:window.localStorage;if(void 0!==t){const e=t.getItem("history");if(null==e)return;try{const s=JSON.parse(e);Array.isArray(s)&&void 0===s.find((t=>"string"!=typeof t))?this.entries=s:(this.entries=[],t.setItem("history","[]"))}catch(e){this.entries=[],t.setItem("history","[]")}}}append(t){this.resetCursor(),this.entries.includes(t)?(this.entries.splice(this.entries.indexOf(t),1),this.entries.unshift(t)):this.entries.unshift(t),this.entries.length>this.maxEntries&&this.entries.pop(),this.saveToLocalStorage()}resetCursor(){this.cursor=-1}next(){if(-1!==this.cursor)return this.cursor-=1,this.entries[this.cursor]}prev(){if(!(this.cursor+1>=this.entries.length))return this.cursor+=1,this.entries[this.cursor]}};var d={},f=s&&s.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(d,"__esModule",{value:!0}),d.Tty=void 0;const y=f(t);d.Tty=class{constructor(t,e,s,i){this.tabWidth=s,this.col=t,this.row=e,this.out=i}write(t){return this.out.write(t)}print(t){return this.out.print(t)}println(t){return this.out.println(t)}clearScreen(){this.out.write("")}calculatePosition(t,e){const s=Object.assign({},e);let i=0;return[...t].forEach((t=>{if("\n"===t)return s.row+=1,void(s.col=0);let e=0;if("\t"===t)e=this.tabWidth-s.col%this.tabWidth;else{let s;[s,i]=function(t,e){return 1===e?"["===t?[0,2]:[0,0]:2===e?";"===t||t[0]>="0"&&t[0]<="9"?[0,e]:[0,0]:""===t?[0,1]:"\n"===t?[0,e]:[(0,y.default)(t),e]}(t,i),e=s}s.col+=e,s.col>this.col&&(s.row+=1,s.col=e)})),s.col===this.col&&(s.col=0,s.row+=1),s}computeLayout(t,e){const s=Object.assign({},t),i=e.pos,r=this.calculatePosition(e.buf.slice(0,e.pos),t);return{promptSize:s,cursor:r,end:i===e.buf.length?Object.assign({},r):this.calculatePosition(e.buf.slice(i),r)}}refreshLine(t,e,s,i,r){const o=i.cursor,h=i.end;this.clearOldRows(s),this.write(r.highlightPrompt(t)),this.write(r.highlight(e.buf,e.pos)),0===h.col&&h.row>0&&"\n"!==e.buf[e.buf.length-1]&&this.write("\n");const n=h.row-o.row;n>0&&this.write(`[${n}A`),o.col>0?this.write(`\r[${o.col}C`):this.write("\r")}clearOldRows(t){const e=t.cursor.row,s=t.end.row,i=Math.max(s-e,0);i>0&&this.write(`[${i}B`);for(let t=0;tt.row){const s=e.row-t.row;1===s?this.write(""):this.write(`[${s}B`)}else if(e.rowt.col){const s=e.col-t.col;1===s?this.write(""):this.write(`[${s}C`)}else if(e.col",this.tty(),this.highlighter,this.history),this.checkHandler=()=>!0,this.ctrlCHandler=()=>{},this.pauseHandler=t=>{},this.history.restoreFromLocalStorage()}activate(t){this.term=t,this.term.onData(this.readData.bind(this)),this.term.attachCustomKeyEventHandler(this.handleKeyEvent.bind(this))}dispose(){this.disposables.forEach((t=>t.dispose()))}appendHistory(t){this.history.append(t)}setHighlighter(t){this.highlighter=t}setCheckHandler(t){this.checkHandler=t}setCtrlCHandler(t){this.ctrlCHandler=t}setPauseHandler(t){this.pauseHandler=t}writeReady(){return!this.highWater}write(t){const e=(t="\n"===t?"\r\n":(t=t.replace(/^\n/,"\r\n")).replace(/([^\r])\n/g,"$1\r\n")).length;this.watermark+=e,this.watermark>this.highWatermark&&(this.highWater=!0),this.term&&this.term.write(t,(()=>{this.watermark=Math.max(this.watermark-e,0),this.highWater&&this.watermark{void 0!==this.term?(this.state=new g.State(t,this.tty(),this.highlighter,this.history),this.state.refresh(),this.activeRead={prompt:t,resolve:e,reject:s}):s("addon is not active")}))}handleKeyEvent(t){return"Enter"!==t.key||!t.shiftKey||("keydown"===t.type&&this.readKey({inputType:b.InputType.ShiftEnter,data:["\r"]}),!1)}readData(t){const e=(0,b.parseInput)(t);e.length>1||e[0].inputType===b.InputType.Text&&e[0].data.length>1?this.readPaste(e):this.readKey(e[0])}readPaste(t){const e=t.map((t=>t.inputType===b.InputType.Enter?{inputType:b.InputType.Text,data:["\n"]}:t));for(const t of e)t.inputType===b.InputType.Text?this.state.editInsert(t.data.join("")):this.readKey(t)}readKey(t){var e,s,i;if(void 0!==this.activeRead)switch(t.inputType){case b.InputType.Text:this.state.editInsert(t.data.join(""));break;case b.InputType.AltEnter:case b.InputType.ShiftEnter:this.state.editInsert("\n");break;case b.InputType.Enter:this.checkHandler(this.state.buffer())?(this.state.moveCursorToEnd(),null===(e=this.term)||void 0===e||e.write("\r\n"),this.history.append(this.state.buffer()),null===(s=this.activeRead)||void 0===s||s.resolve(this.state.buffer()),this.activeRead=void 0):this.state.editInsert("\n");break;case b.InputType.CtrlC:this.state.moveCursorToEnd(),null===(i=this.term)||void 0===i||i.write("^C\r\n"),this.state=new g.State(this.activeRead.prompt,this.tty(),this.highlighter,this.history),this.state.refresh();break;case b.InputType.CtrlS:this.pauseHandler(!1);break;case b.InputType.CtrlU:this.state.update("");break;case b.InputType.CtrlK:this.state.editDeleteEndOfLine();break;case b.InputType.CtrlQ:this.pauseHandler(!0);break;case b.InputType.CtrlL:this.state.clearScreen();break;case b.InputType.Home:case b.InputType.CtrlA:this.state.moveCursorHome();break;case b.InputType.End:case b.InputType.CtrlE:this.state.moveCursorEnd();break;case b.InputType.Backspace:this.state.editBackspace(1);break;case b.InputType.Delete:case b.InputType.CtrlD:this.state.editDelete(1);break;case b.InputType.ArrowLeft:this.state.moveCursorBack(1);break;case b.InputType.ArrowRight:this.state.moveCursorForward(1);break;case b.InputType.ArrowUp:this.state.moveCursorUp(1);break;case b.InputType.ArrowDown:this.state.moveCursorDown(1);case b.InputType.UnsupportedControlChar:case b.InputType.UnsupportedEscape:}else switch(t.inputType){case b.InputType.CtrlC:this.ctrlCHandler();break;case b.InputType.CtrlL:this.write("")}}};var k=i.__esModule;export{v as Readline,k as __esModule,i as default}; diff --git a/core/src/3rd-party/xterm.css b/core/src/3rd-party/xterm.css new file mode 100644 index 00000000000..bfff09b1257 --- /dev/null +++ b/core/src/3rd-party/xterm.css @@ -0,0 +1,7 @@ +/** + * Minified by jsDelivr using clean-css v5.3.2. + * Original file: /npm/@xterm/xterm@5.5.0/css/xterm.css + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:0}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm .xterm-cursor-pointer,.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:transparent}.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative} diff --git a/core/src/3rd-party/xterm.js b/core/src/3rd-party/xterm.js new file mode 100644 index 00000000000..7d1b7706ff4 --- /dev/null +++ b/core/src/3rd-party/xterm.js @@ -0,0 +1,7 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/@xterm/xterm@5.5.0/lib/xterm.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{};function t(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}var s=t,r=i;function n(e){if(s===setTimeout)return setTimeout(e,0);if((s===t||!s)&&setTimeout)return s=setTimeout,setTimeout(e,0);try{return s(e,0)}catch(t){try{return s.call(null,e,0)}catch(t){return s.call(this,e,0)}}}"function"==typeof e.setTimeout&&(s=setTimeout),"function"==typeof e.clearTimeout&&(r=clearTimeout);var o,a=[],h=!1,c=-1;function l(){h&&o&&(h=!1,o.length?a=o.concat(a):c=-1,a.length&&d())}function d(){if(!h){var e=n(l);h=!0;for(var t=a.length;t;){for(o=a,a=[];++c1)for(var i=1;i(()=>{var e={4567:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const n=i(9042),o=i(9924),a=i(844),h=i(4725),c=i(2585),l=i(3656);let d=t.AccessibilityManager=class extends a.Disposable{constructor(e,t,i,s){super(),this._terminal=e,this._coreBrowserService=i,this._renderService=s,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar("\n")))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,l.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,a.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){const i=this._terminal.buffer,s=i.lines.length.toString();for(let r=e;r<=t;r++){const e=i.lines.get(i.ydisp+r),t=[],n=e?.translateToString(!0,void 0,void 0,t)||"",o=(i.ydisp+r+1).toString(),a=this._rowElements[r];a&&(0===n.length?(a.innerText=" ",this._rowColumns.set(a,[0,1])):(a.textContent=n,this._rowColumns.set(a,t)),a.setAttribute("aria-posinset",o),a.setAttribute("aria-setsize",s))}this._announceCharacters()}_announceCharacters(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,t){const i=e.target,s=this._rowElements[0===t?1:this._rowElements.length-2];if(i.getAttribute("aria-posinset")===(0===t?"1":`${this._terminal.buffer.lines.length}`))return;if(e.relatedTarget!==s)return;let r,n;if(0===t?(r=i,n=this._rowElements.pop(),this._rowContainer.removeChild(n)):(r=this._rowElements.shift(),n=i,this._rowContainer.removeChild(r)),r.removeEventListener("focus",this._topBoundaryFocusListener),n.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){const e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement("afterbegin",e)}else{const e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(0===this._rowElements.length)return;const e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error("anchorNode and/or focusNode are null");let t={node:e.anchorNode,offset:e.anchorOffset},i={node:e.focusNode,offset:e.focusOffset};if((t.node.compareDocumentPosition(i.node)&Node.DOCUMENT_POSITION_PRECEDING||t.node===i.node&&t.offset>i.offset)&&([t,i]=[i,t]),t.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(t={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(t.node))return;const s=this._rowElements.slice(-1)[0];if(i.node.compareDocumentPosition(s)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(i={node:s,offset:s.textContent?.length??0}),!this._rowContainer.contains(i.node))return;const r=({node:e,offset:t})=>{const i=e instanceof Text?e.parentNode:e;let s=parseInt(i?.getAttribute("aria-posinset"),10)-1;if(isNaN(s))return console.warn("row is invalid. Race condition?"),null;const r=this._rowColumns.get(i);if(!r)return console.warn("columns is null. Race condition?"),null;let n=t=this._terminal.cols&&(++s,n=0),{row:s,column:n}},n=r(t),o=r(i);if(n&&o){if(n.row>o.row||n.row===o.row&&n.column>=o.column)throw new Error("invalid range");this._terminal.select(n.column,n.row,(o.row-n.row)*this._terminal.cols-n.column+o.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=this._coreBrowserService.mainDocument.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e{function i(e){return e.replace(/\r?\n/g,"\r")}function s(e,t){return t?"[200~"+e+"[201~":e}function r(e,t,r,n){e=s(e=i(e),r.decPrivateModes.bracketedPasteMode&&!0!==n.rawOptions.ignoreBracketedPasteMode),r.triggerDataEvent(e,!0),t.value=""}function n(e,t,i){const s=i.getBoundingClientRect(),r=e.clientX-s.left-10,n=e.clientY-s.top-10;t.style.width="20px",t.style.height="20px",t.style.left=`${r}px`,t.style.top=`${n}px`,t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=i,t.bracketTextForPaste=s,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i,s){e.stopPropagation(),e.clipboardData&&r(e.clipboardData.getData("text/plain"),t,i,s)},t.paste=r,t.moveTextAreaUnderMouseCursor=n,t.rightClickHandler=function(e,t,i,s,r){n(e,t,i),r&&s.rightClickSelect(e),t.value=s.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;const s=i(1505);t.ColorContrastCache=class{constructor(){this._color=new s.TwoKeyMap,this._css=new s.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,s){e.addEventListener(t,i,s);let r=!1;return{dispose:()=>{r||(r=!0,e.removeEventListener(t,i,s))}}}},3551:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier=void 0;const n=i(3656),o=i(8460),a=i(844),h=i(2585),c=i(4725);let l=t.Linkifier=class extends a.Disposable{get currentLink(){return this._currentLink}constructor(e,t,i,s,r){super(),this._element=e,this._mouseService=t,this._renderService=i,this._bufferService=s,this._linkProviderService=r,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new o.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new o.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,a.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,a.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(e){this._lastMouseEvent=e;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(!t)return;this._isMouseOut=!1;const i=e.composedPath();for(let e=0;e{e?.forEach((e=>{e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);let i=!1;for(const[s,r]of this._linkProviderService.linkProviders.entries())if(t){const t=this._activeProviderReplies?.get(s);t&&(i=this._checkLinkProviderResult(s,e,i))}else r.provideLinks(e.y,(t=>{if(this._isMouseOut)return;const r=t?.map((e=>({link:e})));this._activeProviderReplies?.set(s,r),i=this._checkLinkProviderResult(s,e,i),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(e.y,this._activeProviderReplies)}))}_removeIntersectingLinks(e,t){const i=new Set;for(let s=0;se?this._bufferService.cols:s.link.range.end.x;for(let e=n;e<=o;e++){if(i.has(e)){r.splice(t--,1);break}i.add(e)}}}}_checkLinkProviderResult(e,t,i){if(!this._activeProviderReplies)return i;const s=this._activeProviderReplies.get(e);let r=!1;for(let t=0;tthis._linkAtPosition(e.link,t)));e&&(i=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!i)for(let e=0;ethis._linkAtPosition(e.link,t)));if(s){i=!0,this._handleNewLink(s);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){if(!this._currentLink)return;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(e){if(!this._lastMouseEvent)return;const t=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);t&&this._linkAtPosition(e.link,t)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:void 0===e.link.decorations||e.link.decorations.underline,pointerCursor:void 0===e.link.decorations||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:e=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",e))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:t=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==t&&(this._currentLink.state.decorations.underline=t,this._currentLink.state.isHovered&&this._fireUnderlineEvent(e.link,t))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((e=>{if(!this._currentLink)return;const t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp,i=this._bufferService.buffer.ydisp+1+e.end;if(this._currentLink.link.range.start.y>=t&&this._currentLink.link.range.end.y<=i&&(this._clearCurrentLink(t,i),this._lastMouseEvent)){const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._askForLink(e,!1)}}))))}_linkHover(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add("xterm-cursor-pointer")),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){const i=e.range,s=this._bufferService.buffer.ydisp,r=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-s-1,i.end.x,i.end.y-s-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(r)}_linkLeave(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove("xterm-cursor-pointer")),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){const i=e.range.start.y*this._bufferService.cols+e.range.start.x,s=e.range.end.y*this._bufferService.cols+e.range.end.x,r=t.y*this._bufferService.cols+t.x;return i<=r&&r<=s}_positionFromMouseEvent(e,t,i){const s=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(s)return{x:s[0],y:s[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,s,r){return{x1:e,y1:t,x2:i,y2:s,cols:this._bufferService.cols,fg:r}}};t.Linkifier=l=s([r(1,c.IMouseService),r(2,c.IRenderService),r(3,h.IBufferService),r(4,c.ILinkProviderService)],l)},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkProvider=void 0;const n=i(511),o=i(2585);let a=t.OscLinkProvider=class{constructor(e,t,i){this._bufferService=e,this._optionsService=t,this._oscLinkService=i}provideLinks(e,t){const i=this._bufferService.buffer.lines.get(e-1);if(!i)return void t(void 0);const s=[],r=this._optionsService.rawOptions.linkHandler,o=new n.CellData,a=i.getTrimmedLength();let c=-1,l=-1,d=!1;for(let t=0;tr?r.activate(e,t,n):h(0,t),hover:(e,t)=>r?.hover?.(e,t,n),leave:(e,t)=>r?.leave?.(e,t,n)})}d=!1,o.hasExtendedAttrs()&&o.extended.urlId?(l=t,c=o.extended.urlId):(l=-1,c=-1)}}t(s)}};function h(e,t){if(confirm(`Do you want to navigate to ${t}?\n\nWARNING: This link could potentially be dangerous`)){const e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}}t.OscLinkProvider=a=s([r(0,o.IBufferService),r(1,o.IOptionsService),r(2,o.IOscLinkService)],a)},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._renderCallback=e,this._coreBrowserService=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh()))),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._animationFrame=void 0,void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return void this._runRefreshCallbacks();const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(const e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const s=i(3614),r=i(3656),n=i(3551),o=i(9042),a=i(3730),h=i(1680),c=i(3107),l=i(5744),d=i(2950),_=i(1296),u=i(428),f=i(4269),v=i(5114),p=i(8934),g=i(3230),m=i(9312),S=i(4725),C=i(6731),b=i(8055),w=i(8969),y=i(8460),E=i(844),k=i(6114),L=i(8437),D=i(2584),R=i(7399),x=i(5941),A=i(9074),B=i(2585),T=i(5435),M=i(4567),O=i(779);class P extends w.CoreTerminal{get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}get onWillOpen(){return this._onWillOpen.event}constructor(e={}){super(e),this.browser=k,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._accessibilityManager=this.register(new E.MutableDisposable),this._onCursorMove=this.register(new y.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onKey=this.register(new y.EventEmitter),this.onKey=this._onKey.event,this._onRender=this.register(new y.EventEmitter),this.onRender=this._onRender.event,this._onSelectionChange=this.register(new y.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onTitleChange=this.register(new y.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onBell=this.register(new y.EventEmitter),this.onBell=this._onBell.event,this._onFocus=this.register(new y.EventEmitter),this._onBlur=this.register(new y.EventEmitter),this._onA11yCharEmitter=this.register(new y.EventEmitter),this._onA11yTabEmitter=this.register(new y.EventEmitter),this._onWillOpen=this.register(new y.EventEmitter),this._setup(),this._decorationService=this._instantiationService.createInstance(A.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this._linkProviderService=this._instantiationService.createInstance(O.LinkProviderService),this._instantiationService.setService(S.ILinkProviderService,this._linkProviderService),this._linkProviderService.registerLinkProvider(this._instantiationService.createInstance(a.OscLinkProvider)),this.register(this._inputHandler.onRequestBell((()=>this._onBell.fire()))),this.register(this._inputHandler.onRequestRefreshRows(((e,t)=>this.refresh(e,t)))),this.register(this._inputHandler.onRequestSendFocus((()=>this._reportFocus()))),this.register(this._inputHandler.onRequestReset((()=>this.reset()))),this.register(this._inputHandler.onRequestWindowsOptionsReport((e=>this._reportWindowsOptions(e)))),this.register(this._inputHandler.onColor((e=>this._handleColorEvent(e)))),this.register((0,y.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,y.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize((e=>this._afterResize(e.cols,e.rows)))),this.register((0,E.toDisposable)((()=>{this._customKeyEventHandler=void 0,this.element?.parentNode?.removeChild(this.element)})))}_handleColorEvent(e){if(this._themeService)for(const t of e){let e,i="";switch(t.index){case 256:e="foreground",i="10";break;case 257:e="background",i="11";break;case 258:e="cursor",i="12";break;default:e="ansi",i="4;"+t.index}switch(t.type){case 0:const s=b.color.toColorRGB("ansi"===e?this._themeService.colors.ansi[t.index]:this._themeService.colors[e]);this.coreService.triggerDataEvent(`${D.C0.ESC}]${i};${(0,x.toRgbString)(s)}${D.C1_ESCAPED.ST}`);break;case 1:if("ansi"===e)this._themeService.modifyColors((e=>e.ansi[t.index]=b.channels.toColor(...t.color)));else{const i=e;this._themeService.modifyColors((e=>e[i]=b.channels.toColor(...t.color)))}break;case 2:this._themeService.restoreColor(t.index)}}}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_handleScreenReaderModeOptionChange(e){e?!this._accessibilityManager.value&&this._renderService&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)):this._accessibilityManager.clear()}_handleTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[I"),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){return this.textarea?.blur()}_handleTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){if(!this.textarea||!this.buffer.isCursorInViewport||this._compositionHelper.isComposing||!this._renderService)return;const e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(!t)return;const i=Math.min(this.buffer.x,this.cols-1),s=this._renderService.dimensions.css.cell.height,r=t.getWidth(i),n=this._renderService.dimensions.css.cell.width*r,o=this.buffer.y*this._renderService.dimensions.css.cell.height,a=i*this._renderService.dimensions.css.cell.width;this.textarea.style.left=a+"px",this.textarea.style.top=o+"px",this.textarea.style.width=n+"px",this.textarea.style.height=s+"px",this.textarea.style.lineHeight=s+"px",this.textarea.style.zIndex="-5"}_initGlobal(){this._bindKeys(),this.register((0,r.addDisposableDomListener)(this.element,"copy",(e=>{this.hasSelection()&&(0,s.copyHandler)(e,this._selectionService)})));const e=e=>(0,s.handlePasteEvent)(e,this.textarea,this.coreService,this.optionsService);this.register((0,r.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,r.addDisposableDomListener)(this.element,"paste",e)),k.isFirefox?this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>{2===e.button&&(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))):this.register((0,r.addDisposableDomListener)(this.element,"contextmenu",(e=>{(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))),k.isLinux&&this.register((0,r.addDisposableDomListener)(this.element,"auxclick",(e=>{1===e.button&&(0,s.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)})))}_bindKeys(){this.register((0,r.addDisposableDomListener)(this.textarea,"keyup",(e=>this._keyUp(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keydown",(e=>this._keyDown(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keypress",(e=>this._keyPress(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionstart",(()=>this._compositionHelper.compositionstart()))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionupdate",(e=>this._compositionHelper.compositionupdate(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionend",(()=>this._compositionHelper.compositionend()))),this.register((0,r.addDisposableDomListener)(this.textarea,"input",(e=>this._inputEvent(e)),!0)),this.register(this.onRender((()=>this._compositionHelper.updateCompositionElements())))}open(e){if(!e)throw new Error("Terminal requires a parent element.");if(e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this.element?.ownerDocument.defaultView&&this._coreBrowserService)return void(this.element.ownerDocument.defaultView!==this._coreBrowserService.window&&(this._coreBrowserService.window=this.element.ownerDocument.defaultView));this._document=e.ownerDocument,this.options.documentOverride&&this.options.documentOverride instanceof Document&&(this._document=this.optionsService.rawOptions.documentOverride),this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),e.appendChild(this.element);const t=this._document.createDocumentFragment();this._viewportElement=this._document.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),t.appendChild(this._viewportElement),this._viewportScrollArea=this._document.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=this._document.createElement("div"),this.screenElement.classList.add("xterm-screen"),this.register((0,r.addDisposableDomListener)(this.screenElement,"mousemove",(e=>this.updateCursorStyle(e)))),this._helperContainer=this._document.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),t.appendChild(this.screenElement),this.textarea=this._document.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",o.promptLabel),k.isChromeOS||this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this._coreBrowserService=this.register(this._instantiationService.createInstance(v.CoreBrowserService,this.textarea,e.ownerDocument.defaultView??window,this._document??"undefined"!=typeof window?window.document:null)),this._instantiationService.setService(S.ICoreBrowserService,this._coreBrowserService),this.register((0,r.addDisposableDomListener)(this.textarea,"focus",(e=>this._handleTextAreaFocus(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"blur",(()=>this._handleTextAreaBlur()))),this._helperContainer.appendChild(this.textarea),this._charSizeService=this._instantiationService.createInstance(u.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(S.ICharSizeService,this._charSizeService),this._themeService=this._instantiationService.createInstance(C.ThemeService),this._instantiationService.setService(S.IThemeService,this._themeService),this._characterJoinerService=this._instantiationService.createInstance(f.CharacterJoinerService),this._instantiationService.setService(S.ICharacterJoinerService,this._characterJoinerService),this._renderService=this.register(this._instantiationService.createInstance(g.RenderService,this.rows,this.screenElement)),this._instantiationService.setService(S.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange((e=>this._onRender.fire(e)))),this.onResize((e=>this._renderService.resize(e.cols,e.rows))),this._compositionView=this._document.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(d.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this._mouseService=this._instantiationService.createInstance(p.MouseService),this._instantiationService.setService(S.IMouseService,this._mouseService),this.linkifier=this.register(this._instantiationService.createInstance(n.Linkifier,this.screenElement)),this.element.appendChild(t);try{this._onWillOpen.fire(this.element)}catch{}this._renderService.hasRenderer()||this._renderService.setRenderer(this._createRenderer()),this.viewport=this._instantiationService.createInstance(h.Viewport,this._viewportElement,this._viewportScrollArea),this.viewport.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent,1))),this.register(this._inputHandler.onRequestSyncScrollBar((()=>this.viewport.syncScrollArea()))),this.register(this.viewport),this.register(this.onCursorMove((()=>{this._renderService.handleCursorMove(),this._syncTextArea()}))),this.register(this.onResize((()=>this._renderService.handleResize(this.cols,this.rows)))),this.register(this.onBlur((()=>this._renderService.handleBlur()))),this.register(this.onFocus((()=>this._renderService.handleFocus()))),this.register(this._renderService.onDimensionsChange((()=>this.viewport.syncScrollArea()))),this._selectionService=this.register(this._instantiationService.createInstance(m.SelectionService,this.element,this.screenElement,this.linkifier)),this._instantiationService.setService(S.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent)))),this.register(this._selectionService.onSelectionChange((()=>this._onSelectionChange.fire()))),this.register(this._selectionService.onRequestRedraw((e=>this._renderService.handleSelectionChanged(e.start,e.end,e.columnSelectMode)))),this.register(this._selectionService.onLinuxMouseSelection((e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()}))),this.register(this._onScroll.event((e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()}))),this.register((0,r.addDisposableDomListener)(this._viewportElement,"scroll",(()=>this._selectionService.refresh()))),this.register(this._instantiationService.createInstance(c.BufferDecorationRenderer,this.screenElement)),this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>this._selectionService.handleMouseDown(e)))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)),this.register(this.optionsService.onSpecificOptionChange("screenReaderMode",(e=>this._handleScreenReaderModeOptionChange(e)))),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onSpecificOptionChange("overviewRulerWidth",(e=>{!this._overviewRulerRenderer&&e&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement)))})),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(_.DomRenderer,this,this._document,this.element,this.screenElement,this._viewportElement,this._helperContainer,this.linkifier)}bindMouse(){const e=this,t=this.element;function i(t){const i=e._mouseService.getMouseReportCoords(t,e.screenElement);if(!i)return!1;let s,r;switch(t.overrideType||t.type){case"mousemove":r=32,void 0===t.buttons?(s=3,void 0!==t.button&&(s=t.button<3?t.button:3)):s=1&t.buttons?0:4&t.buttons?1:2&t.buttons?2:3;break;case"mouseup":r=0,s=t.button<3?t.button:3;break;case"mousedown":r=1,s=t.button<3?t.button:3;break;case"wheel":if(e._customWheelEventHandler&&!1===e._customWheelEventHandler(t))return!1;if(0===e.viewport.getLinesScrolled(t))return!1;r=t.deltaY<0?0:1,s=4;break;default:return!1}return!(void 0===r||void 0===s||s>4)&&e.coreMouseService.triggerMouseEvent({col:i.col,row:i.row,x:i.x,y:i.y,button:s,action:r,ctrl:t.ctrlKey,alt:t.altKey,shift:t.shiftKey})}const s={mouseup:null,wheel:null,mousedrag:null,mousemove:null},n={mouseup:e=>(i(e),e.buttons||(this._document.removeEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.removeEventListener("mousemove",s.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange((e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?s.mousemove||(t.addEventListener("mousemove",n.mousemove),s.mousemove=n.mousemove):(t.removeEventListener("mousemove",s.mousemove),s.mousemove=null),16&e?s.wheel||(t.addEventListener("wheel",n.wheel,{passive:!1}),s.wheel=n.wheel):(t.removeEventListener("wheel",s.wheel),s.wheel=null),2&e?s.mouseup||(s.mouseup=n.mouseup):(this._document.removeEventListener("mouseup",s.mouseup),s.mouseup=null),4&e?s.mousedrag||(s.mousedrag=n.mousedrag):(this._document.removeEventListener("mousemove",s.mousedrag),s.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,r.addDisposableDomListener)(t,"mousedown",(e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),s.mouseup&&this._document.addEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.addEventListener("mousemove",s.mousedrag),this.cancel(e)}))),this.register((0,r.addDisposableDomListener)(t,"wheel",(e=>{if(!s.wheel){if(this._customWheelEventHandler&&!1===this._customWheelEventHandler(e))return!1;if(!this.buffer.hasScrollback){const t=this.viewport.getLinesScrolled(e);if(0===t)return;const i=D.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let s="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchStart(e),this.cancel(e)}),{passive:!0})),this.register((0,r.addDisposableDomListener)(t,"touchmove",(e=>{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchMove(e)?void 0:this.cancel(e)}),{passive:!1}))}refresh(e,t){this._renderService?.refreshRows(e,t)}updateCursorStyle(e){this._selectionService?.shouldColumnSelect(e)?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){1===i?(super.scrollLines(e,t,i),this.refresh(0,this.rows-1)):this.viewport?.scrollLines(e)}paste(e){(0,s.paste)(e,this.textarea,this.coreService,this.optionsService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}attachCustomWheelEventHandler(e){this._customWheelEventHandler=e}registerLinkProvider(e){return this._linkProviderService.registerLinkProvider(e)}registerCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");const t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}registerMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){this._selectionService?.clearSelection()}selectAll(){this._selectionService?.selectAll()}selectLines(e,t){this._selectionService?.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;const t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.options.scrollOnUserInput&&this.buffer.ybase!==this.buffer.ydisp&&this.scrollToBottom(),!1;t||"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);const i=(0,R.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3===i.type||2===i.type){const t=this.rows-1;return this.scrollLines(2===i.type?-t:t),this.cancel(e,!0)}return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(i.cancel&&this.cancel(e,!0),!i.key||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&1===e.key.length&&e.key.charCodeAt(0)>=65&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(i.key!==D.C0.ETX&&i.key!==D.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),!this.optionsService.rawOptions.screenReaderMode||e.altKey||e.ctrlKey?this.cancel(e,!0):void(this._keyDownHandled=!0))))}_isThirdLevelShift(e,t){const i=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?i:i&&(!t.keyCode||t.keyCode>47)}_keyUp(e){this._keyDownSeen=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return 16===e.keyCode||17===e.keyCode||18===e.keyCode}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)}_keyPress(e){let t;if(this._keyPressHandled=!1,this._keyDownHandled)return!1;if(this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(null===e.which||void 0===e.which)t=e.keyCode;else{if(0===e.which||0===e.charCode)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))}_inputEvent(e){if(e.data&&"insertText"===e.inputType&&(!e.composed||!this._keyDownSeen)&&!this.optionsService.rawOptions.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;const t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1}resize(e,t){e!==this.cols||t!==this.rows?super.resize(e,t):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()}_afterResize(e,t){this._charSizeService?.measure(),this.viewport?.syncScrollArea(!0)}clear(){if(0!==this.buffer.ybase||0!==this.buffer.y){this.buffer.clearAllMarkers(),this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(let e=1;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;const s=Date.now();if(s-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=s,this._innerRefresh();else if(!this._additionalRefreshRequested){const e=s-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0}),t)}}_innerRefresh(){if(void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return;const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}}},1680:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;const n=i(3656),o=i(4725),a=i(8460),h=i(844),c=i(2585);let l=t.Viewport=class extends h.Disposable{constructor(e,t,i,s,r,o,h,c){super(),this._viewportElement=e,this._scrollArea=t,this._bufferService=i,this._optionsService=s,this._charSizeService=r,this._renderService=o,this._coreBrowserService=h,this.scrollBarWidth=0,this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._wheelPartialScroll=0,this._refreshAnimationFrame=null,this._ignoreNextScrollEvent=!1,this._smoothScrollState={startTime:0,origin:-1,target:-1},this._onRequestScrollLines=this.register(new a.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this.register((0,n.addDisposableDomListener)(this._viewportElement,"scroll",this._handleScroll.bind(this))),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange((e=>this._renderDimensions=e))),this._handleThemeChange(c.colors),this.register(c.onChangeColors((e=>this._handleThemeChange(e)))),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.syncScrollArea()))),setTimeout((()=>this.syncScrollArea()))}_handleThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}reset(){this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._coreBrowserService.window.requestAnimationFrame((()=>this.syncScrollArea()))}_refresh(e){if(e)return this._innerRefresh(),void(null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame));null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderDimensions.device.cell.height/this._coreBrowserService.dpr,this._currentDeviceCellHeight=this._renderDimensions.device.cell.height,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;const e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderDimensions.css.canvas.height);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+"px")}const e=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==e&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=e),this._refreshAnimationFrame=null}syncScrollArea(e=!1){if(this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.css.canvas.height&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.device.cell.height===this._currentDeviceCellHeight||this._refresh(e)}_handleScroll(e){if(this._lastScrollTop=this._viewportElement.scrollTop,!this._viewportElement.offsetParent)return;if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._onRequestScrollLines.fire({amount:0,suppressScrollEvent:!0});const t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._onRequestScrollLines.fire({amount:t,suppressScrollEvent:!0})}_smoothScroll(){if(this._isDisposed||-1===this._smoothScrollState.origin||-1===this._smoothScrollState.target)return;const e=this._smoothScrollPercent();this._viewportElement.scrollTop=this._smoothScrollState.origin+Math.round(e*(this._smoothScrollState.target-this._smoothScrollState.origin)),e<1?this._coreBrowserService.window.requestAnimationFrame((()=>this._smoothScroll())):this._clearSmoothScrollState()}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){const i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||t>0&&i0&&(i=e),s=""}}return{bufferElements:r,cursorElement:i}}getLinesScrolled(e){if(0===e.deltaY||e.shiftKey)return 0;let t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t}_applyScrollModifier(e,t){const i=this._optionsService.rawOptions.fastScrollModifier;return"alt"===i&&t.altKey||"ctrl"===i&&t.ctrlKey||"shift"===i&&t.shiftKey?e*this._optionsService.rawOptions.fastScrollSensitivity*this._optionsService.rawOptions.scrollSensitivity:e*this._optionsService.rawOptions.scrollSensitivity}handleTouchStart(e){this._lastTouchY=e.touches[0].pageY}handleTouchMove(e){const t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))}};t.Viewport=l=s([r(2,c.IBufferService),r(3,c.IOptionsService),r(4,o.ICharSizeService),r(5,o.IRenderService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],l)},3107:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferDecorationRenderer=void 0;const n=i(4725),o=i(844),a=i(2585);let h=t.BufferDecorationRenderer=class extends o.Disposable{constructor(e,t,i,s,r){super(),this._screenElement=e,this._bufferService=t,this._coreBrowserService=i,this._decorationService=s,this._renderService=r,this._decorationElements=new Map,this._altBufferIsActive=!1,this._dimensionsChanged=!1,this._container=document.createElement("div"),this._container.classList.add("xterm-decoration-container"),this._screenElement.appendChild(this._container),this.register(this._renderService.onRenderedViewportChange((()=>this._doRefreshDecorations()))),this.register(this._renderService.onDimensionsChange((()=>{this._dimensionsChanged=!0,this._queueRefresh()}))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt}))),this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh()))),this.register(this._decorationService.onDecorationRemoved((e=>this._removeDecoration(e)))),this.register((0,o.toDisposable)((()=>{this._container.remove(),this._decorationElements.clear()})))}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback((()=>{this._doRefreshDecorations(),this._animationFrame=void 0})))}_doRefreshDecorations(){for(const e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){const t=this._coreBrowserService.mainDocument.createElement("div");t.classList.add("xterm-decoration"),t.classList.toggle("xterm-decoration-top-layer","top"===e?.options?.layer),t.style.width=`${Math.round((e.options.width||1)*this._renderService.dimensions.css.cell.width)}px`,t.style.height=(e.options.height||1)*this._renderService.dimensions.css.cell.height+"px",t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.css.cell.height+"px",t.style.lineHeight=`${this._renderService.dimensions.css.cell.height}px`;const i=e.options.x??0;return i&&i>this._bufferService.cols&&(t.style.display="none"),this._refreshXPosition(e,t),t}_refreshStyle(e){const t=e.marker.line-this._bufferService.buffers.active.ydisp;if(t<0||t>=this._bufferService.rows)e.element&&(e.element.style.display="none",e.onRenderEmitter.fire(e.element));else{let i=this._decorationElements.get(e);i||(i=this._createElement(e),e.element=i,this._decorationElements.set(e,i),this._container.appendChild(i),e.onDispose((()=>{this._decorationElements.delete(e),i.remove()}))),i.style.top=t*this._renderService.dimensions.css.cell.height+"px",i.style.display=this._altBufferIsActive?"none":"block",e.onRenderEmitter.fire(i)}}_refreshXPosition(e,t=e.element){if(!t)return;const i=e.options.x??0;"right"===(e.options.anchor||"left")?t.style.right=i?i*this._renderService.dimensions.css.cell.width+"px":"":t.style.left=i?i*this._renderService.dimensions.css.cell.width+"px":""}_removeDecoration(e){this._decorationElements.get(e)?.remove(),this._decorationElements.delete(e),e.dispose()}};t.BufferDecorationRenderer=h=s([r(1,a.IBufferService),r(2,n.ICoreBrowserService),r(3,a.IDecorationService),r(4,n.IRenderService)],h)},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(const t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}if(this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OverviewRulerRenderer=void 0;const n=i(5871),o=i(4725),a=i(844),h=i(2585),c={full:0,left:0,center:0,right:0},l={full:0,left:0,center:0,right:0},d={full:0,left:0,center:0,right:0};let _=t.OverviewRulerRenderer=class extends a.Disposable{get _width(){return this._optionsService.options.overviewRulerWidth||0}constructor(e,t,i,s,r,o,h){super(),this._viewportElement=e,this._screenElement=t,this._bufferService=i,this._decorationService=s,this._renderService=r,this._optionsService=o,this._coreBrowserService=h,this._colorZoneStore=new n.ColorZoneStore,this._shouldUpdateDimensions=!0,this._shouldUpdateAnchor=!0,this._lastKnownBufferLength=0,this._canvas=this._coreBrowserService.mainDocument.createElement("canvas"),this._canvas.classList.add("xterm-decoration-overview-ruler"),this._refreshCanvasDimensions(),this._viewportElement.parentElement?.insertBefore(this._canvas,this._viewportElement);const c=this._canvas.getContext("2d");if(!c)throw new Error("Ctx cannot be null");this._ctx=c,this._registerDecorationListeners(),this._registerBufferChangeListeners(),this._registerDimensionChangeListeners(),this.register((0,a.toDisposable)((()=>{this._canvas?.remove()})))}_registerDecorationListeners(){this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh(void 0,!0)))),this.register(this._decorationService.onDecorationRemoved((()=>this._queueRefresh(void 0,!0))))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"}))),this.register(this._bufferService.onScroll((()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())})))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender((()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)}))),this.register(this._optionsService.onSpecificOptionChange("overviewRulerWidth",(()=>this._queueRefresh(!0)))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh(!0)))),this._queueRefresh(!0)}_refreshDrawConstants(){const e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);l.full=this._canvas.width,l.left=e,l.center=t,l.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=l.left,d.right=l.left+l.center}_refreshDrawHeightConstants(){c.full=Math.round(2*this._coreBrowserService.dpr);const e=this._canvas.height/this._bufferService.buffer.lines.length,t=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowserService.dpr);c.left=t,c.center=t,c.right=t}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=`${this._width}px`,this._canvas.width=Math.round(this._width*this._coreBrowserService.dpr),this._canvas.style.height=`${this._screenElement.clientHeight}px`,this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowserService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(const e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;const e=this._colorZoneStore.zones;for(const t of e)"full"!==t.position&&this._renderColorZone(t);for(const t of e)"full"===t.position&&this._renderColorZone(t);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-c[e.position||"full"]/2),l[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+c[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>{this._refreshDecorations(),this._animationFrame=void 0})))}};t.OverviewRulerRenderer=_=s([r(2,h.IBufferService),r(3,h.IDecorationService),r(4,o.IRenderService),r(5,h.IOptionsService),r(6,o.ICoreBrowserService)],_)},2950:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;const n=i(4725),o=i(2585),a=i(2584);let h=t.CompositionHelper=class{get isComposing(){return this._isComposing}constructor(e,t,i,s,r,n){this._textarea=e,this._compositionView=t,this._bufferService=i,this._optionsService=s,this._coreService=r,this._renderService=n,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=""}compositionstart(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent="",this._dataAlreadySent="",this._compositionView.classList.add("active")}compositionupdate(e){this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((()=>{this._compositionPosition.end=this._textarea.value.length}),0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){const e={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((()=>{if(this._isSendingComposition){let t;this._isSendingComposition=!1,e.start+=this._dataAlreadySent.length,t=this._isComposing?this._textarea.value.substring(e.start,e.end):this._textarea.value.substring(e.start),t.length>0&&this._coreService.triggerDataEvent(t,!0)}}),0)}else{this._isSendingComposition=!1;const e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){const e=this._textarea.value;setTimeout((()=>{if(!this._isComposing){const t=this._textarea.value,i=t.replace(e,"");this._dataAlreadySent=i,t.length>e.length?this._coreService.triggerDataEvent(i,!0):t.lengththis.updateCompositionElements(!0)),0)}}};t.CompositionHelper=h=s([r(2,o.IBufferService),r(3,o.IOptionsService),r(4,o.ICoreService),r(5,n.IRenderService)],h)},9806:(e,t)=>{function i(e,t,i){const s=i.getBoundingClientRect(),r=e.getComputedStyle(i),n=parseInt(r.getPropertyValue("padding-left")),o=parseInt(r.getPropertyValue("padding-top"));return[t.clientX-s.left-n,t.clientY-s.top-o]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=i,t.getCoords=function(e,t,s,r,n,o,a,h,c){if(!o)return;const l=i(e,t,s);return l?(l[0]=Math.ceil((l[0]+(c?a/2:0))/a),l[1]=Math.ceil(l[1]/h),l[0]=Math.min(Math.max(l[0],1),r+(c?1:0)),l[1]=Math.min(Math.max(l[1],1),n),l):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;const s=i(2584);function r(e,t,i,s){const r=e-n(e,i),a=t-n(t,i),l=Math.abs(r-a)-function(e,t,i){let s=0;const r=e-n(e,i),a=t-n(t,i);for(let n=0;n=0&&et?"A":"B"}function a(e,t,i,s,r,n){let o=e,a=t,h="";for(;o!==i||a!==s;)o+=r?1:-1,r&&o>n.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),o=0,e=0,a++):!r&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),o=n.cols-1,e=o,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function h(e,t){const i=t?"O":"[";return s.C0.ESC+i+e}function c(e,t){e=Math.floor(e);let i="";for(let s=0;s0?s-n(s,o):t;const _=s,u=function(e,t,i,s,o,a){let h;return h=r(i,s,o,a).length>0?s-n(s,o):t,e=i&&he?"D":"C",c(Math.abs(o-e),h(d,s));d=l>t?"D":"C";const _=Math.abs(l-t);return c(function(e,t){return t.cols-e}(l>t?e:o,i)+(_-1)*i.cols+1+((l>t?o:e)-1),h(d,s))}},1296:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;const n=i(3787),o=i(2550),a=i(2223),h=i(6171),c=i(6052),l=i(4725),d=i(8055),_=i(8460),u=i(844),f=i(2585),v="xterm-dom-renderer-owner-",p="xterm-rows",g="xterm-fg-",m="xterm-bg-",S="xterm-focus",C="xterm-selection";let b=1,w=t.DomRenderer=class extends u.Disposable{constructor(e,t,i,s,r,a,l,d,f,g,m,S,w){super(),this._terminal=e,this._document=t,this._element=i,this._screenElement=s,this._viewportElement=r,this._helperContainer=a,this._linkifier2=l,this._charSizeService=f,this._optionsService=g,this._bufferService=m,this._coreBrowserService=S,this._themeService=w,this._terminalClass=b++,this._rowElements=[],this._selectionRenderModel=(0,c.createSelectionRenderModel)(),this.onRequestRedraw=this.register(new _.EventEmitter).event,this._rowContainer=this._document.createElement("div"),this._rowContainer.classList.add(p),this._rowContainer.style.lineHeight="normal",this._rowContainer.setAttribute("aria-hidden","true"),this._refreshRowElements(this._bufferService.cols,this._bufferService.rows),this._selectionContainer=this._document.createElement("div"),this._selectionContainer.classList.add(C),this._selectionContainer.setAttribute("aria-hidden","true"),this.dimensions=(0,h.createRenderDimensions)(),this._updateDimensions(),this.register(this._optionsService.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._themeService.onChangeColors((e=>this._injectCss(e)))),this._injectCss(this._themeService.colors),this._rowFactory=d.createInstance(n.DomRendererRowFactory,document),this._element.classList.add(v+this._terminalClass),this._screenElement.appendChild(this._rowContainer),this._screenElement.appendChild(this._selectionContainer),this.register(this._linkifier2.onShowLinkUnderline((e=>this._handleLinkHover(e)))),this.register(this._linkifier2.onHideLinkUnderline((e=>this._handleLinkLeave(e)))),this.register((0,u.toDisposable)((()=>{this._element.classList.remove(v+this._terminalClass),this._rowContainer.remove(),this._selectionContainer.remove(),this._widthCache.dispose(),this._themeStyleElement.remove(),this._dimensionsStyleElement.remove()}))),this._widthCache=new o.WidthCache(this._document,this._helperContainer),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}_updateDimensions(){const e=this._coreBrowserService.dpr;this.dimensions.device.char.width=this._charSizeService.width*e,this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*e),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.left=0,this.dimensions.device.char.top=0,this.dimensions.device.canvas.width=this.dimensions.device.cell.width*this._bufferService.cols,this.dimensions.device.canvas.height=this.dimensions.device.cell.height*this._bufferService.rows,this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/e),this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/e),this.dimensions.css.cell.width=this.dimensions.css.canvas.width/this._bufferService.cols,this.dimensions.css.cell.height=this.dimensions.css.canvas.height/this._bufferService.rows;for(const e of this._rowElements)e.style.width=`${this.dimensions.css.canvas.width}px`,e.style.height=`${this.dimensions.css.cell.height}px`,e.style.lineHeight=`${this.dimensions.css.cell.height}px`,e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));const t=`${this._terminalSelector} .${p} span { display: inline-block; height: 100%; vertical-align: top;}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._screenElement.style.height=`${this.dimensions.css.canvas.height}px`}_injectCss(e){this._themeStyleElement||(this._themeStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let t=`${this._terminalSelector} .${p} { color: ${e.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px; font-kerning: none; white-space: pre}`;t+=`${this._terminalSelector} .${p} .xterm-dim { color: ${d.color.multiplyOpacity(e.foreground,.5).css};}`,t+=`${this._terminalSelector} span:not(.xterm-bold) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.xterm-bold { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.xterm-italic { font-style: italic;}`;const i=`blink_underline_${this._terminalClass}`,s=`blink_bar_${this._terminalClass}`,r=`blink_block_${this._terminalClass}`;t+=`@keyframes ${i} { 50% { border-bottom-style: hidden; }}`,t+=`@keyframes ${s} { 50% { box-shadow: none; }}`,t+=`@keyframes ${r} { 0% { background-color: ${e.cursor.css}; color: ${e.cursorAccent.css}; } 50% { background-color: inherit; color: ${e.cursor.css}; }}`,t+=`${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink.xterm-cursor-underline { animation: ${i} 1s step-end infinite;}${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink.xterm-cursor-bar { animation: ${s} 1s step-end infinite;}${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink.xterm-cursor-block { animation: ${r} 1s step-end infinite;}${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-block { background-color: ${e.cursor.css}; color: ${e.cursorAccent.css};}${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-block:not(.xterm-cursor-blink) { background-color: ${e.cursor.css} !important; color: ${e.cursorAccent.css} !important;}${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-outline { outline: 1px solid ${e.cursor.css}; outline-offset: -1px;}${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-bar { box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${e.cursor.css} inset;}${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-underline { border-bottom: 1px ${e.cursor.css}; border-bottom-style: solid; height: calc(100% - 1px);}`,t+=`${this._terminalSelector} .${C} { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .${C} div { position: absolute; background-color: ${e.selectionBackgroundOpaque.css};}${this._terminalSelector} .${C} div { position: absolute; background-color: ${e.selectionInactiveBackgroundOpaque.css};}`;for(const[i,s]of e.ansi.entries())t+=`${this._terminalSelector} .${g}${i} { color: ${s.css}; }${this._terminalSelector} .${g}${i}.xterm-dim { color: ${d.color.multiplyOpacity(s,.5).css}; }${this._terminalSelector} .${m}${i} { background-color: ${s.css}; }`;t+=`${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR} { color: ${d.color.opaque(e.background).css}; }${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR}.xterm-dim { color: ${d.color.multiplyOpacity(d.color.opaque(e.background),.5).css}; }${this._terminalSelector} .${m}${a.INVERTED_DEFAULT_COLOR} { background-color: ${e.foreground.css}; }`,this._themeStyleElement.textContent=t}_setDefaultSpacing(){const e=this.dimensions.css.cell.width-this._widthCache.get("W",!1,!1);this._rowContainer.style.letterSpacing=`${e}px`,this._rowFactory.defaultSpacing=e}handleDevicePixelRatioChange(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){const e=this._document.createElement("div");this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}handleResize(e,t){this._refreshRowElements(e,t),this._updateDimensions(),this.handleSelectionChanged(this._selectionRenderModel.selectionStart,this._selectionRenderModel.selectionEnd,this._selectionRenderModel.columnSelectMode)}handleCharSizeChanged(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}handleBlur(){this._rowContainer.classList.remove(S),this.renderRows(0,this._bufferService.rows-1)}handleFocus(){this._rowContainer.classList.add(S),this.renderRows(this._bufferService.buffer.y,this._bufferService.buffer.y)}handleSelectionChanged(e,t,i){if(this._selectionContainer.replaceChildren(),this._rowFactory.handleSelectionChanged(e,t,i),this.renderRows(0,this._bufferService.rows-1),!e||!t)return;this._selectionRenderModel.update(this._terminal,e,t,i);const s=this._selectionRenderModel.viewportStartRow,r=this._selectionRenderModel.viewportEndRow,n=this._selectionRenderModel.viewportCappedStartRow,o=this._selectionRenderModel.viewportCappedEndRow;if(n>=this._bufferService.rows||o<0)return;const a=this._document.createDocumentFragment();if(i){const i=e[0]>t[0];a.appendChild(this._createSelectionElement(n,i?t[0]:e[0],i?e[0]:t[0],o-n+1))}else{const i=s===n?e[0]:0,h=n===r?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(n,i,h));const c=o-n-1;if(a.appendChild(this._createSelectionElement(n+1,0,this._bufferService.cols,c)),n!==o){const e=r===o?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(a)}_createSelectionElement(e,t,i,s=1){const r=this._document.createElement("div"),n=t*this.dimensions.css.cell.width;let o=this.dimensions.css.cell.width*(i-t);return n+o>this.dimensions.css.canvas.width&&(o=this.dimensions.css.canvas.width-n),r.style.height=s*this.dimensions.css.cell.height+"px",r.style.top=e*this.dimensions.css.cell.height+"px",r.style.left=`${n}px`,r.style.width=`${o}px`,r}handleCursorMove(){}_handleOptionsChanged(){this._updateDimensions(),this._injectCss(this._themeService.colors),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}clear(){for(const e of this._rowElements)e.replaceChildren()}renderRows(e,t){const i=this._bufferService.buffer,s=i.ybase+i.y,r=Math.min(i.x,this._bufferService.cols-1),n=this._optionsService.rawOptions.cursorBlink,o=this._optionsService.rawOptions.cursorStyle,a=this._optionsService.rawOptions.cursorInactiveStyle;for(let h=e;h<=t;h++){const e=h+i.ydisp,t=this._rowElements[h],c=i.lines.get(e);if(!t||!c)break;t.replaceChildren(...this._rowFactory.createRow(c,e,e===s,o,a,r,n,this.dimensions.css.cell.width,this._widthCache,-1,-1))}}get _terminalSelector(){return`.${v}${this._terminalClass}`}_handleLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_handleLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,i,s,r,n){i<0&&(e=0),s<0&&(t=0);const o=this._bufferService.rows-1;i=Math.max(Math.min(i,o),0),s=Math.max(Math.min(s,o),0),r=Math.min(r,this._bufferService.cols);const a=this._bufferService.buffer,h=a.ybase+a.y,c=Math.min(a.x,r-1),l=this._optionsService.rawOptions.cursorBlink,d=this._optionsService.rawOptions.cursorStyle,_=this._optionsService.rawOptions.cursorInactiveStyle;for(let o=i;o<=s;++o){const u=o+a.ydisp,f=this._rowElements[o],v=a.lines.get(u);if(!f||!v)break;f.replaceChildren(...this._rowFactory.createRow(v,u,u===h,d,_,c,l,this.dimensions.css.cell.width,this._widthCache,n?o===i?e:0:-1,n?(o===s?t:r)-1:-1))}}};t.DomRenderer=w=s([r(7,f.IInstantiationService),r(8,l.ICharSizeService),r(9,f.IOptionsService),r(10,f.IBufferService),r(11,l.ICoreBrowserService),r(12,l.IThemeService)],w)},3787:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=void 0;const n=i(2223),o=i(643),a=i(511),h=i(2585),c=i(8055),l=i(4725),d=i(4269),_=i(6171),u=i(3734);let f=t.DomRendererRowFactory=class{constructor(e,t,i,s,r,n,o){this._document=e,this._characterJoinerService=t,this._optionsService=i,this._coreBrowserService=s,this._coreService=r,this._decorationService=n,this._themeService=o,this._workCell=new a.CellData,this._columnSelectMode=!1,this.defaultSpacing=0}handleSelectionChanged(e,t,i){this._selectionStart=e,this._selectionEnd=t,this._columnSelectMode=i}createRow(e,t,i,s,r,a,h,l,_,f,p){const g=[],m=this._characterJoinerService.getJoinedCharacters(t),S=this._themeService.colors;let C,b=e.getNoBgTrimmedLength();i&&b0&&M===m[0][0]){O=!0;const t=m.shift();I=new d.JoinedCellData(this._workCell,e.translateToString(!0,t[0],t[1]),t[1]-t[0]),P=t[1]-1,b=I.getWidth()}const H=this._isCellInSelection(M,t),F=i&&M===a,W=T&&M>=f&&M<=p;let U=!1;this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{U=!0}));let N=I.getChars()||o.WHITESPACE_CELL_CHAR;if(" "===N&&(I.isUnderline()||I.isOverline())&&(N=" "),A=b*l-_.get(N,I.isBold(),I.isItalic()),C){if(w&&(H&&x||!H&&!x&&I.bg===E)&&(H&&x&&S.selectionForeground||I.fg===k)&&I.extended.ext===L&&W===D&&A===R&&!F&&!O&&!U){I.isInvisible()?y+=o.WHITESPACE_CELL_CHAR:y+=N,w++;continue}w&&(C.textContent=y),C=this._document.createElement("span"),w=0,y=""}else C=this._document.createElement("span");if(E=I.bg,k=I.fg,L=I.extended.ext,D=W,R=A,x=H,O&&a>=M&&a<=P&&(a=M),!this._coreService.isCursorHidden&&F&&this._coreService.isCursorInitialized)if(B.push("xterm-cursor"),this._coreBrowserService.isFocused)h&&B.push("xterm-cursor-blink"),B.push("bar"===s?"xterm-cursor-bar":"underline"===s?"xterm-cursor-underline":"xterm-cursor-block");else if(r)switch(r){case"outline":B.push("xterm-cursor-outline");break;case"block":B.push("xterm-cursor-block");break;case"bar":B.push("xterm-cursor-bar");break;case"underline":B.push("xterm-cursor-underline")}if(I.isBold()&&B.push("xterm-bold"),I.isItalic()&&B.push("xterm-italic"),I.isDim()&&B.push("xterm-dim"),y=I.isInvisible()?o.WHITESPACE_CELL_CHAR:I.getChars()||o.WHITESPACE_CELL_CHAR,I.isUnderline()&&(B.push(`xterm-underline-${I.extended.underlineStyle}`)," "===y&&(y=" "),!I.isUnderlineColorDefault()))if(I.isUnderlineColorRGB())C.style.textDecorationColor=`rgb(${u.AttributeData.toColorRGB(I.getUnderlineColor()).join(",")})`;else{let e=I.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&I.isBold()&&e<8&&(e+=8),C.style.textDecorationColor=S.ansi[e].css}I.isOverline()&&(B.push("xterm-overline")," "===y&&(y=" ")),I.isStrikethrough()&&B.push("xterm-strikethrough"),W&&(C.style.textDecoration="underline");let $=I.getFgColor(),j=I.getFgColorMode(),z=I.getBgColor(),K=I.getBgColorMode();const q=!!I.isInverse();if(q){const e=$;$=z,z=e;const t=j;j=K,K=t}let V,G,X,J=!1;switch(this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{"top"!==e.options.layer&&J||(e.backgroundColorRGB&&(K=50331648,z=e.backgroundColorRGB.rgba>>8&16777215,V=e.backgroundColorRGB),e.foregroundColorRGB&&(j=50331648,$=e.foregroundColorRGB.rgba>>8&16777215,G=e.foregroundColorRGB),J="top"===e.options.layer)})),!J&&H&&(V=this._coreBrowserService.isFocused?S.selectionBackgroundOpaque:S.selectionInactiveBackgroundOpaque,z=V.rgba>>8&16777215,K=50331648,J=!0,S.selectionForeground&&(j=50331648,$=S.selectionForeground.rgba>>8&16777215,G=S.selectionForeground)),J&&B.push("xterm-decoration-top"),K){case 16777216:case 33554432:X=S.ansi[z],B.push(`xterm-bg-${z}`);break;case 50331648:X=c.channels.toColor(z>>16,z>>8&255,255&z),this._addStyle(C,`background-color:#${v((z>>>0).toString(16),"0",6)}`);break;default:q?(X=S.foreground,B.push(`xterm-bg-${n.INVERTED_DEFAULT_COLOR}`)):X=S.background}switch(V||I.isDim()&&(V=c.color.multiplyOpacity(X,.5)),j){case 16777216:case 33554432:I.isBold()&&$<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&($+=8),this._applyMinimumContrast(C,X,S.ansi[$],I,V,void 0)||B.push(`xterm-fg-${$}`);break;case 50331648:const e=c.channels.toColor($>>16&255,$>>8&255,255&$);this._applyMinimumContrast(C,X,e,I,V,G)||this._addStyle(C,`color:#${v($.toString(16),"0",6)}`);break;default:this._applyMinimumContrast(C,X,S.foreground,I,V,G)||q&&B.push(`xterm-fg-${n.INVERTED_DEFAULT_COLOR}`)}B.length&&(C.className=B.join(" "),B.length=0),F||O||U?C.textContent=y:w++,A!==this.defaultSpacing&&(C.style.letterSpacing=`${A}px`),g.push(C),M=P}return C&&w&&(C.textContent=y),g}_applyMinimumContrast(e,t,i,s,r,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,_.treatGlyphAsBackgroundColor)(s.getCode()))return!1;const o=this._getContrastCache(s);let a;if(r||n||(a=o.getColor(t.rgba,i.rgba)),void 0===a){const e=this._optionsService.rawOptions.minimumContrastRatio/(s.isDim()?2:1);a=c.color.ensureContrastRatio(r||t,n||i,e),o.setColor((r||t).rgba,(n||i).rgba,a??null)}return!!a&&(this._addStyle(e,`color:${a.css}`),!0)}_getContrastCache(e){return e.isDim()?this._themeService.colors.halfContrastCache:this._themeService.colors.contrastCache}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){const i=this._selectionStart,s=this._selectionEnd;return!(!i||!s)&&(this._columnSelectMode?i[0]<=s[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=s[0]&&t<=s[1]:t>i[1]&&t=i[0]&&e=i[0])}};function v(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.WidthCache=void 0,t.WidthCache=class{constructor(e,t){this._flat=new Float32Array(256),this._font="",this._fontSize=0,this._weight="normal",this._weightBold="bold",this._measureElements=[],this._container=e.createElement("div"),this._container.classList.add("xterm-width-cache-measure-container"),this._container.setAttribute("aria-hidden","true"),this._container.style.whiteSpace="pre",this._container.style.fontKerning="none";const i=e.createElement("span");i.classList.add("xterm-char-measure-element");const s=e.createElement("span");s.classList.add("xterm-char-measure-element"),s.style.fontWeight="bold";const r=e.createElement("span");r.classList.add("xterm-char-measure-element"),r.style.fontStyle="italic";const n=e.createElement("span");n.classList.add("xterm-char-measure-element"),n.style.fontWeight="bold",n.style.fontStyle="italic",this._measureElements=[i,s,r,n],this._container.appendChild(i),this._container.appendChild(s),this._container.appendChild(r),this._container.appendChild(n),t.appendChild(this._container),this.clear()}dispose(){this._container.remove(),this._measureElements.length=0,this._holey=void 0}clear(){this._flat.fill(-9999),this._holey=new Map}setFont(e,t,i,s){e===this._font&&t===this._fontSize&&i===this._weight&&s===this._weightBold||(this._font=e,this._fontSize=t,this._weight=i,this._weightBold=s,this._container.style.fontFamily=this._font,this._container.style.fontSize=`${this._fontSize}px`,this._measureElements[0].style.fontWeight=`${i}`,this._measureElements[1].style.fontWeight=`${s}`,this._measureElements[2].style.fontWeight=`${i}`,this._measureElements[3].style.fontWeight=`${s}`,this.clear())}get(e,t,i){let s=0;if(!t&&!i&&1===e.length&&(s=e.charCodeAt(0))<256){if(-9999!==this._flat[s])return this._flat[s];const t=this._measure(e,0);return t>0&&(this._flat[s]=t),t}let r=e;t&&(r+="B"),i&&(r+="I");let n=this._holey.get(r);if(void 0===n){let s=0;t&&(s|=1),i&&(s|=2),n=this._measure(e,s),n>0&&this._holey.set(r,n)}return n}_measure(e,t){const i=this._measureElements[t];return i.textContent=e.repeat(32),i.offsetWidth/32}}},2223:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;const s=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=s.isFirefox||s.isLegacyEdge?"bottom":"ideographic"},6171:(e,t)=>{function i(e){return 57508<=e&&e<=57558}function s(e){return e>=128512&&e<=128591||e>=127744&&e<=128511||e>=128640&&e<=128767||e>=9728&&e<=9983||e>=9984&&e<=10175||e>=65024&&e<=65039||e>=129280&&e<=129535||e>=127462&&e<=127487}Object.defineProperty(t,"__esModule",{value:!0}),t.computeNextVariantOffset=t.createRenderDimensions=t.treatGlyphAsBackgroundColor=t.allowRescaling=t.isEmoji=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw new Error("value must not be falsy");return e},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.isEmoji=s,t.allowRescaling=function(e,t,r,n){return 1===t&&r>Math.ceil(1.5*n)&&void 0!==e&&e>255&&!s(e)&&!i(e)&&!function(e){return 57344<=e&&e<=63743}(e)},t.treatGlyphAsBackgroundColor=function(e){return i(e)||function(e){return 9472<=e&&e<=9631}(e)},t.createRenderDimensions=function(){return{css:{canvas:{width:0,height:0},cell:{width:0,height:0}},device:{canvas:{width:0,height:0},cell:{width:0,height:0},char:{width:0,height:0,left:0,top:0}}}},t.computeNextVariantOffset=function(e,t,i=0){return(e-(2*Math.round(t)-i))%(2*Math.round(t))}},6052:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createSelectionRenderModel=void 0;class i{constructor(){this.clear()}clear(){this.hasSelection=!1,this.columnSelectMode=!1,this.viewportStartRow=0,this.viewportEndRow=0,this.viewportCappedStartRow=0,this.viewportCappedEndRow=0,this.startCol=0,this.endCol=0,this.selectionStart=void 0,this.selectionEnd=void 0}update(e,t,i,s=!1){if(this.selectionStart=t,this.selectionEnd=i,!t||!i||t[0]===i[0]&&t[1]===i[1])return void this.clear();const r=e.buffers.active.ydisp,n=t[1]-r,o=i[1]-r,a=Math.max(n,0),h=Math.min(o,e.rows-1);a>=e.rows||h<0?this.clear():(this.hasSelection=!0,this.columnSelectMode=s,this.viewportStartRow=n,this.viewportEndRow=o,this.viewportCappedStartRow=a,this.viewportCappedEndRow=h,this.startCol=t[0],this.endCol=i[0])}isCellSelected(e,t,i){return!!this.hasSelection&&(i-=e.buffer.active.viewportY,this.columnSelectMode?this.startCol<=this.endCol?t>=this.startCol&&i>=this.viewportCappedStartRow&&t=this.viewportCappedStartRow&&t>=this.endCol&&i<=this.viewportCappedEndRow:i>this.viewportStartRow&&i=this.startCol&&t=this.startCol)}}t.createSelectionRenderModel=function(){return new i}},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}if(this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]}return this.selectionEnd}}areSelectionValuesReversed(){const e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}handleTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;const n=i(2585),o=i(8460),a=i(844);let h=t.CharSizeService=class extends a.Disposable{get hasValidSize(){return this.width>0&&this.height>0}constructor(e,t,i){super(),this._optionsService=i,this.width=0,this.height=0,this._onCharSizeChange=this.register(new o.EventEmitter),this.onCharSizeChange=this._onCharSizeChange.event;try{this._measureStrategy=this.register(new d(this._optionsService))}catch{this._measureStrategy=this.register(new l(e,t,this._optionsService))}this.register(this._optionsService.onMultipleOptionChange(["fontFamily","fontSize"],(()=>this.measure())))}measure(){const e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())}};t.CharSizeService=h=s([r(2,n.IOptionsService)],h);class c extends a.Disposable{constructor(){super(...arguments),this._result={width:0,height:0}}_validateAndSet(e,t){void 0!==e&&e>0&&void 0!==t&&t>0&&(this._result.width=e,this._result.height=t)}}class l extends c{constructor(e,t,i){super(),this._document=e,this._parentElement=t,this._optionsService=i,this._measureElement=this._document.createElement("span"),this._measureElement.classList.add("xterm-char-measure-element"),this._measureElement.textContent="W".repeat(32),this._measureElement.setAttribute("aria-hidden","true"),this._measureElement.style.whiteSpace="pre",this._measureElement.style.fontKerning="none",this._parentElement.appendChild(this._measureElement)}measure(){return this._measureElement.style.fontFamily=this._optionsService.rawOptions.fontFamily,this._measureElement.style.fontSize=`${this._optionsService.rawOptions.fontSize}px`,this._validateAndSet(Number(this._measureElement.offsetWidth)/32,Number(this._measureElement.offsetHeight)),this._result}}class d extends c{constructor(e){super(),this._optionsService=e,this._canvas=new OffscreenCanvas(100,100),this._ctx=this._canvas.getContext("2d");const t=this._ctx.measureText("W");if(!("width"in t&&"fontBoundingBoxAscent"in t&&"fontBoundingBoxDescent"in t))throw new Error("Required font metrics not supported")}measure(){this._ctx.font=`${this._optionsService.rawOptions.fontSize}px ${this._optionsService.rawOptions.fontFamily}`;const e=this._ctx.measureText("W");return this._validateAndSet(e.width,e.fontBoundingBoxAscent+e.fontBoundingBoxDescent),this._result}}},4269:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;const n=i(3734),o=i(643),a=i(511),h=i(2585);class c extends n.AttributeData{constructor(e,t,i){super(),this.content=0,this.combinedData="",this.fg=e.fg,this.bg=e.bg,this.combinedData=t,this._width=i}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(e){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.JoinedCellData=c;let l=t.CharacterJoinerService=class e{constructor(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new a.CellData}register(e){const t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id}deregister(e){for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0;const s=i(844),r=i(8460),n=i(3656);class o extends s.Disposable{constructor(e,t,i){super(),this._textarea=e,this._window=t,this.mainDocument=i,this._isFocused=!1,this._cachedIsFocused=void 0,this._screenDprMonitor=new a(this._window),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._onWindowChange=this.register(new r.EventEmitter),this.onWindowChange=this._onWindowChange.event,this.register(this.onWindowChange((e=>this._screenDprMonitor.setWindow(e)))),this.register((0,r.forwardEvent)(this._screenDprMonitor.onDprChange,this._onDprChange)),this._textarea.addEventListener("focus",(()=>this._isFocused=!0)),this._textarea.addEventListener("blur",(()=>this._isFocused=!1))}get window(){return this._window}set window(e){this._window!==e&&(this._window=e,this._onWindowChange.fire(this._window))}get dpr(){return this.window.devicePixelRatio}get isFocused(){return void 0===this._cachedIsFocused&&(this._cachedIsFocused=this._isFocused&&this._textarea.ownerDocument.hasFocus(),queueMicrotask((()=>this._cachedIsFocused=void 0))),this._cachedIsFocused}}t.CoreBrowserService=o;class a extends s.Disposable{constructor(e){super(),this._parentWindow=e,this._windowResizeListener=this.register(new s.MutableDisposable),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._outerListener=()=>this._setDprAndFireIfDiffers(),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._updateDpr(),this._setWindowResizeListener(),this.register((0,s.toDisposable)((()=>this.clearListener())))}setWindow(e){this._parentWindow=e,this._setWindowResizeListener(),this._setDprAndFireIfDiffers()}_setWindowResizeListener(){this._windowResizeListener.value=(0,n.addDisposableDomListener)(this._parentWindow,"resize",(()=>this._setDprAndFireIfDiffers()))}_setDprAndFireIfDiffers(){this._parentWindow.devicePixelRatio!==this._currentDevicePixelRatio&&this._onDprChange.fire(this._parentWindow.devicePixelRatio),this._updateDpr()}_updateDpr(){this._outerListener&&(this._resolutionMediaMatchList?.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._outerListener=void 0)}}},779:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkProviderService=void 0;const s=i(844);class r extends s.Disposable{constructor(){super(),this.linkProviders=[],this.register((0,s.toDisposable)((()=>this.linkProviders.length=0)))}registerLinkProvider(e){return this.linkProviders.push(e),{dispose:()=>{const t=this.linkProviders.indexOf(e);-1!==t&&this.linkProviders.splice(t,1)}}}}t.LinkProviderService=r},8934:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;const n=i(4725),o=i(9806);let a=t.MouseService=class{constructor(e,t){this._renderService=e,this._charSizeService=t}getCoords(e,t,i,s,r){return(0,o.getCoords)(window,e,t,i,s,this._charSizeService.hasValidSize,this._renderService.dimensions.css.cell.width,this._renderService.dimensions.css.cell.height,r)}getMouseReportCoords(e,t){const i=(0,o.getCoordsRelativeToElement)(window,e,t);if(this._charSizeService.hasValidSize)return i[0]=Math.min(Math.max(i[0],0),this._renderService.dimensions.css.canvas.width-1),i[1]=Math.min(Math.max(i[1],0),this._renderService.dimensions.css.canvas.height-1),{col:Math.floor(i[0]/this._renderService.dimensions.css.cell.width),row:Math.floor(i[1]/this._renderService.dimensions.css.cell.height),x:Math.floor(i[0]),y:Math.floor(i[1])}}};t.MouseService=a=s([r(0,n.IRenderService),r(1,n.ICharSizeService)],a)},3230:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;const n=i(6193),o=i(4725),a=i(8460),h=i(844),c=i(7226),l=i(2585);let d=t.RenderService=class extends h.Disposable{get dimensions(){return this._renderer.value.dimensions}constructor(e,t,i,s,r,o,l,d){super(),this._rowCount=e,this._charSizeService=s,this._renderer=this.register(new h.MutableDisposable),this._pausedResizeTask=new c.DebouncedIdleTask,this._observerDisposable=this.register(new h.MutableDisposable),this._isPaused=!1,this._needsFullRefresh=!1,this._isNextRenderRedrawOnly=!0,this._needsSelectionRefresh=!1,this._canvasWidth=0,this._canvasHeight=0,this._selectionState={start:void 0,end:void 0,columnSelectMode:!1},this._onDimensionsChange=this.register(new a.EventEmitter),this.onDimensionsChange=this._onDimensionsChange.event,this._onRenderedViewportChange=this.register(new a.EventEmitter),this.onRenderedViewportChange=this._onRenderedViewportChange.event,this._onRender=this.register(new a.EventEmitter),this.onRender=this._onRender.event,this._onRefreshRequest=this.register(new a.EventEmitter),this.onRefreshRequest=this._onRefreshRequest.event,this._renderDebouncer=new n.RenderDebouncer(((e,t)=>this._renderRows(e,t)),l),this.register(this._renderDebouncer),this.register(l.onDprChange((()=>this.handleDevicePixelRatioChange()))),this.register(o.onResize((()=>this._fullRefresh()))),this.register(o.buffers.onBufferActivate((()=>this._renderer.value?.clear()))),this.register(i.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._charSizeService.onCharSizeChange((()=>this.handleCharSizeChanged()))),this.register(r.onDecorationRegistered((()=>this._fullRefresh()))),this.register(r.onDecorationRemoved((()=>this._fullRefresh()))),this.register(i.onMultipleOptionChange(["customGlyphs","drawBoldTextInBrightColors","letterSpacing","lineHeight","fontFamily","fontSize","fontWeight","fontWeightBold","minimumContrastRatio","rescaleOverlappingGlyphs"],(()=>{this.clear(),this.handleResize(o.cols,o.rows),this._fullRefresh()}))),this.register(i.onMultipleOptionChange(["cursorBlink","cursorStyle"],(()=>this.refreshRows(o.buffer.y,o.buffer.y,!0)))),this.register(d.onChangeColors((()=>this._fullRefresh()))),this._registerIntersectionObserver(l.window,t),this.register(l.onWindowChange((e=>this._registerIntersectionObserver(e,t))))}_registerIntersectionObserver(e,t){if("IntersectionObserver"in e){const i=new e.IntersectionObserver((e=>this._handleIntersectionChange(e[e.length-1])),{threshold:0});i.observe(t),this._observerDisposable.value=(0,h.toDisposable)((()=>i.disconnect()))}}_handleIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this._pausedResizeTask.flush(),this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.value&&(e=Math.min(e,this._rowCount-1),t=Math.min(t,this._rowCount-1),this._renderer.value.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.value.handleSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0)}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.value&&(this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize())}_fireOnCanvasResize(){this._renderer.value&&(this._renderer.value.dimensions.css.canvas.width===this._canvasWidth&&this._renderer.value.dimensions.css.canvas.height===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.value.dimensions))}hasRenderer(){return!!this._renderer.value}setRenderer(e){this._renderer.value=e,this._renderer.value&&(this._renderer.value.onRequestRedraw((e=>this.refreshRows(e.start,e.end,!0))),this._needsSelectionRefresh=!0,this._fullRefresh())}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){this._renderer.value&&(this._renderer.value.clearTextureAtlas?.(),this._fullRefresh())}handleDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.value&&(this._renderer.value.handleDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1))}handleResize(e,t){this._renderer.value&&(this._isPaused?this._pausedResizeTask.set((()=>this._renderer.value?.handleResize(e,t))):this._renderer.value.handleResize(e,t),this._fullRefresh())}handleCharSizeChanged(){this._renderer.value?.handleCharSizeChanged()}handleBlur(){this._renderer.value?.handleBlur()}handleFocus(){this._renderer.value?.handleFocus()}handleSelectionChanged(e,t,i){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,this._renderer.value?.handleSelectionChanged(e,t,i)}handleCursorMove(){this._renderer.value?.handleCursorMove()}clear(){this._renderer.value?.clear()}};t.RenderService=d=s([r(2,l.IOptionsService),r(3,o.ICharSizeService),r(4,l.IDecorationService),r(5,l.IBufferService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],d)},9312:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;const n=i(9806),o=i(9504),a=i(456),h=i(4725),c=i(8460),l=i(844),d=i(6114),_=i(4841),u=i(511),f=i(2585),v=String.fromCharCode(160),p=new RegExp(v,"g");let g=t.SelectionService=class extends l.Disposable{constructor(e,t,i,s,r,n,o,h,d){super(),this._element=e,this._screenElement=t,this._linkifier=i,this._bufferService=s,this._coreService=r,this._mouseService=n,this._optionsService=o,this._renderService=h,this._coreBrowserService=d,this._dragScrollAmount=0,this._enabled=!0,this._workCell=new u.CellData,this._mouseDownTimeStamp=0,this._oldHasSelection=!1,this._oldSelectionStart=void 0,this._oldSelectionEnd=void 0,this._onLinuxMouseSelection=this.register(new c.EventEmitter),this.onLinuxMouseSelection=this._onLinuxMouseSelection.event,this._onRedrawRequest=this.register(new c.EventEmitter),this.onRequestRedraw=this._onRedrawRequest.event,this._onSelectionChange=this.register(new c.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onRequestScrollLines=this.register(new c.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this._mouseMoveListener=e=>this._handleMouseMove(e),this._mouseUpListener=e=>this._handleMouseUp(e),this._coreService.onUserInput((()=>{this.hasSelection&&this.clearSelection()})),this._trimListener=this._bufferService.buffer.lines.onTrim((e=>this._handleTrim(e))),this.register(this._bufferService.buffers.onBufferActivate((e=>this._handleBufferActivate(e)))),this.enable(),this._model=new a.SelectionModel(this._bufferService),this._activeSelectionMode=0,this.register((0,l.toDisposable)((()=>{this._removeMouseDownListeners()})))}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return"";const i=this._bufferService.buffer,s=[];if(3===this._activeSelectionMode){if(e[0]===t[0])return"";const r=e[0]e.replace(p," "))).join(d.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._refresh()))),d.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){const t=this._getMouseBufferCoords(e),i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!!(i&&s&&t)&&this._areCoordsInSelection(t,i,s)}isCellInSelection(e,t){const i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!(!i||!s)&&this._areCoordsInSelection([e,t],i,s)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){const i=this._linkifier.currentLink?.link?.range;if(i)return this._model.selectionStart=[i.start.x-1,i.start.y-1],this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols),this._model.selectionEnd=void 0,!0;const s=this._getMouseBufferCoords(e);return!!s&&(this._selectWordAt(s,t),this._model.selectionEnd=void 0,!0)}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_handleTrim(e){this._model.handleTrim(e)&&this.refresh()}_getMouseBufferCoords(e){const t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(t)return t[0]--,t[1]--,t[1]+=this._bufferService.buffer.ydisp,t}_getMouseEventScrollAmount(e){let t=(0,n.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];const i=this._renderService.dimensions.css.canvas.height;return t>=0&&t<=i?0:(t>i&&(t-=i),t=Math.min(Math.max(t,-50),50),t/=50,t/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return d.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}handleMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._handleIncrementalClick(e):1===e.detail?this._handleSingleClick(e):2===e.detail?this._handleDoubleClick(e):3===e.detail&&this._handleTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval((()=>this._dragScroll()),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_handleIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_handleSingleClick(e){if(this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),!this._model.selectionStart)return;this._model.selectionEnd=void 0;const t=this._bufferService.buffer.lines.get(this._model.selectionStart[1]);t&&t.length!==this._model.selectionStart[0]&&0===t.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_handleDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_handleTripleClick(e){const t=this._getMouseBufferCoords(e);t&&(this._activeSelectionMode=2,this._selectLineAt(t[1]))}shouldColumnSelect(e){return e.altKey&&!(d.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_handleMouseMove(e){if(e.stopImmediatePropagation(),!this._model.selectionStart)return;const t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),!this._model.selectionEnd)return void this.refresh(!0);2===this._activeSelectionMode?this._model.selectionEnd[1]0?this._model.selectionEnd[0]=this._bufferService.cols:this._dragScrollAmount<0&&(this._model.selectionEnd[0]=0));const i=this._bufferService.buffer;if(this._model.selectionEnd[1]0?(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=this._bufferService.cols),this._model.selectionEnd[1]=Math.min(e.ydisp+this._bufferService.rows,e.lines.length-1)):(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=0),this._model.selectionEnd[1]=e.ydisp),this.refresh()}}_handleMouseUp(e){const t=e.timeStamp-this._mouseDownTimeStamp;if(this._removeMouseDownListeners(),this.selectionText.length<=1&&t<500&&e.altKey&&this._optionsService.rawOptions.altClickMovesCursor){if(this._bufferService.buffer.ybase===this._bufferService.buffer.ydisp){const t=this._mouseService.getCoords(e,this._element,this._bufferService.cols,this._bufferService.rows,!1);if(t&&void 0!==t[0]&&void 0!==t[1]){const e=(0,o.moveToCellSequence)(t[0]-1,t[1]-1,this._bufferService,this._coreService.decPrivateModes.applicationCursorKeys);this._coreService.triggerDataEvent(e,!0)}}}else this._fireEventIfSelectionChanged()}_fireEventIfSelectionChanged(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd,i=!(!e||!t||e[0]===t[0]&&e[1]===t[1]);i?e&&t&&(this._oldSelectionStart&&this._oldSelectionEnd&&e[0]===this._oldSelectionStart[0]&&e[1]===this._oldSelectionStart[1]&&t[0]===this._oldSelectionEnd[0]&&t[1]===this._oldSelectionEnd[1]||this._fireOnSelectionChange(e,t,i)):this._oldHasSelection&&this._fireOnSelectionChange(e,t,i)}_fireOnSelectionChange(e,t,i){this._oldSelectionStart=e,this._oldSelectionEnd=t,this._oldHasSelection=i,this._onSelectionChange.fire()}_handleBufferActivate(e){this.clearSelection(),this._trimListener.dispose(),this._trimListener=e.activeBuffer.lines.onTrim((e=>this._handleTrim(e)))}_convertViewportColToCharacterIndex(e,t){let i=t;for(let s=0;t>=s;s++){const r=e.loadCell(s,this._workCell).getChars().length;0===this._workCell.getWidth()?i--:r>1&&t!==s&&(i+=r-1)}return i}setSelection(e,t,i){this._model.clearSelection(),this._removeMouseDownListeners(),this._model.selectionStart=[e,t],this._model.selectionStartLength=i,this.refresh(),this._fireEventIfSelectionChanged()}rightClickSelect(e){this._isClickInSelection(e)||(this._selectWordAtCursor(e,!1)&&this.refresh(!0),this._fireEventIfSelectionChanged())}_getWordAt(e,t,i=!0,s=!0){if(e[0]>=this._bufferService.cols)return;const r=this._bufferService.buffer,n=r.lines.get(e[1]);if(!n)return;const o=r.translateBufferLineToString(e[1],!1);let a=this._convertViewportColToCharacterIndex(n,e[0]),h=a;const c=e[0]-a;let l=0,d=0,_=0,u=0;if(" "===o.charAt(a)){for(;a>0&&" "===o.charAt(a-1);)a--;for(;h1&&(u+=s-1,h+=s-1);t>0&&a>0&&!this._isCharWordSeparator(n.loadCell(t-1,this._workCell));){n.loadCell(t-1,this._workCell);const e=this._workCell.getChars().length;0===this._workCell.getWidth()?(l++,t--):e>1&&(_+=e-1,a-=e-1),a--,t--}for(;i1&&(u+=e-1,h+=e-1),h++,i++}}h++;let f=a+c-l+_,v=Math.min(this._bufferService.cols,h-a+l+d-_-u);if(t||""!==o.slice(a,h).trim()){if(i&&0===f&&32!==n.getCodePoint(0)){const t=r.lines.get(e[1]-1);if(t&&n.isWrapped&&32!==t.getCodePoint(this._bufferService.cols-1)){const t=this._getWordAt([this._bufferService.cols-1,e[1]-1],!1,!0,!1);if(t){const e=this._bufferService.cols-t.start;f-=e,v+=e}}}if(s&&f+v===this._bufferService.cols&&32!==n.getCodePoint(this._bufferService.cols-1)){const t=r.lines.get(e[1]+1);if(t?.isWrapped&&32!==t.getCodePoint(0)){const t=this._getWordAt([0,e[1]+1],!1,!1,!0);t&&(v+=t.length)}}return{start:f,length:v}}}_selectWordAt(e,t){const i=this._getWordAt(e,t);if(i){for(;i.start<0;)i.start+=this._bufferService.cols,e[1]--;this._model.selectionStart=[i.start,e[1]],this._model.selectionStartLength=i.length}}_selectToWordAt(e){const t=this._getWordAt(e,!0);if(t){let i=e[1];for(;t.start<0;)t.start+=this._bufferService.cols,i--;if(!this._model.areSelectionValuesReversed())for(;t.start+t.length>this._bufferService.cols;)t.length-=this._bufferService.cols,i++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?t.start:t.start+t.length,i]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())>=0}_selectLineAt(e){const t=this._bufferService.buffer.getWrappedRangeForLine(e),i={start:{x:0,y:t.first},end:{x:this._bufferService.cols-1,y:t.last}};this._model.selectionStart=[0,t.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols)}};t.SelectionService=g=s([r(3,f.IBufferService),r(4,f.ICoreService),r(5,h.IMouseService),r(6,f.IOptionsService),r(7,h.IRenderService),r(8,h.ICoreBrowserService)],g)},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ILinkProviderService=t.IThemeService=t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;const s=i(8343);t.ICharSizeService=(0,s.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,s.createDecorator)("CoreBrowserService"),t.IMouseService=(0,s.createDecorator)("MouseService"),t.IRenderService=(0,s.createDecorator)("RenderService"),t.ISelectionService=(0,s.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,s.createDecorator)("CharacterJoinerService"),t.IThemeService=(0,s.createDecorator)("ThemeService"),t.ILinkProviderService=(0,s.createDecorator)("LinkProviderService")},6731:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.ThemeService=t.DEFAULT_ANSI_COLORS=void 0;const n=i(7239),o=i(8055),a=i(8460),h=i(844),c=i(2585),l=o.css.toColor("#ffffff"),d=o.css.toColor("#000000"),_=o.css.toColor("#ffffff"),u=o.css.toColor("#000000"),f={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};t.DEFAULT_ANSI_COLORS=Object.freeze((()=>{const e=[o.css.toColor("#2e3436"),o.css.toColor("#cc0000"),o.css.toColor("#4e9a06"),o.css.toColor("#c4a000"),o.css.toColor("#3465a4"),o.css.toColor("#75507b"),o.css.toColor("#06989a"),o.css.toColor("#d3d7cf"),o.css.toColor("#555753"),o.css.toColor("#ef2929"),o.css.toColor("#8ae234"),o.css.toColor("#fce94f"),o.css.toColor("#729fcf"),o.css.toColor("#ad7fa8"),o.css.toColor("#34e2e2"),o.css.toColor("#eeeeec")],t=[0,95,135,175,215,255];for(let i=0;i<216;i++){const s=t[i/36%6|0],r=t[i/6%6|0],n=t[i%6];e.push({css:o.channels.toCss(s,r,n),rgba:o.channels.toRgba(s,r,n)})}for(let t=0;t<24;t++){const i=8+10*t;e.push({css:o.channels.toCss(i,i,i),rgba:o.channels.toRgba(i,i,i)})}return e})());let v=t.ThemeService=class extends h.Disposable{get colors(){return this._colors}constructor(e){super(),this._optionsService=e,this._contrastCache=new n.ColorContrastCache,this._halfContrastCache=new n.ColorContrastCache,this._onChangeColors=this.register(new a.EventEmitter),this.onChangeColors=this._onChangeColors.event,this._colors={foreground:l,background:d,cursor:_,cursorAccent:u,selectionForeground:void 0,selectionBackgroundTransparent:f,selectionBackgroundOpaque:o.color.blend(d,f),selectionInactiveBackgroundTransparent:f,selectionInactiveBackgroundOpaque:o.color.blend(d,f),ansi:t.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache,halfContrastCache:this._halfContrastCache},this._updateRestoreColors(),this._setTheme(this._optionsService.rawOptions.theme),this.register(this._optionsService.onSpecificOptionChange("minimumContrastRatio",(()=>this._contrastCache.clear()))),this.register(this._optionsService.onSpecificOptionChange("theme",(()=>this._setTheme(this._optionsService.rawOptions.theme))))}_setTheme(e={}){const i=this._colors;if(i.foreground=p(e.foreground,l),i.background=p(e.background,d),i.cursor=p(e.cursor,_),i.cursorAccent=p(e.cursorAccent,u),i.selectionBackgroundTransparent=p(e.selectionBackground,f),i.selectionBackgroundOpaque=o.color.blend(i.background,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundTransparent=p(e.selectionInactiveBackground,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundOpaque=o.color.blend(i.background,i.selectionInactiveBackgroundTransparent),i.selectionForeground=e.selectionForeground?p(e.selectionForeground,o.NULL_COLOR):void 0,i.selectionForeground===o.NULL_COLOR&&(i.selectionForeground=void 0),o.color.isOpaque(i.selectionBackgroundTransparent)){const e=.3;i.selectionBackgroundTransparent=o.color.opacity(i.selectionBackgroundTransparent,e)}if(o.color.isOpaque(i.selectionInactiveBackgroundTransparent)){const e=.3;i.selectionInactiveBackgroundTransparent=o.color.opacity(i.selectionInactiveBackgroundTransparent,e)}if(i.ansi=t.DEFAULT_ANSI_COLORS.slice(),i.ansi[0]=p(e.black,t.DEFAULT_ANSI_COLORS[0]),i.ansi[1]=p(e.red,t.DEFAULT_ANSI_COLORS[1]),i.ansi[2]=p(e.green,t.DEFAULT_ANSI_COLORS[2]),i.ansi[3]=p(e.yellow,t.DEFAULT_ANSI_COLORS[3]),i.ansi[4]=p(e.blue,t.DEFAULT_ANSI_COLORS[4]),i.ansi[5]=p(e.magenta,t.DEFAULT_ANSI_COLORS[5]),i.ansi[6]=p(e.cyan,t.DEFAULT_ANSI_COLORS[6]),i.ansi[7]=p(e.white,t.DEFAULT_ANSI_COLORS[7]),i.ansi[8]=p(e.brightBlack,t.DEFAULT_ANSI_COLORS[8]),i.ansi[9]=p(e.brightRed,t.DEFAULT_ANSI_COLORS[9]),i.ansi[10]=p(e.brightGreen,t.DEFAULT_ANSI_COLORS[10]),i.ansi[11]=p(e.brightYellow,t.DEFAULT_ANSI_COLORS[11]),i.ansi[12]=p(e.brightBlue,t.DEFAULT_ANSI_COLORS[12]),i.ansi[13]=p(e.brightMagenta,t.DEFAULT_ANSI_COLORS[13]),i.ansi[14]=p(e.brightCyan,t.DEFAULT_ANSI_COLORS[14]),i.ansi[15]=p(e.brightWhite,t.DEFAULT_ANSI_COLORS[15]),e.extendedAnsi){const s=Math.min(i.ansi.length-16,e.extendedAnsi.length);for(let r=0;r{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._maxLength=e,this.onDeleteEmitter=this.register(new s.EventEmitter),this.onDelete=this.onDeleteEmitter.event,this.onInsertEmitter=this.register(new s.EventEmitter),this.onInsert=this.onInsertEmitter.event,this.onTrimEmitter=this.register(new s.EventEmitter),this.onTrim=this.onTrimEmitter.event,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get maxLength(){return this._maxLength}set maxLength(e){if(this._maxLength===e)return;const t=new Array(e);for(let i=0;ithis._length)for(let t=this._length;t=e;t--)this._array[this._getCyclicIndex(t+i.length)]=this._array[this._getCyclicIndex(t)];for(let t=0;tthis._maxLength){const e=this._length+i.length-this._maxLength;this._startIndex+=e,this._length=this._maxLength,this.onTrimEmitter.fire(e)}else this._length+=i.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(e,t,i){if(!(t<=0)){if(e<0||e>=this._length)throw new Error("start argument out of range");if(e+i<0)throw new Error("Cannot shift elements in list beyond index 0");if(i>0){for(let s=t-1;s>=0;s--)this.set(e+s+i,this.get(e+s));const s=e+t+i-this._length;if(s>0)for(this._length+=s;this._length>this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let s=0;s{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;const s=Array.isArray(t)?[]:{};for(const r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=t.NULL_COLOR=void 0;let i=0,s=0,r=0,n=0;var o,a,h,c,l;function d(e){const t=e.toString(16);return t.length<2?"0"+t:t}function _(e,t){return e>>0},e.toColor=function(t,i,s,r){return{css:e.toCss(t,i,s,r),rgba:e.toRgba(t,i,s,r)}}}(o||(t.channels=o={})),function(e){function t(e,t){return n=Math.round(255*t),[i,s,r]=l.toChannels(e.rgba),{css:o.toCss(i,s,r,n),rgba:o.toRgba(i,s,r,n)}}e.blend=function(e,t){if(n=(255&t.rgba)/255,1===n)return{css:t.css,rgba:t.rgba};const a=t.rgba>>24&255,h=t.rgba>>16&255,c=t.rgba>>8&255,l=e.rgba>>24&255,d=e.rgba>>16&255,_=e.rgba>>8&255;return i=l+Math.round((a-l)*n),s=d+Math.round((h-d)*n),r=_+Math.round((c-_)*n),{css:o.toCss(i,s,r),rgba:o.toRgba(i,s,r)}},e.isOpaque=function(e){return!(255&~e.rgba)},e.ensureContrastRatio=function(e,t,i){const s=l.ensureContrastRatio(e.rgba,t.rgba,i);if(s)return o.toColor(s>>24&255,s>>16&255,s>>8&255)},e.opaque=function(e){const t=(255|e.rgba)>>>0;return[i,s,r]=l.toChannels(t),{css:o.toCss(i,s,r),rgba:t}},e.opacity=t,e.multiplyOpacity=function(e,i){return n=255&e.rgba,t(e,n*i/255)},e.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]}}(a||(t.color=a={})),function(e){let t,a;try{const e=document.createElement("canvas");e.width=1,e.height=1;const i=e.getContext("2d",{willReadFrequently:!0});i&&(t=i,t.globalCompositeOperation="copy",a=t.createLinearGradient(0,0,1,1))}catch{}e.toColor=function(e){if(e.match(/#[\da-f]{3,8}/i))switch(e.length){case 4:return i=parseInt(e.slice(1,2).repeat(2),16),s=parseInt(e.slice(2,3).repeat(2),16),r=parseInt(e.slice(3,4).repeat(2),16),o.toColor(i,s,r);case 5:return i=parseInt(e.slice(1,2).repeat(2),16),s=parseInt(e.slice(2,3).repeat(2),16),r=parseInt(e.slice(3,4).repeat(2),16),n=parseInt(e.slice(4,5).repeat(2),16),o.toColor(i,s,r,n);case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}const h=e.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(h)return i=parseInt(h[1]),s=parseInt(h[2]),r=parseInt(h[3]),n=Math.round(255*(void 0===h[5]?1:parseFloat(h[5]))),o.toColor(i,s,r,n);if(!t||!a)throw new Error("css.toColor: Unsupported css format");if(t.fillStyle=a,t.fillStyle=e,"string"!=typeof t.fillStyle)throw new Error("css.toColor: Unsupported css format");if(t.fillRect(0,0,1,1),[i,s,r,n]=t.getImageData(0,0,1,1).data,255!==n)throw new Error("css.toColor: Unsupported css format");return{rgba:o.toRgba(i,s,r,n),css:e}}}(h||(t.css=h={})),function(e){function t(e,t,i){const s=e/255,r=t/255,n=i/255;return.2126*(s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4))+.7152*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))+.0722*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}e.relativeLuminance=function(e){return t(e>>16&255,e>>8&255,255&e)},e.relativeLuminance2=t}(c||(t.rgb=c={})),function(e){function t(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=_(c.relativeLuminance2(o,a,h),c.relativeLuminance2(s,r,n));for(;l0||a>0||h>0);)o-=Math.max(0,Math.ceil(.1*o)),a-=Math.max(0,Math.ceil(.1*a)),h-=Math.max(0,Math.ceil(.1*h)),l=_(c.relativeLuminance2(o,a,h),c.relativeLuminance2(s,r,n));return(o<<24|a<<16|h<<8|255)>>>0}function a(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=_(c.relativeLuminance2(o,a,h),c.relativeLuminance2(s,r,n));for(;l>>0}e.blend=function(e,t){if(n=(255&t)/255,1===n)return t;const a=t>>24&255,h=t>>16&255,c=t>>8&255,l=e>>24&255,d=e>>16&255,_=e>>8&255;return i=l+Math.round((a-l)*n),s=d+Math.round((h-d)*n),r=_+Math.round((c-_)*n),o.toRgba(i,s,r)},e.ensureContrastRatio=function(e,i,s){const r=c.relativeLuminance(e>>8),n=c.relativeLuminance(i>>8);if(_(r,n)>8));if(o_(r,c.relativeLuminance(t>>8))?n:t}return n}const o=a(e,i,s),h=_(r,c.relativeLuminance(o>>8));if(h_(r,c.relativeLuminance(n>>8))?o:n}return o}},e.reduceLuminance=t,e.increaseLuminance=a,e.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]}}(l||(t.rgba=l={})),t.toPaddedHex=d,t.contrastRatio=_},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;const s=i(844),r=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),c=i(6975),l=i(8460),d=i(1753),_=i(1480),u=i(7994),f=i(9282),v=i(5435),p=i(5981),g=i(2660);let m=!1;class S extends s.Disposable{get onScroll(){return this._onScrollApi||(this._onScrollApi=this.register(new l.EventEmitter),this._onScroll.event((e=>{this._onScrollApi?.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(const t in e)this.optionsService.options[t]=e[t]}constructor(e){super(),this._windowsWrappingHeuristics=this.register(new s.MutableDisposable),this._onBinary=this.register(new l.EventEmitter),this.onBinary=this._onBinary.event,this._onData=this.register(new l.EventEmitter),this.onData=this._onData.event,this._onLineFeed=this.register(new l.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onResize=this.register(new l.EventEmitter),this.onResize=this._onResize.event,this._onWriteParsed=this.register(new l.EventEmitter),this.onWriteParsed=this._onWriteParsed.event,this._onScroll=this.register(new l.EventEmitter),this._instantiationService=new n.InstantiationService,this.optionsService=this.register(new h.OptionsService(e)),this._instantiationService.setService(r.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(r.IBufferService,this._bufferService),this._logService=this.register(this._instantiationService.createInstance(o.LogService)),this._instantiationService.setService(r.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(c.CoreService)),this._instantiationService.setService(r.ICoreService,this.coreService),this.coreMouseService=this.register(this._instantiationService.createInstance(d.CoreMouseService)),this._instantiationService.setService(r.ICoreMouseService,this.coreMouseService),this.unicodeService=this.register(this._instantiationService.createInstance(_.UnicodeService)),this._instantiationService.setService(r.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(u.CharsetService),this._instantiationService.setService(r.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(g.OscLinkService),this._instantiationService.setService(r.IOscLinkService,this._oscLinkService),this._inputHandler=this.register(new v.InputHandler(this._bufferService,this._charsetService,this.coreService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService)),this.register((0,l.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,l.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,l.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,l.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.coreService.onRequestScrollToBottom((()=>this.scrollToBottom()))),this.register(this.coreService.onUserInput((()=>this._writeBuffer.handleUserInput()))),this.register(this.optionsService.onMultipleOptionChange(["windowsMode","windowsPty"],(()=>this._handleWindowsPtyOptionChange()))),this.register(this._bufferService.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this.register(this._inputHandler.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this._writeBuffer=this.register(new p.WriteBuffer(((e,t)=>this._inputHandler.parse(e,t)))),this.register((0,l.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=r.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}input(e,t=!0){this.coreService.triggerDataEvent(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this._bufferService.buffer.ydisp)}scrollToBottom(){this.scrollLines(this._bufferService.buffer.ybase-this._bufferService.buffer.ydisp)}scrollToLine(e){const t=e-this._bufferService.buffer.ydisp;0!==t&&this.scrollLines(t)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this._handleWindowsPtyOptionChange()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_handleWindowsPtyOptionChange(){let e=!1;const t=this.optionsService.rawOptions.windowsPty;t&&void 0!==t.buildNumber&&void 0!==t.buildNumber?e=!!("conpty"===t.backend&&t.buildNumber<21376):this.optionsService.rawOptions.windowsMode&&(e=!0),e?this._enableWindowsWrappingHeuristics():this._windowsWrappingHeuristics.clear()}_enableWindowsWrappingHeuristics(){if(!this._windowsWrappingHeuristics.value){const e=[];e.push(this.onLineFeed(f.updateWindowsModeWrappedState.bind(null,this._bufferService))),e.push(this.registerCsiHandler({final:"H"},(()=>((0,f.updateWindowsModeWrappedState)(this._bufferService),!1)))),this._windowsWrappingHeuristics.value=(0,s.toDisposable)((()=>{for(const t of e)t.dispose()}))}}}t.CoreTerminal=S},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.runAndSubscribe=t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;tt.fire(e)))},t.runAndSubscribe=function(e,t){return t(void 0),e((e=>t(e)))}},5435:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;const n=i(2584),o=i(7116),a=i(2015),h=i(844),c=i(482),l=i(8437),d=i(8460),_=i(643),u=i(511),f=i(3734),v=i(2585),p=i(1480),g=i(6242),m=i(6351),S=i(5941),C={"(":0,")":1,"*":2,"+":3,"-":1,".":2},b=131072;function w(e,t){if(e>24)return t.setWinLines||!1;switch(e){case 1:return!!t.restoreWin;case 2:return!!t.minimizeWin;case 3:return!!t.setWinPosition;case 4:return!!t.setWinSizePixels;case 5:return!!t.raiseWin;case 6:return!!t.lowerWin;case 7:return!!t.refreshWin;case 8:return!!t.setWinSizeChars;case 9:return!!t.maximizeWin;case 10:return!!t.fullscreenWin;case 11:return!!t.getWinState;case 13:return!!t.getWinPosition;case 14:return!!t.getWinSizePixels;case 15:return!!t.getScreenSizePixels;case 16:return!!t.getCellSizePixels;case 18:return!!t.getWinSizeChars;case 19:return!!t.getScreenSizeChars;case 20:return!!t.getIconTitle;case 21:return!!t.getWinTitle;case 22:return!!t.pushTitle;case 23:return!!t.popTitle;case 24:return!!t.setWinLines}return!1}var y;!function(e){e[e.GET_WIN_SIZE_PIXELS=0]="GET_WIN_SIZE_PIXELS",e[e.GET_CELL_SIZE_PIXELS=1]="GET_CELL_SIZE_PIXELS"}(y||(t.WindowsOptionsReportType=y={}));let E=0;class k extends h.Disposable{getAttrData(){return this._curAttrData}constructor(e,t,i,s,r,h,_,f,v=new a.EscapeSequenceParser){super(),this._bufferService=e,this._charsetService=t,this._coreService=i,this._logService=s,this._optionsService=r,this._oscLinkService=h,this._coreMouseService=_,this._unicodeService=f,this._parser=v,this._parseBuffer=new Uint32Array(4096),this._stringDecoder=new c.StringToUtf32,this._utf8Decoder=new c.Utf8ToUtf32,this._workCell=new u.CellData,this._windowTitle="",this._iconName="",this._windowTitleStack=[],this._iconNameStack=[],this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone(),this._onRequestBell=this.register(new d.EventEmitter),this.onRequestBell=this._onRequestBell.event,this._onRequestRefreshRows=this.register(new d.EventEmitter),this.onRequestRefreshRows=this._onRequestRefreshRows.event,this._onRequestReset=this.register(new d.EventEmitter),this.onRequestReset=this._onRequestReset.event,this._onRequestSendFocus=this.register(new d.EventEmitter),this.onRequestSendFocus=this._onRequestSendFocus.event,this._onRequestSyncScrollBar=this.register(new d.EventEmitter),this.onRequestSyncScrollBar=this._onRequestSyncScrollBar.event,this._onRequestWindowsOptionsReport=this.register(new d.EventEmitter),this.onRequestWindowsOptionsReport=this._onRequestWindowsOptionsReport.event,this._onA11yChar=this.register(new d.EventEmitter),this.onA11yChar=this._onA11yChar.event,this._onA11yTab=this.register(new d.EventEmitter),this.onA11yTab=this._onA11yTab.event,this._onCursorMove=this.register(new d.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onLineFeed=this.register(new d.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onScroll=this.register(new d.EventEmitter),this.onScroll=this._onScroll.event,this._onTitleChange=this.register(new d.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onColor=this.register(new d.EventEmitter),this.onColor=this._onColor.event,this._parseStack={paused:!1,cursorStartX:0,cursorStartY:0,decodedLength:0,position:0},this._specialColors=[256,257,258],this.register(this._parser),this._dirtyRowTracker=new L(this._bufferService),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._parser.setCsiHandlerFallback(((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})})),this._parser.setEscHandlerFallback((e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})})),this._parser.setExecuteHandlerFallback((e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})})),this._parser.setOscHandlerFallback(((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})})),this._parser.setDcsHandlerFallback(((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})})),this._parser.setPrintHandler(((e,t,i)=>this.print(e,t,i))),this._parser.registerCsiHandler({final:"@"},(e=>this.insertChars(e))),this._parser.registerCsiHandler({intermediates:" ",final:"@"},(e=>this.scrollLeft(e))),this._parser.registerCsiHandler({final:"A"},(e=>this.cursorUp(e))),this._parser.registerCsiHandler({intermediates:" ",final:"A"},(e=>this.scrollRight(e))),this._parser.registerCsiHandler({final:"B"},(e=>this.cursorDown(e))),this._parser.registerCsiHandler({final:"C"},(e=>this.cursorForward(e))),this._parser.registerCsiHandler({final:"D"},(e=>this.cursorBackward(e))),this._parser.registerCsiHandler({final:"E"},(e=>this.cursorNextLine(e))),this._parser.registerCsiHandler({final:"F"},(e=>this.cursorPrecedingLine(e))),this._parser.registerCsiHandler({final:"G"},(e=>this.cursorCharAbsolute(e))),this._parser.registerCsiHandler({final:"H"},(e=>this.cursorPosition(e))),this._parser.registerCsiHandler({final:"I"},(e=>this.cursorForwardTab(e))),this._parser.registerCsiHandler({final:"J"},(e=>this.eraseInDisplay(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"J"},(e=>this.eraseInDisplay(e,!0))),this._parser.registerCsiHandler({final:"K"},(e=>this.eraseInLine(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"K"},(e=>this.eraseInLine(e,!0))),this._parser.registerCsiHandler({final:"L"},(e=>this.insertLines(e))),this._parser.registerCsiHandler({final:"M"},(e=>this.deleteLines(e))),this._parser.registerCsiHandler({final:"P"},(e=>this.deleteChars(e))),this._parser.registerCsiHandler({final:"S"},(e=>this.scrollUp(e))),this._parser.registerCsiHandler({final:"T"},(e=>this.scrollDown(e))),this._parser.registerCsiHandler({final:"X"},(e=>this.eraseChars(e))),this._parser.registerCsiHandler({final:"Z"},(e=>this.cursorBackwardTab(e))),this._parser.registerCsiHandler({final:"`"},(e=>this.charPosAbsolute(e))),this._parser.registerCsiHandler({final:"a"},(e=>this.hPositionRelative(e))),this._parser.registerCsiHandler({final:"b"},(e=>this.repeatPrecedingCharacter(e))),this._parser.registerCsiHandler({final:"c"},(e=>this.sendDeviceAttributesPrimary(e))),this._parser.registerCsiHandler({prefix:">",final:"c"},(e=>this.sendDeviceAttributesSecondary(e))),this._parser.registerCsiHandler({final:"d"},(e=>this.linePosAbsolute(e))),this._parser.registerCsiHandler({final:"e"},(e=>this.vPositionRelative(e))),this._parser.registerCsiHandler({final:"f"},(e=>this.hVPosition(e))),this._parser.registerCsiHandler({final:"g"},(e=>this.tabClear(e))),this._parser.registerCsiHandler({final:"h"},(e=>this.setMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"h"},(e=>this.setModePrivate(e))),this._parser.registerCsiHandler({final:"l"},(e=>this.resetMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"l"},(e=>this.resetModePrivate(e))),this._parser.registerCsiHandler({final:"m"},(e=>this.charAttributes(e))),this._parser.registerCsiHandler({final:"n"},(e=>this.deviceStatus(e))),this._parser.registerCsiHandler({prefix:"?",final:"n"},(e=>this.deviceStatusPrivate(e))),this._parser.registerCsiHandler({intermediates:"!",final:"p"},(e=>this.softReset(e))),this._parser.registerCsiHandler({intermediates:" ",final:"q"},(e=>this.setCursorStyle(e))),this._parser.registerCsiHandler({final:"r"},(e=>this.setScrollRegion(e))),this._parser.registerCsiHandler({final:"s"},(e=>this.saveCursor(e))),this._parser.registerCsiHandler({final:"t"},(e=>this.windowOptions(e))),this._parser.registerCsiHandler({final:"u"},(e=>this.restoreCursor(e))),this._parser.registerCsiHandler({intermediates:"'",final:"}"},(e=>this.insertColumns(e))),this._parser.registerCsiHandler({intermediates:"'",final:"~"},(e=>this.deleteColumns(e))),this._parser.registerCsiHandler({intermediates:'"',final:"q"},(e=>this.selectProtected(e))),this._parser.registerCsiHandler({intermediates:"$",final:"p"},(e=>this.requestMode(e,!0))),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},(e=>this.requestMode(e,!1))),this._parser.setExecuteHandler(n.C0.BEL,(()=>this.bell())),this._parser.setExecuteHandler(n.C0.LF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.VT,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.FF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.CR,(()=>this.carriageReturn())),this._parser.setExecuteHandler(n.C0.BS,(()=>this.backspace())),this._parser.setExecuteHandler(n.C0.HT,(()=>this.tab())),this._parser.setExecuteHandler(n.C0.SO,(()=>this.shiftOut())),this._parser.setExecuteHandler(n.C0.SI,(()=>this.shiftIn())),this._parser.setExecuteHandler(n.C1.IND,(()=>this.index())),this._parser.setExecuteHandler(n.C1.NEL,(()=>this.nextLine())),this._parser.setExecuteHandler(n.C1.HTS,(()=>this.tabSet())),this._parser.registerOscHandler(0,new g.OscHandler((e=>(this.setTitle(e),this.setIconName(e),!0)))),this._parser.registerOscHandler(1,new g.OscHandler((e=>this.setIconName(e)))),this._parser.registerOscHandler(2,new g.OscHandler((e=>this.setTitle(e)))),this._parser.registerOscHandler(4,new g.OscHandler((e=>this.setOrReportIndexedColor(e)))),this._parser.registerOscHandler(8,new g.OscHandler((e=>this.setHyperlink(e)))),this._parser.registerOscHandler(10,new g.OscHandler((e=>this.setOrReportFgColor(e)))),this._parser.registerOscHandler(11,new g.OscHandler((e=>this.setOrReportBgColor(e)))),this._parser.registerOscHandler(12,new g.OscHandler((e=>this.setOrReportCursorColor(e)))),this._parser.registerOscHandler(104,new g.OscHandler((e=>this.restoreIndexedColor(e)))),this._parser.registerOscHandler(110,new g.OscHandler((e=>this.restoreFgColor(e)))),this._parser.registerOscHandler(111,new g.OscHandler((e=>this.restoreBgColor(e)))),this._parser.registerOscHandler(112,new g.OscHandler((e=>this.restoreCursorColor(e)))),this._parser.registerEscHandler({final:"7"},(()=>this.saveCursor())),this._parser.registerEscHandler({final:"8"},(()=>this.restoreCursor())),this._parser.registerEscHandler({final:"D"},(()=>this.index())),this._parser.registerEscHandler({final:"E"},(()=>this.nextLine())),this._parser.registerEscHandler({final:"H"},(()=>this.tabSet())),this._parser.registerEscHandler({final:"M"},(()=>this.reverseIndex())),this._parser.registerEscHandler({final:"="},(()=>this.keypadApplicationMode())),this._parser.registerEscHandler({final:">"},(()=>this.keypadNumericMode())),this._parser.registerEscHandler({final:"c"},(()=>this.fullReset())),this._parser.registerEscHandler({final:"n"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"o"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"|"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"}"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"~"},(()=>this.setgLevel(1))),this._parser.registerEscHandler({intermediates:"%",final:"@"},(()=>this.selectDefaultCharset())),this._parser.registerEscHandler({intermediates:"%",final:"G"},(()=>this.selectDefaultCharset()));for(const e in o.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},(()=>this.selectCharset("("+e))),this._parser.registerEscHandler({intermediates:")",final:e},(()=>this.selectCharset(")"+e))),this._parser.registerEscHandler({intermediates:"*",final:e},(()=>this.selectCharset("*"+e))),this._parser.registerEscHandler({intermediates:"+",final:e},(()=>this.selectCharset("+"+e))),this._parser.registerEscHandler({intermediates:"-",final:e},(()=>this.selectCharset("-"+e))),this._parser.registerEscHandler({intermediates:".",final:e},(()=>this.selectCharset("."+e))),this._parser.registerEscHandler({intermediates:"/",final:e},(()=>this.selectCharset("/"+e)));this._parser.registerEscHandler({intermediates:"#",final:"8"},(()=>this.screenAlignmentPattern())),this._parser.setErrorHandler((e=>(this._logService.error("Parsing error: ",e),e))),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new m.DcsHandler(((e,t)=>this.requestStatusString(e,t))))}_preserveStack(e,t,i,s){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=s}_logSlowResolvingAsync(e){this._logService.logLevel<=v.LogLevelEnum.WARN&&Promise.race([e,new Promise(((e,t)=>setTimeout((()=>t("#SLOW_TIMEOUT")),5e3)))]).catch((e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")}))}_getCurrentLinkId(){return this._curAttrData.extended.urlId}parse(e,t){let i,s=this._activeBuffer.x,r=this._activeBuffer.y,n=0;const o=this._parseStack.paused;if(o){if(i=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,t))return this._logSlowResolvingAsync(i),i;s=this._parseStack.cursorStartX,r=this._parseStack.cursorStartY,this._parseStack.paused=!1,e.length>b&&(n=this._parseStack.position+b)}if(this._logService.logLevel<=v.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof e?` "${e}"`:` "${Array.prototype.map.call(e,(e=>String.fromCharCode(e))).join("")}"`),"string"==typeof e?e.split("").map((e=>e.charCodeAt(0))):e),this._parseBuffer.lengthb)for(let t=n;t0&&2===f.getWidth(this._activeBuffer.x-1)&&f.setCellFromCodepoint(this._activeBuffer.x-1,0,1,u);let v=this._parser.precedingJoinState;for(let g=t;ga)if(h){const e=f;let t=this._activeBuffer.x-m;for(this._activeBuffer.x=m,this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData(),!0)):(this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),f=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y),m>0&&f instanceof l.BufferLine&&f.copyCellsFrom(e,t,0,m,!1);t=0;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}else if(d&&(f.insertCells(this._activeBuffer.x,r-m,this._activeBuffer.getNullCell(u)),2===f.getWidth(a-1)&&f.setCellFromCodepoint(a-1,_.NULL_CELL_CODE,_.NULL_CELL_WIDTH,u)),f.setCellFromCodepoint(this._activeBuffer.x++,s,r,u),r>0)for(;--r;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}this._parser.precedingJoinState=v,this._activeBuffer.x0&&0===f.getWidth(this._activeBuffer.x)&&!f.hasContent(this._activeBuffer.x)&&f.setCellFromCodepoint(this._activeBuffer.x,0,1,u),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}registerCsiHandler(e,t){return"t"!==e.final||e.prefix||e.intermediates?this._parser.registerCsiHandler(e,t):this._parser.registerCsiHandler(e,(e=>!w(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e)))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new g.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows?this._activeBuffer.y=this._bufferService.rows-1:this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return this._activeBuffer.x=0,!0}backspace(){if(!this._coreService.decPrivateModes.reverseWraparound)return this._restrictCursor(),this._activeBuffer.x>0&&this._activeBuffer.x--,!0;if(this._restrictCursor(this._bufferService.cols),this._activeBuffer.x>0)this._activeBuffer.x--;else if(0===this._activeBuffer.x&&this._activeBuffer.y>this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)?.isWrapped){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;const e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}return this._restrictCursor(),!0}tab(){if(this._activeBuffer.x>=this._bufferService.cols)return!0;const e=this._activeBuffer.x;return this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){const t=this._activeBuffer.y-this._activeBuffer.scrollTop;return t>=0?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){const t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return t>=0?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),this._activeBuffer.x=0,!0}cursorPrecedingLine(e){return this.cursorUp(e),this._activeBuffer.x=0,!0}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(e.length>=2?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){const t=e.params[0];return 0===t?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===t&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.nextStop();return!0}cursorBackwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.prevStop();return!0}selectProtected(e){const t=e.params[0];return 1===t&&(this._curAttrData.bg|=536870912),2!==t&&0!==t||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,s=!1,r=!1){const n=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);n.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),r),s&&(n.isWrapped=!1)}_resetBufferLine(e,t=!1){const i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i&&(i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1)}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowTracker.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowTracker.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 3:const e=this._activeBuffer.lines.length-this._bufferService.rows;e>0&&(this._activeBuffer.lines.trimStart(e),this._activeBuffer.ybase=Math.max(this._activeBuffer.ybase-e,0),this._activeBuffer.ydisp=Math.max(this._activeBuffer.ydisp-e,0),this._onScroll.fire(0))}return!0}eraseInLine(e,t=!1){switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:this._eraseInBufferLine(this._activeBuffer.y,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);break;case 1:this._eraseInBufferLine(this._activeBuffer.y,0,this._activeBuffer.x+1,!1,t);break;case 2:this._eraseInBufferLine(this._activeBuffer.y,0,this._bufferService.cols,!0,t)}return this._dirtyRowTracker.markDirty(this._activeBuffer.y),!0}insertLines(e){this._restrictCursor();let t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y65535?2:1}let h=a;for(let e=1;e0||(this._is("xterm")||this._is("rxvt-unicode")||this._is("screen")?this._coreService.triggerDataEvent(n.C0.ESC+"[?1;2c"):this._is("linux")&&this._coreService.triggerDataEvent(n.C0.ESC+"[?6c")),!0}sendDeviceAttributesSecondary(e){return e.params[0]>0||(this._is("xterm")?this._coreService.triggerDataEvent(n.C0.ESC+"[>0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(n.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(n.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(e){for(let t=0;te?1:2,u=e.params[0];return f=u,v=t?2===u?4:4===u?_(o.modes.insertMode):12===u?3:20===u?_(d.convertEol):0:1===u?_(i.applicationCursorKeys):3===u?d.windowOptions.setWinLines?80===h?2:132===h?1:0:0:6===u?_(i.origin):7===u?_(i.wraparound):8===u?3:9===u?_("X10"===s):12===u?_(d.cursorBlink):25===u?_(!o.isCursorHidden):45===u?_(i.reverseWraparound):66===u?_(i.applicationKeypad):67===u?4:1e3===u?_("VT200"===s):1002===u?_("DRAG"===s):1003===u?_("ANY"===s):1004===u?_(i.sendFocus):1005===u?4:1006===u?_("SGR"===r):1015===u?4:1016===u?_("SGR_PIXELS"===r):1048===u?1:47===u||1047===u||1049===u?_(c===l):2004===u?_(i.bracketedPasteMode):0,o.triggerDataEvent(`${n.C0.ESC}[${t?"":"?"}${f};${v}$y`),!0;var f,v}_updateAttrColor(e,t,i,s,r){return 2===t?(e|=50331648,e&=-16777216,e|=f.AttributeData.fromColorRGB([i,s,r])):5===t&&(e&=-50331904,e|=33554432|255&i),e}_extractColor(e,t,i){const s=[0,0,-1,0,0,0];let r=0,n=0;do{if(s[n+r]=e.params[t+n],e.hasSubParams(t+n)){const i=e.getSubParams(t+n);let o=0;do{5===s[1]&&(r=1),s[n+o+1+r]=i[o]}while(++o=2||2===s[1]&&n+r>=5)break;s[1]&&(r=1)}while(++n+t5)&&(e=1),t.extended.underlineStyle=e,t.fg|=268435456,0===e&&(t.fg&=-268435457),t.updateExtended()}_processSGR0(e){e.fg=l.DEFAULT_ATTR_DATA.fg,e.bg=l.DEFAULT_ATTR_DATA.bg,e.extended=e.extended.clone(),e.extended.underlineStyle=0,e.extended.underlineColor&=-67108864,e.updateExtended()}charAttributes(e){if(1===e.length&&0===e.params[0])return this._processSGR0(this._curAttrData),!0;const t=e.length;let i;const s=this._curAttrData;for(let r=0;r=30&&i<=37?(s.fg&=-50331904,s.fg|=16777216|i-30):i>=40&&i<=47?(s.bg&=-50331904,s.bg|=16777216|i-40):i>=90&&i<=97?(s.fg&=-50331904,s.fg|=16777224|i-90):i>=100&&i<=107?(s.bg&=-50331904,s.bg|=16777224|i-100):0===i?this._processSGR0(s):1===i?s.fg|=134217728:3===i?s.bg|=67108864:4===i?(s.fg|=268435456,this._processUnderline(e.hasSubParams(r)?e.getSubParams(r)[0]:1,s)):5===i?s.fg|=536870912:7===i?s.fg|=67108864:8===i?s.fg|=1073741824:9===i?s.fg|=2147483648:2===i?s.bg|=134217728:21===i?this._processUnderline(2,s):22===i?(s.fg&=-134217729,s.bg&=-134217729):23===i?s.bg&=-67108865:24===i?(s.fg&=-268435457,this._processUnderline(0,s)):25===i?s.fg&=-536870913:27===i?s.fg&=-67108865:28===i?s.fg&=-1073741825:29===i?s.fg&=2147483647:39===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg):49===i?(s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):38===i||48===i||58===i?r+=this._extractColor(e,r,s):53===i?s.bg|=1073741824:55===i?s.bg&=-1073741825:59===i?(s.extended=s.extended.clone(),s.extended.underlineColor=-1,s.updateExtended()):100===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg,s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):this._logService.debug("Unknown SGR attribute: %d.",i);return!0}deviceStatus(e){switch(e.params[0]){case 5:this._coreService.triggerDataEvent(`${n.C0.ESC}[0n`);break;case 6:const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[${e};${t}R`)}return!0}deviceStatusPrivate(e){if(6===e.params[0]){const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[?${e};${t}R`)}return!0}softReset(e){return this._coreService.isCursorHidden=!1,this._onRequestSyncScrollBar.fire(),this._activeBuffer.scrollTop=0,this._activeBuffer.scrollBottom=this._bufferService.rows-1,this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._coreService.reset(),this._charsetService.reset(),this._activeBuffer.savedX=0,this._activeBuffer.savedY=this._activeBuffer.ybase,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,this._coreService.decPrivateModes.origin=!1,!0}setCursorStyle(e){const t=e.params[0]||1;switch(t){case 1:case 2:this._optionsService.options.cursorStyle="block";break;case 3:case 4:this._optionsService.options.cursorStyle="underline";break;case 5:case 6:this._optionsService.options.cursorStyle="bar"}const i=t%2==1;return this._optionsService.options.cursorBlink=i,!0}setScrollRegion(e){const t=e.params[0]||1;let i;return(e.length<2||(i=e.params[1])>this._bufferService.rows||0===i)&&(i=this._bufferService.rows),i>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(!w(e.params[0],this._optionsService.rawOptions.windowOptions))return!0;const t=e.length>1?e.params[1]:0;switch(e.params[0]){case 14:2!==t&&this._onRequestWindowsOptionsReport.fire(y.GET_WIN_SIZE_PIXELS);break;case 16:this._onRequestWindowsOptionsReport.fire(y.GET_CELL_SIZE_PIXELS);break;case 18:this._bufferService&&this._coreService.triggerDataEvent(`${n.C0.ESC}[8;${this._bufferService.rows};${this._bufferService.cols}t`);break;case 22:0!==t&&2!==t||(this._windowTitleStack.push(this._windowTitle),this._windowTitleStack.length>10&&this._windowTitleStack.shift()),0!==t&&1!==t||(this._iconNameStack.push(this._iconName),this._iconNameStack.length>10&&this._iconNameStack.shift());break;case 23:0!==t&&2!==t||this._windowTitleStack.length&&this.setTitle(this._windowTitleStack.pop()),0!==t&&1!==t||this._iconNameStack.length&&this.setIconName(this._iconNameStack.pop())}return!0}saveCursor(e){return this._activeBuffer.savedX=this._activeBuffer.x,this._activeBuffer.savedY=this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,!0}restoreCursor(e){return this._activeBuffer.x=this._activeBuffer.savedX||0,this._activeBuffer.y=Math.max(this._activeBuffer.savedY-this._activeBuffer.ybase,0),this._curAttrData.fg=this._activeBuffer.savedCurAttrData.fg,this._curAttrData.bg=this._activeBuffer.savedCurAttrData.bg,this._charsetService.charset=this._savedCharset,this._activeBuffer.savedCharset&&(this._charsetService.charset=this._activeBuffer.savedCharset),this._restrictCursor(),!0}setTitle(e){return this._windowTitle=e,this._onTitleChange.fire(e),!0}setIconName(e){return this._iconName=e,!0}setOrReportIndexedColor(e){const t=[],i=e.split(";");for(;i.length>1;){const e=i.shift(),s=i.shift();if(/^\d+$/.exec(e)){const i=parseInt(e);if(D(i))if("?"===s)t.push({type:0,index:i});else{const e=(0,S.parseColor)(s);e&&t.push({type:1,index:i,color:e})}}}return t.length&&this._onColor.fire(t),!0}setHyperlink(e){const t=e.split(";");return!(t.length<2)&&(t[1]?this._createHyperlink(t[0],t[1]):!t[0]&&this._finishHyperlink())}_createHyperlink(e,t){this._getCurrentLinkId()&&this._finishHyperlink();const i=e.split(":");let s;const r=i.findIndex((e=>e.startsWith("id=")));return-1!==r&&(s=i[r].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=this._oscLinkService.registerLink({id:s,uri:t}),this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!0}_setOrReportSpecialColor(e,t){const i=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)if("?"===i[e])this._onColor.fire([{type:0,index:this._specialColors[t]}]);else{const s=(0,S.parseColor)(i[e]);s&&this._onColor.fire([{type:1,index:this._specialColors[t],color:s}])}return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(!e)return this._onColor.fire([{type:2}]),!0;const t=[],i=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0,!0}reverseIndex(){if(this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop){const e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop;this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)}else this._activeBuffer.y--,this._restrictCursor();return!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){const e=new u.CellData;e.content=1<<22|"E".charCodeAt(0),e.fg=this._curAttrData.fg,e.bg=this._curAttrData.bg,this._setCursor(0,0);for(let t=0;t(this._coreService.triggerDataEvent(`${n.C0.ESC}${e}${n.C0.ESC}\\`),!0))('"q'===e?`P1$r${this._curAttrData.isProtected()?1:0}"q`:'"p'===e?'P1$r61;1"p':"r"===e?`P1$r${i.scrollTop+1};${i.scrollBottom+1}r`:"m"===e?"P1$r0m":" q"===e?`P1$r${{block:2,underline:4,bar:6}[s.cursorStyle]-(s.cursorBlink?1:0)} q`:"P0$r")}markRangeDirty(e,t){this._dirtyRowTracker.markRangeDirty(e,t)}}t.InputHandler=k;let L=class{constructor(e){this._bufferService=e,this.clearRange()}clearRange(){this.start=this._bufferService.buffer.y,this.end=this._bufferService.buffer.y}markDirty(e){ethis.end&&(this.end=e)}markRangeDirty(e,t){e>t&&(E=e,e=t,t=E),ethis.end&&(this.end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}};function D(e){return 0<=e&&e<256}L=s([r(0,v.IBufferService)],L)},844:(e,t)=>{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.MutableDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){const t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)}},t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){this._isDisposed||e===this._value||(this._value?.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){this._isDisposed=!0,this._value?.dispose(),this._value=void 0}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class i{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=i,t.FourKeyMap=class{constructor(){this._data=new i}set(e,t,s,r,n){this._data.get(e,t)||this._data.set(e,t,new i),this._data.get(e,t).set(s,r,n)}get(e,t,i,s){return this._data.get(e,t)?.get(i,s)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isChromeOS=t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.getSafariVersion=t.isSafari=t.isLegacyEdge=t.isFirefox=t.isNode=void 0,t.isNode="title"in E;const i=t.isNode?"node":navigator.userAgent,s=t.isNode?"node":navigator.platform;t.isFirefox=i.includes("Firefox"),t.isLegacyEdge=i.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(i),t.getSafariVersion=function(){if(!t.isSafari)return 0;const e=i.match(/Version\/(\d+)/);return null===e||e.length<2?0:parseInt(e[1])},t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(s),t.isIpad="iPad"===s,t.isIphone="iPhone"===s,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(s),t.isLinux=s.indexOf("Linux")>=0,t.isChromeOS=/\bCrOS\b/.test(i)},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e)),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0===this._array.length)return!1;const t=this._getKey(e);if(void 0===t)return!1;if(i=this._search(t),-1===i)return!1;if(this._getKey(this._array[i])!==t)return!1;do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{yield this._array[i]}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{t(this._array[i])}while(++i=t;){let s=t+i>>1;const r=this._getKey(this._array[s]);if(r>e)i=s-1;else{if(!(r0&&this._getKey(this._array[s-1])===e;)s--;return s}t=s+1}}return t}}},7226:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DebouncedIdleTask=t.IdleTaskQueue=t.PriorityTaskQueue=void 0;const s=i(6114);class r{constructor(){this._tasks=[],this._i=0}enqueue(e){this._tasks.push(e),this._start()}flush(){for(;this._ir)return s-t<-20&&console.warn(`task queue exceeded allotted deadline by ${Math.abs(Math.round(s-t))}ms`),void this._start();s=r}this.clear()}}class n extends r{_requestCallback(e){return setTimeout((()=>e(this._createDeadline(16))))}_cancelCallback(e){clearTimeout(e)}_createDeadline(e){const t=Date.now()+e;return{timeRemaining:()=>Math.max(0,t-Date.now())}}}t.PriorityTaskQueue=n,t.IdleTaskQueue=!s.isNode&&"requestIdleCallback"in window?class extends r{_requestCallback(e){return requestIdleCallback(e)}_cancelCallback(e){cancelIdleCallback(e)}}:n,t.DebouncedIdleTask=class{constructor(){this._queue=new t.IdleTaskQueue}set(e){this._queue.clear(),this._queue.enqueue(e)}flush(){this._queue.flush()}}},9282:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;const s=i(643);t.updateWindowsModeWrappedState=function(e){const t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),i=t?.get(e.cols-1),r=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);r&&i&&(r.isWrapped=i[s.CHAR_DATA_CODE_INDEX]!==s.NULL_CELL_CODE&&i[s.CHAR_DATA_CODE_INDEX]!==s.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;class i{constructor(){this.fg=0,this.bg=0,this.extended=new s}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){const e=new i;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}isOverline(){return 1073741824&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return!(50331648&~this.fg)}isBgRGB(){return!(50331648&~this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return!(50331648&this.fg)}isBgDefault(){return!(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?!(50331648&~this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?!(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}}t.AttributeData=i;class s{get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){const e=(3758096384&this._ext)>>29;return e<0?4294967288^e:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}clone(){return new s(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=s},9092:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Buffer=t.MAX_BUFFER_SIZE=void 0;const s=i(6349),r=i(7226),n=i(3734),o=i(8437),a=i(4634),h=i(511),c=i(643),l=i(4863),d=i(7116);t.MAX_BUFFER_SIZE=4294967295,t.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.tabs={},this.savedY=0,this.savedX=0,this.savedCurAttrData=o.DEFAULT_ATTR_DATA.clone(),this.savedCharset=d.DEFAULT_CHARSET,this.markers=[],this._nullCell=h.CellData.fromCharData([0,c.NULL_CELL_CHAR,c.NULL_CELL_WIDTH,c.NULL_CELL_CODE]),this._whitespaceCell=h.CellData.fromCharData([0,c.WHITESPACE_CELL_CHAR,c.WHITESPACE_CELL_WIDTH,c.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._memoryCleanupQueue=new r.IdleTaskQueue,this._memoryCleanupPosition=0,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new n.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new n.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new o.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){const e=this.ybase+this.y-this.ydisp;return e>=0&&et.MAX_BUFFER_SIZE?t.MAX_BUFFER_SIZE:i}fillViewportRows(e){if(0===this.lines.length){void 0===e&&(e=o.DEFAULT_ATTR_DATA);let t=this._rows;for(;t--;)this.lines.push(this.getBlankLine(e))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(e,t){const i=this.getNullCell(o.DEFAULT_ATTR_DATA);let s=0;const r=this._getCorrectBufferLength(t);if(r>this.lines.maxLength&&(this.lines.maxLength=r),this.lines.length>0){if(this._cols0&&this.lines.length<=this.ybase+this.y+n+1?(this.ybase--,n++,this.ydisp>0&&this.ydisp--):this.lines.push(new o.BufferLine(e,i)));else for(let e=this._rows;e>t;e--)this.lines.length>t+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(r0&&(this.lines.trimStart(e),this.ybase=Math.max(this.ybase-e,0),this.ydisp=Math.max(this.ydisp-e,0),this.savedY=Math.max(this.savedY-e,0)),this.lines.maxLength=r}this.x=Math.min(this.x,e-1),this.y=Math.min(this.y,t-1),n&&(this.y+=n),this.savedX=Math.min(this.savedX,e-1),this.scrollTop=0}if(this.scrollBottom=t-1,this._isReflowEnabled&&(this._reflow(e,t),this._cols>e))for(let t=0;t.1*this.lines.length&&(this._memoryCleanupPosition=0,this._memoryCleanupQueue.enqueue((()=>this._batchedMemoryCleanup())))}_batchedMemoryCleanup(){let e=!0;this._memoryCleanupPosition>=this.lines.length&&(this._memoryCleanupPosition=0,e=!1);let t=0;for(;this._memoryCleanupPosition100)return!0;return e}get _isReflowEnabled(){const e=this._optionsService.rawOptions.windowsPty;return e&&e.buildNumber?this._hasScrollback&&"conpty"===e.backend&&e.buildNumber>=21376:this._hasScrollback&&!this._optionsService.rawOptions.windowsMode}_reflow(e,t){this._cols!==e&&(e>this._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){const i=(0,a.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(o.DEFAULT_ATTR_DATA));if(i.length>0){const s=(0,a.reflowLargerCreateNewLayout)(this.lines,i);(0,a.reflowLargerApplyNewLayout)(this.lines,s.layout),this._reflowLargerAdjustViewport(e,t,s.countRemoved)}}_reflowLargerAdjustViewport(e,t,i){const s=this.getNullCell(o.DEFAULT_ATTR_DATA);let r=i;for(;r-- >0;)0===this.ybase?(this.y>0&&this.y--,this.lines.length=0;n--){let h=this.lines.get(n);if(!h||!h.isWrapped&&h.getTrimmedLength()<=e)continue;const c=[h];for(;h.isWrapped&&n>0;)h=this.lines.get(--n),c.unshift(h);const l=this.ybase+this.y;if(l>=n&&l0&&(s.push({start:n+c.length+r,newLines:v}),r+=v.length),c.push(...v);let p=_.length-1,g=_[p];0===g&&(p--,g=_[p]);let m=c.length-u-1,S=d;for(;m>=0;){const e=Math.min(S,g);if(void 0===c[p])break;if(c[p].copyCellsFrom(c[m],S-e,g-e,e,!0),g-=e,0===g&&(p--,g=_[p]),S-=e,0===S){m--;const e=Math.max(m,0);S=(0,a.getWrappedLineTrimmedLength)(c,e,this._cols)}}for(let t=0;t0;)0===this.ybase?this.y0){const e=[],t=[];for(let e=0;e=0;c--)if(a&&a.start>n+h){for(let e=a.newLines.length-1;e>=0;e--)this.lines.set(c--,a.newLines[e]);c++,e.push({index:n+1,amount:a.newLines.length}),h+=a.newLines.length,a=s[++o]}else this.lines.set(c,t[n--]);let c=0;for(let t=e.length-1;t>=0;t--)e[t].index+=c,this.lines.onInsertEmitter.fire(e[t]),c+=e[t].amount;const l=Math.max(0,i+r-this.lines.maxLength);l>0&&this.lines.onTrimEmitter.fire(l)}}translateBufferLineToString(e,t,i=0,s){const r=this.lines.get(e);return r?r.translateToString(t,i,s):""}getWrappedRangeForLine(e){let t=e,i=e;for(;t>0&&this.lines.get(t).isWrapped;)t--;for(;i+10;);return e>=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(e){this._isClearing=!0;for(let t=0;t{t.line-=e,t.line<0&&t.dispose()}))),t.register(this.lines.onInsert((e=>{t.line>=e.index&&(t.line+=e.amount)}))),t.register(this.lines.onDelete((e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)}))),t.register(t.onDispose((()=>this._removeMarker(t)))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}}},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;const s=i(3734),r=i(511),n=i(643),o=i(482);t.DEFAULT_ATTR_DATA=Object.freeze(new s.AttributeData);let a=0;class h{constructor(e,t,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*e);const s=t||r.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let t=0;t>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],t[n.CHAR_DATA_CHAR_INDEX].length>1?(this._combined[e]=t[1],this._data[3*e+0]=2097152|e|t[n.CHAR_DATA_WIDTH_INDEX]<<22):this._data[3*e+0]=t[n.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|t[n.CHAR_DATA_WIDTH_INDEX]<<22}getWidth(e){return this._data[3*e+0]>>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,o.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return a=3*e,t.content=this._data[a+0],t.fg=this._data[a+1],t.bg=this._data[a+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodepoint(e,t,i,s){268435456&s.bg&&(this._extendedAttrs[e]=s.extended),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=s.fg,this._data[3*e+2]=s.bg}addCodepointToCell(e,t,i){let s=this._data[3*e+0];2097152&s?this._combined[e]+=(0,o.stringFromCodePoint)(t):2097151&s?(this._combined[e]=(0,o.stringFromCodePoint)(2097151&s)+(0,o.stringFromCodePoint)(t),s&=-2097152,s|=2097152):s=t|1<<22,i&&(s&=-12582913,s|=i<<22),this._data[3*e+0]=s}insertCells(e,t,i){if((e%=this.length)&&2===this.getWidth(e-1)&&this.setCellFromCodepoint(e-1,0,1,i),t=0;--i)this.setCell(e+t+i,this.loadCell(e+i,s));for(let s=0;sthis.length){if(this._data.buffer.byteLength>=4*i)this._data=new Uint32Array(this._data.buffer,0,i);else{const e=new Uint32Array(i);e.set(this._data),this._data=e}for(let i=this.length;i=e&&delete this._combined[s]}const s=Object.keys(this._extendedAttrs);for(let t=0;t=e&&delete this._extendedAttrs[i]}}return this.length=e,4*i*2=0;--e)if(4194303&this._data[3*e+0])return e+(this._data[3*e+0]>>22);return 0}getNoBgTrimmedLength(){for(let e=this.length-1;e>=0;--e)if(4194303&this._data[3*e+0]||50331648&this._data[3*e+2])return e+(this._data[3*e+0]>>22);return 0}copyCellsFrom(e,t,i,s,r){const n=e._data;if(r)for(let r=s-1;r>=0;r--){for(let e=0;e<3;e++)this._data[3*(i+r)+e]=n[3*(t+r)+e];268435456&n[3*(t+r)+2]&&(this._extendedAttrs[i+r]=e._extendedAttrs[t+r])}else for(let r=0;r=t&&(this._combined[r-t+i]=e._combined[r])}}translateToString(e,t,i,s){t=t??0,i=i??this.length,e&&(i=Math.min(i,this.getTrimmedLength())),s&&(s.length=0);let r="";for(;t>22||1}return s&&s.push(t),r}}t.BufferLine=h},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function i(e,t,i){if(t===e.length-1)return e[t].getTrimmedLength();const s=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),r=2===e[t+1].getWidth(0);return s&&r?i-1:i}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(e,t,s,r,n){const o=[];for(let a=0;a=a&&r0&&(e>d||0===l[e].getTrimmedLength());e--)v++;v>0&&(o.push(a+l.length-v),o.push(v)),a+=l.length-1}return o},t.reflowLargerCreateNewLayout=function(e,t){const i=[];let s=0,r=t[s],n=0;for(let o=0;oi(e,r,t))).reduce(((e,t)=>e+t));let o=0,a=0,h=0;for(;hc&&(o-=c,a++);const l=2===e[a].getWidth(o-1);l&&o--;const d=l?s-1:s;r.push(d),h+=d}return r},t.getWrappedLineTrimmedLength=i},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;const s=i(8460),r=i(844),n=i(9092);class o extends r.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new s.EventEmitter),this.onBufferActivate=this._onBufferActivate.event,this.reset(),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.resize(this._bufferService.cols,this._bufferService.rows)))),this.register(this._optionsService.onSpecificOptionChange("tabStopWidth",(()=>this.setupTabStops())))}reset(){this._normal=new n.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new n.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t),this.setupTabStops(e)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;const s=i(482),r=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){const t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,s.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[r.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;if(e[r.CHAR_DATA_CHAR_INDEX].length>2)t=!0;else if(2===e[r.CHAR_DATA_CHAR_INDEX].length){const i=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0);if(55296<=i&&i<=56319){const s=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(1);56320<=s&&s<=57343?this.content=1024*(i-55296)+s-56320+65536|e[r.CHAR_DATA_WIDTH_INDEX]<<22:t=!0}else t=!0}else this.content=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|e[r.CHAR_DATA_WIDTH_INDEX]<<22;t&&(this.combinedData=e[r.CHAR_DATA_CHAR_INDEX],this.content=2097152|e[r.CHAR_DATA_WIDTH_INDEX]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.CellData=o},643:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=0,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;const s=i(8460),r=i(844);class n{get id(){return this._id}constructor(e){this.line=e,this.isDisposed=!1,this._disposables=[],this._id=n._nextId++,this._onDispose=this.register(new s.EventEmitter),this.onDispose=this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),(0,r.disposeArray)(this._disposables),this._disposables.length=0)}register(e){return this._disposables.push(e),e}}t.Marker=n,n._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var i,s,r;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,function(e){e.NUL="\0",e.SOH="",e.STX="",e.ETX="",e.EOT="",e.ENQ="",e.ACK="",e.BEL="",e.BS="\b",e.HT="\t",e.LF="\n",e.VT="\v",e.FF="\f",e.CR="\r",e.SO="",e.SI="",e.DLE="",e.DC1="",e.DC2="",e.DC3="",e.DC4="",e.NAK="",e.SYN="",e.ETB="",e.CAN="",e.EM="",e.SUB="",e.ESC="",e.FS="",e.GS="",e.RS="",e.US="",e.SP=" ",e.DEL=""}(i||(t.C0=i={})),function(e){e.PAD="€",e.HOP="",e.BPH="‚",e.NBH="ƒ",e.IND="„",e.NEL="…",e.SSA="†",e.ESA="‡",e.HTS="ˆ",e.HTJ="‰",e.VTS="Š",e.PLD="‹",e.PLU="Œ",e.RI="",e.SS2="Ž",e.SS3="",e.DCS="",e.PU1="‘",e.PU2="’",e.STS="“",e.CCH="”",e.MW="•",e.SPA="–",e.EPA="—",e.SOS="˜",e.SGCI="™",e.SCI="š",e.CSI="›",e.ST="œ",e.OSC="",e.PM="ž",e.APC="Ÿ"}(s||(t.C1=s={})),function(e){e.ST=`${i.ESC}\\`}(r||(t.C1_ESCAPED=r={}))},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;const s=i(2584),r={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(e,t,i,n){const o={type:0,cancel:!1,key:void 0},a=(e.shiftKey?1:0)|(e.altKey?2:0)|(e.ctrlKey?4:0)|(e.metaKey?8:0);switch(e.keyCode){case 0:"UIKeyInputUpArrow"===e.key?o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A":"UIKeyInputLeftArrow"===e.key?o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D":"UIKeyInputRightArrow"===e.key?o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C":"UIKeyInputDownArrow"===e.key&&(o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B");break;case 8:o.key=e.ctrlKey?"\b":s.C0.DEL,e.altKey&&(o.key=s.C0.ESC+o.key);break;case 9:if(e.shiftKey){o.key=s.C0.ESC+"[Z";break}o.key=s.C0.HT,o.cancel=!0;break;case 13:o.key=e.altKey?s.C0.ESC+s.C0.CR:s.C0.CR,o.cancel=!0;break;case 27:o.key=s.C0.ESC,e.altKey&&(o.key=s.C0.ESC+s.C0.ESC),o.cancel=!0;break;case 37:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"D",o.key===s.C0.ESC+"[1;3D"&&(o.key=s.C0.ESC+(i?"b":"[1;5D"))):o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D";break;case 39:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"C",o.key===s.C0.ESC+"[1;3C"&&(o.key=s.C0.ESC+(i?"f":"[1;5C"))):o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C";break;case 38:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"A",i||o.key!==s.C0.ESC+"[1;3A"||(o.key=s.C0.ESC+"[1;5A")):o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A";break;case 40:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"B",i||o.key!==s.C0.ESC+"[1;3B"||(o.key=s.C0.ESC+"[1;5B")):o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B";break;case 45:e.shiftKey||e.ctrlKey||(o.key=s.C0.ESC+"[2~");break;case 46:o.key=a?s.C0.ESC+"[3;"+(a+1)+"~":s.C0.ESC+"[3~";break;case 36:o.key=a?s.C0.ESC+"[1;"+(a+1)+"H":t?s.C0.ESC+"OH":s.C0.ESC+"[H";break;case 35:o.key=a?s.C0.ESC+"[1;"+(a+1)+"F":t?s.C0.ESC+"OF":s.C0.ESC+"[F";break;case 33:e.shiftKey?o.type=2:e.ctrlKey?o.key=s.C0.ESC+"[5;"+(a+1)+"~":o.key=s.C0.ESC+"[5~";break;case 34:e.shiftKey?o.type=3:e.ctrlKey?o.key=s.C0.ESC+"[6;"+(a+1)+"~":o.key=s.C0.ESC+"[6~";break;case 112:o.key=a?s.C0.ESC+"[1;"+(a+1)+"P":s.C0.ESC+"OP";break;case 113:o.key=a?s.C0.ESC+"[1;"+(a+1)+"Q":s.C0.ESC+"OQ";break;case 114:o.key=a?s.C0.ESC+"[1;"+(a+1)+"R":s.C0.ESC+"OR";break;case 115:o.key=a?s.C0.ESC+"[1;"+(a+1)+"S":s.C0.ESC+"OS";break;case 116:o.key=a?s.C0.ESC+"[15;"+(a+1)+"~":s.C0.ESC+"[15~";break;case 117:o.key=a?s.C0.ESC+"[17;"+(a+1)+"~":s.C0.ESC+"[17~";break;case 118:o.key=a?s.C0.ESC+"[18;"+(a+1)+"~":s.C0.ESC+"[18~";break;case 119:o.key=a?s.C0.ESC+"[19;"+(a+1)+"~":s.C0.ESC+"[19~";break;case 120:o.key=a?s.C0.ESC+"[20;"+(a+1)+"~":s.C0.ESC+"[20~";break;case 121:o.key=a?s.C0.ESC+"[21;"+(a+1)+"~":s.C0.ESC+"[21~";break;case 122:o.key=a?s.C0.ESC+"[23;"+(a+1)+"~":s.C0.ESC+"[23~";break;case 123:o.key=a?s.C0.ESC+"[24;"+(a+1)+"~":s.C0.ESC+"[24~";break;default:if(!e.ctrlKey||e.shiftKey||e.altKey||e.metaKey)if(i&&!n||!e.altKey||e.metaKey)!i||e.altKey||e.ctrlKey||e.shiftKey||!e.metaKey?e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.keyCode>=48&&1===e.key.length?o.key=e.key:e.key&&e.ctrlKey&&("_"===e.key&&(o.key=s.C0.US),"@"===e.key&&(o.key=s.C0.NUL)):65===e.keyCode&&(o.type=1);else{const t=r[e.keyCode],i=t?.[e.shiftKey?1:0];if(i)o.key=s.C0.ESC+i;else if(e.keyCode>=65&&e.keyCode<=90){const t=e.ctrlKey?e.keyCode-64:e.keyCode+32;let i=String.fromCharCode(t);e.shiftKey&&(i=i.toUpperCase()),o.key=s.C0.ESC+i}else if(32===e.keyCode)o.key=s.C0.ESC+(e.ctrlKey?s.C0.NUL:" ");else if("Dead"===e.key&&e.code.startsWith("Key")){let t=e.code.slice(3,4);e.shiftKey||(t=t.toLowerCase()),o.key=s.C0.ESC+t,o.cancel=!0}}else e.keyCode>=65&&e.keyCode<=90?o.key=String.fromCharCode(e.keyCode-64):32===e.keyCode?o.key=s.C0.NUL:e.keyCode>=51&&e.keyCode<=55?o.key=String.fromCharCode(e.keyCode-51+27):56===e.keyCode?o.key=s.C0.DEL:219===e.keyCode?o.key=s.C0.ESC:220===e.keyCode?o.key=s.C0.FS:221===e.keyCode&&(o.key=s.C0.GS)}return o}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return e>65535?(e-=65536,String.fromCharCode(55296+(e>>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(e,t=0,i=e.length){let s="";for(let r=t;r65535?(t-=65536,s+=String.fromCharCode(55296+(t>>10))+String.fromCharCode(t%1024+56320)):s+=String.fromCharCode(t)}return s},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){const i=e.length;if(!i)return 0;let s=0,r=0;if(this._interim){const i=e.charCodeAt(r++);56320<=i&&i<=57343?t[s++]=1024*(this._interim-55296)+i-56320+65536:(t[s++]=this._interim,t[s++]=i),this._interim=0}for(let n=r;n=i)return this._interim=r,s;const o=e.charCodeAt(n);56320<=o&&o<=57343?t[s++]=1024*(r-55296)+o-56320+65536:(t[s++]=r,t[s++]=o)}else 65279!==r&&(t[s++]=r)}return s}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){const i=e.length;if(!i)return 0;let s,r,n,o,a=0,h=0,c=0;if(this.interim[0]){let s=!1,r=this.interim[0];r&=192==(224&r)?31:224==(240&r)?15:7;let n,o=0;for(;(n=63&this.interim[++o])&&o<4;)r<<=6,r|=n;const h=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,l=h-o;for(;c=i)return 0;if(n=e[c++],128!=(192&n)){c--,s=!0;break}this.interim[o++]=n,r<<=6,r|=63&n}s||(2===h?r<128?c--:t[a++]=r:3===h?r<2048||r>=55296&&r<=57343||65279===r||(t[a++]=r):r<65536||r>1114111||(t[a++]=r)),this.interim.fill(0)}const l=i-4;let d=c;for(;d=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(h=(31&s)<<6|63&r,h<128){d--;continue}t[a++]=h}else if(224==(240&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(h=(15&s)<<12|(63&r)<<6|63&n,h<2048||h>=55296&&h<=57343||65279===h)continue;t[a++]=h}else if(240==(248&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,this.interim[2]=n,a;if(o=e[d++],128!=(192&o)){d--;continue}if(h=(7&s)<<18|(63&r)<<12|(63&n)<<6|63&o,h<65536||h>1114111)continue;t[a++]=h}}return a}}},225:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const s=i(1480),r=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),o.fill(1),o[0]=0,o.fill(0,1,32),o.fill(0,127,160),o.fill(2,4352,4448),o[9001]=2,o[9002]=2,o.fill(2,11904,42192),o[12351]=1,o.fill(2,44032,55204),o.fill(2,63744,64256),o.fill(2,65040,65050),o.fill(2,65072,65136),o.fill(2,65280,65377),o.fill(2,65504,65511);for(let e=0;et[r][1])return!1;for(;r>=s;)if(i=s+r>>1,e>t[i][1])s=i+1;else{if(!(e=131072&&e<=196605||e>=196608&&e<=262141?2:1}charProperties(e,t){let i=this.wcwidth(e),r=0===i&&0!==t;if(r){const e=s.UnicodeService.extractWidth(t);0===e?r=!1:e>i&&(i=e)}return s.UnicodeService.createPropertyValue(0,i,r)}}},5981:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._didUserInput=!1,this._onWriteParsed=this.register(new s.EventEmitter),this.onWriteParsed=this._onWriteParsed.event}handleUserInput(){this._didUserInput=!0}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)return void(this._syncCalls=0);if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,this._isSyncWriting)return;let i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);const e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}write(e,t){if(this._pendingData>5e7)throw new Error("write data discarded, use flow control to avoid losing data");if(!this._writeBuffer.length){if(this._bufferOffset=0,this._didUserInput)return this._didUserInput=!1,this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t),void this._innerWrite();setTimeout((()=>this._innerWrite()))}this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,t=!0){const i=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){const e=this._writeBuffer[this._bufferOffset],s=this._action(e,t);if(s){const e=e=>Date.now()-i>=12?setTimeout((()=>this._innerWrite(0,e))):this._innerWrite(i,e);return void s.catch((e=>(queueMicrotask((()=>{throw e})),Promise.resolve(!1)))).then(e)}const r=this._callbacks[this._bufferOffset];if(r&&r(),this._bufferOffset++,this._pendingData-=e.length,Date.now()-i>=12)break}this._writeBuffer.length>this._bufferOffset?(this._bufferOffset>50&&(this._writeBuffer=this._writeBuffer.slice(this._bufferOffset),this._callbacks=this._callbacks.slice(this._bufferOffset),this._bufferOffset=0),setTimeout((()=>this._innerWrite()))):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}t.WriteBuffer=n},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;const i=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,s=/^[\da-f]+$/;function r(e,t){const i=e.toString(16),s=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return s;case 12:return(s+s).slice(0,3);default:return s+s}}t.parseColor=function(e){if(!e)return;let t=e.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);const e=i.exec(t);if(e){const t=e[1]?15:e[4]?255:e[7]?4095:65535;return[Math.round(parseInt(e[1]||e[4]||e[7]||e[10],16)/t*255),Math.round(parseInt(e[2]||e[5]||e[8]||e[11],16)/t*255),Math.round(parseInt(e[3]||e[6]||e[9]||e[12],16)/t*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),s.exec(t)&&[3,6,9,12].includes(t.length))){const e=t.length/3,i=[0,0,0];for(let s=0;s<3;++s){const r=parseInt(t.slice(e*s,e*s+e),16);i[s]=1===e?r<<4:2===e?r:3===e?r>>4:r>>8}return i}},t.toRgbString=function(e,t=16){const[i,s,n]=e;return`rgb:${r(i,t)}/${r(s,t)}/${r(n,t)}`}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;const s=i(482),r=i(8742),n=i(5770),o=[];t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._ident,"PUT",(0,s.utf32ToString)(e,t,i))}unhook(e,t=!0){if(this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].unhook(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].unhook(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._ident,"UNHOOK",e);this._active=o,this._ident=0}};const a=new r.Params;a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=e.length>1||e.params[0]?e.clone():a,this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,s.utf32ToString)(e,t,i),this._data.length>n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params),t instanceof Promise))return t.then((e=>(this._params=a,this._data="",this._hitLimit=!1,e)));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;const s=i(844),r=i(8742),n=i(6242),o=i(6351);class a{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){this.table.fill(e<<4|t)}add(e,t,i,s){this.table[t<<8|e]=i<<4|s}addMany(e,t,i,s){for(let r=0;rt)),i=(e,i)=>t.slice(e,i),s=i(32,127),r=i(0,24);r.push(25),r.push.apply(r,i(28,32));const n=i(0,14);let o;for(o in e.setDefault(1,0),e.addMany(s,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(i(128,144),o,3,0),e.addMany(i(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(r,0,3,0),e.addMany(r,1,3,1),e.add(127,1,0,1),e.addMany(r,8,0,8),e.addMany(r,3,3,3),e.add(127,3,0,3),e.addMany(r,4,3,4),e.add(127,4,0,4),e.addMany(r,6,3,6),e.addMany(r,5,3,5),e.add(127,5,0,5),e.addMany(r,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(s,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(i(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(s,7,0,7),e.addMany(r,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(i(64,127),3,7,0),e.addMany(i(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(i(48,60),4,8,4),e.addMany(i(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(i(32,64),6,0,6),e.add(127,6,0,6),e.addMany(i(64,127),6,0,0),e.addMany(i(32,48),3,9,5),e.addMany(i(32,48),5,9,5),e.addMany(i(48,64),5,0,6),e.addMany(i(64,127),5,7,0),e.addMany(i(32,48),4,9,5),e.addMany(i(32,48),1,9,2),e.addMany(i(32,48),2,9,2),e.addMany(i(48,127),2,10,0),e.addMany(i(48,80),1,10,0),e.addMany(i(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(i(96,127),1,10,0),e.add(80,1,11,9),e.addMany(r,9,0,9),e.add(127,9,0,9),e.addMany(i(28,32),9,0,9),e.addMany(i(32,48),9,9,12),e.addMany(i(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(r,11,0,11),e.addMany(i(32,128),11,0,11),e.addMany(i(28,32),11,0,11),e.addMany(r,10,0,10),e.add(127,10,0,10),e.addMany(i(28,32),10,0,10),e.addMany(i(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(i(32,48),10,9,12),e.addMany(r,12,0,12),e.add(127,12,0,12),e.addMany(i(28,32),12,0,12),e.addMany(i(32,48),12,9,12),e.addMany(i(48,64),12,0,11),e.addMany(i(64,127),12,12,13),e.addMany(i(64,127),10,12,13),e.addMany(i(64,127),9,12,13),e.addMany(r,13,13,13),e.addMany(s,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(h,0,2,0),e.add(h,8,5,8),e.add(h,6,0,6),e.add(h,11,0,11),e.add(h,13,13,13),e}();class c extends s.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new r.Params,this._params.addParam(0),this._collect=0,this.precedingJoinState=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this.register((0,s.toDisposable)((()=>{this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null)}))),this._oscParser=this.register(new n.OscParser),this._dcsParser=this.register(new o.DcsParser),this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},(()=>!0))}_identifier(e,t=[64,126]){let i=0;if(e.prefix){if(e.prefix.length>1)throw new Error("only one byte as prefix supported");if(i=e.prefix.charCodeAt(0),i&&60>i||i>63)throw new Error("prefix must be in range 0x3c .. 0x3f")}if(e.intermediates){if(e.intermediates.length>2)throw new Error("only two bytes as intermediates are supported");for(let t=0;ts||s>47)throw new Error("intermediate must be in range 0x20 .. 0x2f");i<<=8,i|=s}}if(1!==e.final.length)throw new Error("final must be a single byte");const s=e.final.charCodeAt(0);if(t[0]>s||s>t[1])throw new Error(`final must be in range ${t[0]} .. ${t[1]}`);return i<<=8,i|=s,i}identToString(e){const t=[];for(;e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){const i=this._identifier(e,[48,126]);void 0===this._escHandlers[i]&&(this._escHandlers[i]=[]);const s=this._escHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){const i=this._identifier(e);void 0===this._csiHandlers[i]&&(this._csiHandlers[i]=[]);const s=this._csiHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingJoinState=0,0!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,s,r){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=s,this._parseStack.chunkPos=r}parse(e,t,i){let s,r=0,n=0,o=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,o=this._parseStack.chunkPos+1;else{if(void 0===i||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");const t=this._parseStack.handlers;let n=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](this._params),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 4:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 6:if(r=e[this._parseStack.chunkPos],s=this._dcsParser.unhook(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0;break;case 5:if(r=e[this._parseStack.chunkPos],s=this._oscParser.end(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0}this._parseStack.state=0,o=this._parseStack.chunkPos+1,this.precedingJoinState=0,this.currentState=15&this._parseStack.transition}for(let i=o;i>4){case 2:for(let s=i+1;;++s){if(s>=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=0&&(s=o[a](this._params),!0!==s);a--)if(s instanceof Promise)return this._preserveStack(3,o,a,n,i),s;a<0&&this._csiHandlerFb(this._collect<<8|r,this._params),this.precedingJoinState=0;break;case 8:do{switch(r){case 59:this._params.addParam(0);break;case 58:this._params.addSubParam(-1);break;default:this._params.addDigit(r-48)}}while(++i47&&r<60);i--;break;case 9:this._collect<<=8,this._collect|=r;break;case 10:const c=this._escHandlers[this._collect<<8|r];let l=c?c.length-1:-1;for(;l>=0&&(s=c[l](),!0!==s);l--)if(s instanceof Promise)return this._preserveStack(4,c,l,n,i),s;l<0&&this._escHandlerFb(this._collect<<8|r),this.precedingJoinState=0;break;case 11:this._params.reset(),this._params.addParam(0),this._collect=0;break;case 12:this._dcsParser.hook(this._collect<<8|r,this._params);break;case 13:for(let s=i+1;;++s)if(s>=t||24===(r=e[s])||26===r||27===r||r>127&&r=t||(r=e[s])<32||r>127&&r{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;const s=i(5770),r=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._id,"PUT",(0,r.utf32ToString)(e,t,i))}start(){this.reset(),this._state=1}put(e,t,i){if(3!==this._state){if(1===this._state)for(;t0&&this._put(e,t,i)}}end(e,t=!0){if(0!==this._state){if(3!==this._state)if(1===this._state&&this._start(),this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].end(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].end(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._id,"END",e);this._active=n,this._id=-1,this._state=0}}},t.OscHandler=class{constructor(e){this._handler=e,this._data="",this._hitLimit=!1}start(){this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,r.utf32ToString)(e,t,i),this._data.length>s.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data),t instanceof Promise))return t.then((e=>(this._data="",this._hitLimit=!1,e)));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;const i=2147483647;class s{static fromArray(e){const t=new s;if(!e.length)return t;for(let i=Array.isArray(e[0])?1:0;i256)throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}clone(){const e=new s(this.maxLength,this.maxSubParamsLength);return e.params.set(this.params),e.length=this.length,e._subParams.set(this._subParams),e._subParamsLength=this._subParamsLength,e._subParamsIdx.set(this._subParamsIdx),e._rejectDigits=this._rejectDigits,e._rejectSubDigits=this._rejectSubDigits,e._digitIsSub=this._digitIsSub,e}toArray(){const e=[];for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&e.push(Array.prototype.slice.call(this._subParams,i,s))}return e}reset(){this.length=0,this._subParamsLength=0,this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}addParam(e){if(this._digitIsSub=!1,this.length>=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>i?i:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>i?i:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)>0}getSubParams(e){const t=this._subParamsIdx[e]>>8,i=255&this._subParamsIdx[e];return i-t>0?this._subParams.subarray(t,i):null}getSubParamsAll(){const e={};for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&(e[t]=this._subParams.slice(i,s))}return e}addDigit(e){let t;if(this._rejectDigits||!(t=this._digitIsSub?this._subParamsLength:this.length)||this._digitIsSub&&this._rejectSubDigits)return;const s=this._digitIsSub?this._subParams:this.params,r=s[t-1];s[t-1]=~r?Math.min(10*r+e,i):e}}t.Params=s},5741:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;e>=0;e--)this._addons[e].instance.dispose()}loadAddon(e,t){const i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(e){if(e.isDisposed)return;let t=-1;for(let i=0;i{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;const s=i(3785),r=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){const t=this._buffer.lines.get(e);if(t)return new s.BufferLineApiView(t)}getNullCell(){return new r.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;const s=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new s.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;const s=i(8771),r=i(8460),n=i(844);class o extends n.Disposable{constructor(e){super(),this._core=e,this._onBufferChange=this.register(new r.EventEmitter),this.onBufferChange=this._onBufferChange.event,this._normal=new s.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new s.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate((()=>this._onBufferChange.fire(this.active)))}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}t.BufferNamespaceApi=o},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,(e=>t(e.toArray())))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,t){return this._core.registerDcsHandler(e,((e,i)=>t(e,i.toArray())))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferService=t.MINIMUM_ROWS=t.MINIMUM_COLS=void 0;const n=i(8460),o=i(844),a=i(5295),h=i(2585);t.MINIMUM_COLS=2,t.MINIMUM_ROWS=1;let c=t.BufferService=class extends o.Disposable{get buffer(){return this.buffers.active}constructor(e){super(),this.isUserScrolling=!1,this._onResize=this.register(new n.EventEmitter),this.onResize=this._onResize.event,this._onScroll=this.register(new n.EventEmitter),this.onScroll=this._onScroll.event,this.cols=Math.max(e.rawOptions.cols||0,t.MINIMUM_COLS),this.rows=Math.max(e.rawOptions.rows||0,t.MINIMUM_ROWS),this.buffers=this.register(new a.BufferSet(e,this))}resize(e,t){this.cols=e,this.rows=t,this.buffers.resize(e,t),this._onResize.fire({cols:e,rows:t})}reset(){this.buffers.reset(),this.isUserScrolling=!1}scroll(e,t=!1){const i=this.buffer;let s;s=this._cachedBlankLine,s&&s.length===this.cols&&s.getFg(0)===e.fg&&s.getBg(0)===e.bg||(s=i.getBlankLine(e,t),this._cachedBlankLine=s),s.isWrapped=t;const r=i.ybase+i.scrollTop,n=i.ybase+i.scrollBottom;if(0===i.scrollTop){const e=i.lines.isFull;n===i.lines.length-1?e?i.lines.recycle().copyFrom(s):i.lines.push(s.clone()):i.lines.splice(n+1,0,s.clone()),e?this.isUserScrolling&&(i.ydisp=Math.max(i.ydisp-1,0)):(i.ybase++,this.isUserScrolling||i.ydisp++)}else{const e=n-r+1;i.lines.shiftElements(r+1,e-1,-1),i.lines.set(n,s.clone())}this.isUserScrolling||(i.ydisp=i.ybase),this._onScroll.fire(i.ydisp)}scrollLines(e,t,i){const s=this.buffer;if(e<0){if(0===s.ydisp)return;this.isUserScrolling=!0}else e+s.ydisp>=s.ybase&&(this.isUserScrolling=!1);const r=s.ydisp;s.ydisp=Math.max(Math.min(s.ydisp+e,s.ybase),0),r!==s.ydisp&&(t||this._onScroll.fire(s.ydisp))}};t.BufferService=c=s([r(0,h.IOptionsService)],c)},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreMouseService=void 0;const n=i(2585),o=i(8460),a=i(844),h={NONE:{events:0,restrict:()=>!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,e.shift=!1,!0)},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function c(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?(i|=64,i|=e.action):(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}const l=String.fromCharCode,d={DEFAULT:e=>{const t=[c(e,!1)+32,e.col+32,e.row+32];return t[0]>255||t[1]>255||t[2]>255?"":`${l(t[0])}${l(t[1])}${l(t[2])}`},SGR:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.col};${e.row}${t}`},SGR_PIXELS:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.x};${e.y}${t}`}};let _=t.CoreMouseService=class extends a.Disposable{constructor(e,t){super(),this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._lastEvent=null,this._onProtocolChange=this.register(new o.EventEmitter),this.onProtocolChange=this._onProtocolChange.event;for(const e of Object.keys(h))this.addProtocol(e,h[e]);for(const e of Object.keys(d))this.addEncoding(e,d[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}triggerMouseEvent(e){if(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows)return!1;if(4===e.button&&32===e.action)return!1;if(3===e.button&&32!==e.action)return!1;if(4!==e.button&&(2===e.action||3===e.action))return!1;if(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))return!1;if(!this._protocols[this._activeProtocol].restrict(e))return!1;const t=this._encodings[this._activeEncoding](e);return t&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,!0}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}};t.CoreMouseService=_=s([r(0,n.IBufferService),r(1,n.ICoreService)],_)},6975:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreService=void 0;const n=i(1439),o=i(8460),a=i(844),h=i(2585),c=Object.freeze({insertMode:!1}),l=Object.freeze({applicationCursorKeys:!1,applicationKeypad:!1,bracketedPasteMode:!1,origin:!1,reverseWraparound:!1,sendFocus:!1,wraparound:!0});let d=t.CoreService=class extends a.Disposable{constructor(e,t,i){super(),this._bufferService=e,this._logService=t,this._optionsService=i,this.isCursorInitialized=!1,this.isCursorHidden=!1,this._onData=this.register(new o.EventEmitter),this.onData=this._onData.event,this._onUserInput=this.register(new o.EventEmitter),this.onUserInput=this._onUserInput.event,this._onBinary=this.register(new o.EventEmitter),this.onBinary=this._onBinary.event,this._onRequestScrollToBottom=this.register(new o.EventEmitter),this.onRequestScrollToBottom=this._onRequestScrollToBottom.event,this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}reset(){this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}triggerDataEvent(e,t=!1){if(this._optionsService.rawOptions.disableStdin)return;const i=this._bufferService.buffer;t&&this._optionsService.rawOptions.scrollOnUserInput&&i.ybase!==i.ydisp&&this._onRequestScrollToBottom.fire(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onData.fire(e)}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onBinary.fire(e))}};t.CoreService=d=s([r(0,h.IBufferService),r(1,h.ILogService),r(2,h.IOptionsService)],d)},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;const s=i(8055),r=i(8460),n=i(844),o=i(6106);let a=0,h=0;class c extends n.Disposable{get decorations(){return this._decorations.values()}constructor(){super(),this._decorations=new o.SortedList((e=>e?.marker.line)),this._onDecorationRegistered=this.register(new r.EventEmitter),this.onDecorationRegistered=this._onDecorationRegistered.event,this._onDecorationRemoved=this.register(new r.EventEmitter),this.onDecorationRemoved=this._onDecorationRemoved.event,this.register((0,n.toDisposable)((()=>this.reset())))}registerDecoration(e){if(e.marker.isDisposed)return;const t=new l(e);if(t){const e=t.marker.onDispose((()=>t.dispose()));t.onDispose((()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())})),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}reset(){for(const e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){let s=0,r=0;for(const n of this._decorations.getKeyIterator(t))s=n.options.x??0,r=s+(n.options.width??1),e>=s&&e{a=t.options.x??0,h=a+(t.options.width??1),e>=a&&e{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;const s=i(2585),r=i(8343);class n{constructor(...e){this._entries=new Map;for(const[t,i]of e)this.set(t,i)}set(e,t){const i=this._entries.get(e);return this._entries.set(e,t),i}forEach(e){for(const[t,i]of this._entries.entries())e(t,i)}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=n,t.InstantiationService=class{constructor(){this._services=new n,this._services.set(s.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(e,...t){const i=(0,r.getServiceDependencies)(e).sort(((e,t)=>e.index-t.index)),s=[];for(const t of i){const i=this._services.get(t.id);if(!i)throw new Error(`[createInstance] ${e.name} depends on UNKNOWN service ${t.id}.`);s.push(i)}const n=i.length>0?i[0].index:t.length;if(t.length!==n)throw new Error(`[createInstance] First service dependency of ${e.name} at position ${n+1} conflicts with ${t.length} static arguments`);return new e(...[...t,...s])}}},7866:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.traceCall=t.setTraceLogger=t.LogService=void 0;const n=i(844),o=i(2585),a={trace:o.LogLevelEnum.TRACE,debug:o.LogLevelEnum.DEBUG,info:o.LogLevelEnum.INFO,warn:o.LogLevelEnum.WARN,error:o.LogLevelEnum.ERROR,off:o.LogLevelEnum.OFF};let h,c=t.LogService=class extends n.Disposable{get logLevel(){return this._logLevel}constructor(e){super(),this._optionsService=e,this._logLevel=o.LogLevelEnum.OFF,this._updateLogLevel(),this.register(this._optionsService.onSpecificOptionChange("logLevel",(()=>this._updateLogLevel()))),h=this}_updateLogLevel(){this._logLevel=a[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(e){for(let t=0;tJSON.stringify(e))).join(", ")})`);const t=s.apply(this,e);return h.trace(`GlyphRenderer#${s.name} return`,t),t}}},7302:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OptionsService=t.DEFAULT_OPTIONS=void 0;const s=i(8460),r=i(844),n=i(6114);t.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,cursorInactiveStyle:"outline",customGlyphs:!0,drawBoldTextInBrightColors:!0,documentOverride:null,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",ignoreBracketedPasteMode:!1,lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",logger:null,scrollback:1e3,scrollOnUserInput:!0,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rescaleOverlappingGlyphs:!1,rightClickSelectsWord:n.isMac,windowOptions:{},windowsMode:!1,windowsPty:{},wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0};const o=["normal","bold","100","200","300","400","500","600","700","800","900"];class a extends r.Disposable{constructor(e){super(),this._onOptionChange=this.register(new s.EventEmitter),this.onOptionChange=this._onOptionChange.event;const i={...t.DEFAULT_OPTIONS};for(const t in e)if(t in i)try{const s=e[t];i[t]=this._sanitizeAndValidateOption(t,s)}catch(e){console.error(e)}this.rawOptions=i,this.options={...i},this._setupOptions(),this.register((0,r.toDisposable)((()=>{this.rawOptions.linkHandler=null,this.rawOptions.documentOverride=null})))}onSpecificOptionChange(e,t){return this.onOptionChange((i=>{i===e&&t(this.rawOptions[e])}))}onMultipleOptionChange(e,t){return this.onOptionChange((i=>{-1!==e.indexOf(i)&&t()}))}_setupOptions(){const e=e=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);return this.rawOptions[e]},i=(e,i)=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);i=this._sanitizeAndValidateOption(e,i),this.rawOptions[e]!==i&&(this.rawOptions[e]=i,this._onOptionChange.fire(e))};for(const t in this.rawOptions){const s={get:e.bind(this,t),set:i.bind(this,t)};Object.defineProperty(this.options,t,s)}}_sanitizeAndValidateOption(e,i){switch(e){case"cursorStyle":if(i||(i=t.DEFAULT_OPTIONS[e]),!function(e){return"block"===e||"underline"===e||"bar"===e}(i))throw new Error(`"${i}" is not a valid value for ${e}`);break;case"wordSeparator":i||(i=t.DEFAULT_OPTIONS[e]);break;case"fontWeight":case"fontWeightBold":if("number"==typeof i&&1<=i&&i<=1e3)break;i=o.includes(i)?i:t.DEFAULT_OPTIONS[e];break;case"cursorWidth":i=Math.floor(i);case"lineHeight":case"tabStopWidth":if(i<1)throw new Error(`${e} cannot be less than 1, value: ${i}`);break;case"minimumContrastRatio":i=Math.max(1,Math.min(21,Math.round(10*i)/10));break;case"scrollback":if((i=Math.min(i,4294967295))<0)throw new Error(`${e} cannot be less than 0, value: ${i}`);break;case"fastScrollSensitivity":case"scrollSensitivity":if(i<=0)throw new Error(`${e} cannot be less than or equal to 0, value: ${i}`);break;case"rows":case"cols":if(!i&&0!==i)throw new Error(`${e} must be numeric, value: ${i}`);break;case"windowsPty":i=i??{}}return i}}t.OptionsService=a},2660:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkService=void 0;const n=i(2585);let o=t.OscLinkService=class{constructor(e){this._bufferService=e,this._nextId=1,this._entriesWithId=new Map,this._dataByLinkId=new Map}registerLink(e){const t=this._bufferService.buffer;if(void 0===e.id){const i=t.addMarker(t.ybase+t.y),s={data:e,id:this._nextId++,lines:[i]};return i.onDispose((()=>this._removeMarkerFromLink(s,i))),this._dataByLinkId.set(s.id,s),s.id}const i=e,s=this._getEntryIdKey(i),r=this._entriesWithId.get(s);if(r)return this.addLineToLink(r.id,t.ybase+t.y),r.id;const n=t.addMarker(t.ybase+t.y),o={id:this._nextId++,key:this._getEntryIdKey(i),data:i,lines:[n]};return n.onDispose((()=>this._removeMarkerFromLink(o,n))),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){const i=this._dataByLinkId.get(e);if(i&&i.lines.every((e=>e.line!==t))){const e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose((()=>this._removeMarkerFromLink(i,e)))}}getLinkData(e){return this._dataByLinkId.get(e)?.data}_getEntryIdKey(e){return`${e.id};;${e.uri}`}_removeMarkerFromLink(e,t){const i=e.lines.indexOf(t);-1!==i&&(e.lines.splice(i,1),0===e.lines.length&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id)))}};t.OscLinkService=o=s([r(0,n.IBufferService)],o)},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0;const i="di$target",s="di$dependencies";t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e[s]||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);const r=function(e,t,n){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");!function(e,t,r){t[i]===t?t[s].push({id:e,index:r}):(t[s]=[{id:e,index:r}],t[i]=t)}(r,e,n)};return r.toString=()=>e,t.serviceRegistry.set(e,r),r}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;const s=i(8343);var r;t.IBufferService=(0,s.createDecorator)("BufferService"),t.ICoreMouseService=(0,s.createDecorator)("CoreMouseService"),t.ICoreService=(0,s.createDecorator)("CoreService"),t.ICharsetService=(0,s.createDecorator)("CharsetService"),t.IInstantiationService=(0,s.createDecorator)("InstantiationService"),function(e){e[e.TRACE=0]="TRACE",e[e.DEBUG=1]="DEBUG",e[e.INFO=2]="INFO",e[e.WARN=3]="WARN",e[e.ERROR=4]="ERROR",e[e.OFF=5]="OFF"}(r||(t.LogLevelEnum=r={})),t.ILogService=(0,s.createDecorator)("LogService"),t.IOptionsService=(0,s.createDecorator)("OptionsService"),t.IOscLinkService=(0,s.createDecorator)("OscLinkService"),t.IUnicodeService=(0,s.createDecorator)("UnicodeService"),t.IDecorationService=(0,s.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const s=i(8460),r=i(225);class n{static extractShouldJoin(e){return!!(1&e)}static extractWidth(e){return e>>1&3}static extractCharKind(e){return e>>3}static createPropertyValue(e,t,i=!1){return(16777215&e)<<3|(3&t)<<1|(i?1:0)}constructor(){this._providers=Object.create(null),this._active="",this._onChange=new s.EventEmitter,this.onChange=this._onChange.event;const e=new r.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}dispose(){this._onChange.dispose()}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(e){let t=0,i=0;const s=e.length;for(let r=0;r=s)return t+this.wcwidth(o);const i=e.charCodeAt(r);56320<=i&&i<=57343?o=1024*(o-55296)+i-56320+65536:t+=this.wcwidth(i)}const a=this.charProperties(o,i);let h=n.extractWidth(a);n.extractShouldJoin(a)&&(h-=n.extractWidth(i)),t+=h,i=a}return t}charProperties(e,t){return this._activeProvider.charProperties(e,t)}}t.UnicodeService=n}},t={};function i(s){var r=t[s];if(void 0!==r)return r.exports;var n=t[s]={exports:{}};return e[s].call(n.exports,n,n.exports,i),n.exports}var s={};return(()=>{var e=s;Object.defineProperty(e,"__esModule",{value:!0}),e.Terminal=void 0;const t=i(9042),r=i(3236),n=i(844),o=i(5741),a=i(8285),h=i(7975),c=i(7090),l=["cols","rows"];class d extends n.Disposable{constructor(e){super(),this._core=this.register(new r.Terminal(e)),this._addonManager=this.register(new o.AddonManager),this._publicOptions={...this._core.options};const t=e=>this._core.options[e],i=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(const e in this._core.options){const s={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this._publicOptions,e,s)}}_checkReadonlyOptions(e){if(l.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._parser||(this._parser=new h.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new c.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._buffer||(this._buffer=this.register(new a.BufferNamespaceApi(this._core))),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){const e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(const t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}input(e,t=!0){this._core.input(e,t)}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}attachCustomWheelEventHandler(e){this._core.attachCustomWheelEventHandler(e)}registerLinkProvider(e){return this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.registerMarker(e)}registerDecoration(e){return this._checkProposedApi(),this._verifyPositiveIntegers(e.x??0,e.width??0,e.height??0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){super.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){this._addonManager.loadAddon(this,e)}static get strings(){return t}_verifyIntegers(...e){for(const t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(const t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}e.Terminal=d})(),s})())(),D=k.exports.Terminal,R=k.exports.__esModule;export{D as Terminal,R as __esModule,L as default}; diff --git a/core/src/3rd-party/xterm_addon-fit.js b/core/src/3rd-party/xterm_addon-fit.js new file mode 100644 index 00000000000..6fad4c1ef1e --- /dev/null +++ b/core/src/3rd-party/xterm_addon-fit.js @@ -0,0 +1,7 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/@xterm/addon-fit@0.10.0/lib/addon-fit.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var e,t,r={exports:{}};self;var s=r.exports=(e=t={},Object.defineProperty(e,"__esModule",{value:!0}),e.FitAddon=void 0,e.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,s=window.getComputedStyle(this._terminal.element.parentElement),i=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=i-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=o-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}},t),i=r.exports.FitAddon,o=r.exports.__esModule;export{i as FitAddon,o as __esModule,s as default}; diff --git a/core/src/3rd-party/xterm_addon-web-links.js b/core/src/3rd-party/xterm_addon-web-links.js new file mode 100644 index 00000000000..ee1cffdb311 --- /dev/null +++ b/core/src/3rd-party/xterm_addon-web-links.js @@ -0,0 +1,7 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/@xterm/addon-web-links@0.11.0/lib/addon-web-links.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var e={exports:{}};self;var t=e.exports=(()=>{var e={6:(e,t)=>{function r(e){try{const t=new URL(e),r=t.password&&t.username?`${t.protocol}//${t.username}:${t.password}@${t.host}`:t.username?`${t.protocol}//${t.username}@${t.host}`:`${t.protocol}//${t.host}`;return e.toLocaleLowerCase().startsWith(r.toLocaleLowerCase())}catch(e){return!1}}Object.defineProperty(t,"__esModule",{value:!0}),t.LinkComputer=t.WebLinkProvider=void 0,t.WebLinkProvider=class{constructor(e,t,r,n={}){this._terminal=e,this._regex=t,this._handler=r,this._options=n}provideLinks(e,t){const r=n.computeLink(e,this._regex,this._terminal,this._handler);t(this._addCallbacks(r))}_addCallbacks(e){return e.map((e=>(e.leave=this._options.leave,e.hover=(t,r)=>{if(this._options.hover){const{range:n}=e;this._options.hover(t,r,n)}},e)))}};class n{static computeLink(e,t,o,s){const i=new RegExp(t.source,(t.flags||"")+"g"),[a,l]=n._getWindowedLineStrings(e-1,o),c=a.join("");let d;const p=[];for(;d=i.exec(c);){const e=d[0];if(!r(e))continue;const[t,i]=n._mapStrIdx(o,l,0,d.index),[a,c]=n._mapStrIdx(o,t,i,e.length);if(-1===t||-1===i||-1===a||-1===c)continue;const h={start:{x:i+1,y:t+1},end:{x:c,y:a+1}};p.push({range:h,text:e,activate:s})}return p}static _getWindowedLineStrings(e,t){let r,n=e,o=e,s=0,i="";const a=[];if(r=t.buffer.active.getLine(e)){const e=r.translateToString(!0);if(r.isWrapped&&" "!==e[0]){for(s=0;(r=t.buffer.active.getLine(--n))&&s<2048&&(i=r.translateToString(!0),s+=i.length,a.push(i),r.isWrapped&&-1===i.indexOf(" ")););a.reverse()}for(a.push(e),s=0;(r=t.buffer.active.getLine(++o))&&r.isWrapped&&s<2048&&(i=r.translateToString(!0),s+=i.length,a.push(i),-1===i.indexOf(" ")););}return[a,n]}static _mapStrIdx(e,t,r,n){const o=e.buffer.active,s=o.getNullCell();let i=r;for(;n;){const e=o.getLine(t);if(!e)return[-1,-1];for(let r=i;r{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.WebLinksAddon=void 0;const t=r(6),o=/(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function s(e,t){const r=window.open();if(r){try{r.opener=null}catch{}r.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}e.WebLinksAddon=class{constructor(e=s,t={}){this._handler=e,this._options=t}activate(e){this._terminal=e;const r=this._options,n=r.urlRegex||o;this._linkProvider=this._terminal.registerLinkProvider(new t.WebLinkProvider(this._terminal,n,this._handler,r))}dispose(){this._linkProvider?.dispose()}}})(),n})(),r=e.exports.WebLinksAddon,n=e.exports.__esModule;export{r as WebLinksAddon,n as __esModule,t as default}; diff --git a/pyscript.core/src/all-done.js b/core/src/all-done.js similarity index 79% rename from pyscript.core/src/all-done.js rename to core/src/all-done.js index 4a005660c69..c1b1e23f903 100644 --- a/pyscript.core/src/all-done.js +++ b/core/src/all-done.js @@ -1,3 +1,4 @@ +import withResolvers from "@webreflection/utils/with-resolvers"; import TYPES from "./types.js"; const waitForIt = []; @@ -5,7 +6,7 @@ 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(); + const { promise, resolve } = withResolvers(); waitForIt.push(promise); element.addEventListener(`${TYPE}:done`, resolve, { once: true }); } diff --git a/pyscript.core/src/config.js b/core/src/config.js similarity index 81% rename from pyscript.core/src/config.js rename to core/src/config.js index ca8d3a46099..b7ed1338ef2 100644 --- a/pyscript.core/src/config.js +++ b/core/src/config.js @@ -25,7 +25,7 @@ const badURL = (url, expected = "") => { * @param {string?} type the optional type to enforce * @returns {{json: boolean, toml: boolean, text: string}} */ -const configDetails = async (config, type) => { +export const configDetails = async (config, type) => { let text = config?.trim(); // we only support an object as root config let url = "", @@ -45,6 +45,8 @@ const configDetails = async (config, type) => { const conflictError = (reason) => new Error(`(${CONFLICTING_CODE}): ${reason}`); +const relative_url = (url, base = location.href) => new URL(url, base).href; + const syntaxError = (type, url, { message }) => { let str = `(${BAD_CONFIG}): Invalid ${type}`; if (url) str += ` @ ${url}`; @@ -54,7 +56,7 @@ const syntaxError = (type, url, { message }) => { const configs = new Map(); for (const [TYPE] of TYPES) { - /** @type {Promise<[...any]>} A Promise wrapping any plugins which should be loaded. */ + /** @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} ) */ @@ -108,7 +110,7 @@ for (const [TYPE] of TYPES) { if (!error && config) { try { const { json, toml, text, url } = await configDetails(config, type); - if (url) configURL = new URL(url, location.href).href; + if (url) configURL = relative_url(url); config = text; if (json || type === "json") { try { @@ -133,24 +135,26 @@ for (const [TYPE] of TYPES) { // 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)); + plugins = async () => { + 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)); + } else if (key === "error") { + toBeAwaited.push(value().then(({ notOnDOM }) => notOnDOM())); } - } 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); + return await Promise.all(toBeAwaited); + }; configs.set(TYPE, { config: parsed, configURL, plugins, error }); } -export default configs; +export { configs, relative_url }; diff --git a/pyscript.core/src/core.css b/core/src/core.css similarity index 69% rename from pyscript.core/src/core.css rename to core/src/core.css index 84473940143..7fb91da8ad5 100644 --- a/pyscript.core/src/core.css +++ b/core/src/core.css @@ -28,17 +28,34 @@ mpy-config { .py-editor-run-button, .mpy-editor-run-button { position: absolute; + display: flex; right: 0.5rem; bottom: 0.5rem; opacity: 0; transition: opacity 0.25s; z-index: 1; + padding: 0; } .py-editor-box:hover .py-editor-run-button, .mpy-editor-box:hover .mpy-editor-run-button, .py-editor-run-button:focus, -.py-editor-run-button:disabled, +.py-editor-run-button.running, .mpy-editor-run-button:focus, -.mpy-editor-run-button:disabled { +.mpy-editor-run-button.running { opacity: 1; } + +py-terminal span, +mpy-terminal span { + letter-spacing: 0 !important; +} + +dialog.pyscript-fs { + border-radius: 8px; + border-width: 1px; +} + +dialog.pyscript-fs > div { + display: flex; + justify-content: space-between; +} diff --git a/pyscript.core/src/core.js b/core/src/core.js similarity index 81% rename from pyscript.core/src/core.js rename to core/src/core.js index 05a111da625..3a167f961ac 100644 --- a/pyscript.core/src/core.js +++ b/core/src/core.js @@ -1,7 +1,8 @@ /*! (c) PyScript Development Team */ +import "./zero-redirect.js"; import stickyModule from "sticky-module"; -import "@ungap/with-resolvers"; +import withResolvers from "@webreflection/utils/with-resolvers"; import { INVALID_CONTENT, @@ -12,6 +13,7 @@ import { define, defineProperty, dispatch, + isSync, queryTarget, unescape, whenDefined, @@ -19,20 +21,65 @@ import { import "./all-done.js"; import TYPES from "./types.js"; -import configs from "./config.js"; +import { configs, relative_url } 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"; +import { + hooks, + main, + worker, + codeFor, + createFunction, + inputFailure, +} from "./hooks.js"; +import * as fs from "./fs.js"; + +import codemirror from "./plugins/codemirror.js"; +export { codemirror }; + +import { stdlib, optional } from "./stdlib.js"; +export { stdlib, optional, inputFailure }; + +export const donkey = (options) => + import(/* webpackIgnore: true */ "./plugins/donkey.js").then((module) => + module.default(options), + ); // generic helper to disambiguate between custom element and script const isScript = ({ tagName }) => tagName === "SCRIPT"; +// Used to create either Pyodide or MicroPython workers +// with the PyScript module available within the code +const [PyWorker, MPWorker] = [...TYPES.entries()].map( + ([TYPE, interpreter]) => + /** + * 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 {Promise} + */ + async function PyScriptWorker(file, options) { + await configs.get(TYPE).plugins; + const xworker = XWorker.call( + new Hook(null, hooked.get(TYPE)), + file, + { + ...options, + type: interpreter, + }, + ); + assign(xworker.sync, sync); + return xworker.ready; + }, +); + // avoid multiple initialization of the same library const [ { PyWorker: exportedPyWorker, + MPWorker: exportedMPWorker, hooks: exportedHooks, config: exportedConfig, whenDefined: exportedWhenDefined, @@ -40,6 +87,7 @@ const [ alreadyLive, ] = stickyModule("@pyscript/core", { PyWorker, + MPWorker, hooks, config: {}, whenDefined, @@ -47,12 +95,17 @@ const [ export { TYPES, + relative_url, exportedPyWorker as PyWorker, + exportedMPWorker as MPWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined, }; +export const offline_interpreter = (config) => + config?.interpreter && relative_url(config.interpreter); + const hooked = new Map(); for (const [TYPE, interpreter] of TYPES) { @@ -116,6 +169,9 @@ for (const [TYPE, interpreter] of TYPES) { // enrich the Python env with some JS utility for main interpreter.registerJsModule("_pyscript", { PyWorker, + fs, + interpreter, + js_import: (...urls) => Promise.all(urls.map((url) => import(url))), get target() { return isScript(currentElement) ? currentElement.target.id @@ -130,14 +186,14 @@ for (const [TYPE, interpreter] of TYPES) { // ensure plugins are bootstrapped already before custom type definition // NOTE: we cannot top-level await in here as plugins import other utilities // from core.js itself so that custom definition should not be blocking. - plugins.then(() => { + plugins().then(() => { // possible early errors sent by polyscript const errors = new Map(); // specific main and worker hooks const hooks = { main: { - ...codeFor(main), + ...codeFor(main, TYPE), async onReady(wrap, element) { registerModule(wrap); @@ -159,15 +215,13 @@ for (const [TYPE, interpreter] of TYPES) { } if (isScript(element)) { - const { - attributes: { async: isAsync, target }, - } = element; - const hasTarget = !!target?.value; - const show = hasTarget - ? queryTarget(element, target.value) + const isAsync = !isSync(element); + const target = element.getAttribute("target"); + const show = target + ? queryTarget(element, target) : document.createElement("script-py"); - if (!hasTarget) { + if (!target) { const { head, body } = document; if (head.contains(element)) body.append(show); else element.after(show); @@ -234,7 +288,7 @@ for (const [TYPE, interpreter] of TYPES) { }, }, worker: { - ...codeFor(worker), + ...codeFor(worker, TYPE), // these are lazy getters that returns a composition // of the current hooks or undefined, if no hook is present get onReady() { @@ -263,7 +317,7 @@ for (const [TYPE, interpreter] of TYPES) { interpreter, hooks, env: `${TYPE}-script`, - version: config?.interpreter, + version: offline_interpreter(config), onerror(error, element) { errors.set(element, error); }, @@ -274,7 +328,7 @@ for (const [TYPE, interpreter] of TYPES) { class extends HTMLElement { constructor() { assign(super(), { - _wrap: Promise.withResolvers(), + _wrap: withResolvers(), srcCode: "", executed: false, }); @@ -288,7 +342,7 @@ for (const [TYPE, interpreter] of TYPES) { async connectedCallback() { if (!this.executed) { this.executed = true; - const isAsync = this.hasAttribute("async"); + const isAsync = !isSync(this); const { io, run, runAsync } = await this._wrap .promise; this.srcCode = await fetchSource( @@ -314,24 +368,3 @@ for (const [TYPE, interpreter] of TYPES) { // export the used config without allowing leaks through it exportedConfig[TYPE] = structuredClone(config); } - -/** - * 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}} - */ -function PyWorker(file, options) { - const hooks = hooked.get("py"); - // this propagates pyscript worker hooks without needing a pyscript - // bootstrap + it passes arguments and it defaults to `pyodide` - // as the interpreter to use in the worker, as all hooks assume that - // and as `pyodide` is the only default interpreter that can deal with - // all the features we need to deliver pyscript out there. - const xworker = XWorker.call(new Hook(null, hooks), file, { - type: "pyodide", - ...options, - }); - assign(xworker.sync, sync); - return xworker; -} diff --git a/pyscript.core/src/exceptions.js b/core/src/exceptions.js similarity index 100% rename from pyscript.core/src/exceptions.js rename to core/src/exceptions.js diff --git a/pyscript.core/src/fetch.js b/core/src/fetch.js similarity index 96% rename from pyscript.core/src/fetch.js rename to core/src/fetch.js index 4b8e60ba8ea..00879cae030 100644 --- a/pyscript.core/src/fetch.js +++ b/core/src/fetch.js @@ -1,7 +1,10 @@ import { FetchError, ErrorCode } from "./exceptions.js"; -import { getText } from "polyscript/exports"; -export { getText }; +/** + * @param {Response} response + * @returns + */ +export const getText = (response) => response.text(); /** * This is a fetch wrapper that handles any non 200 responses and throws a diff --git a/core/src/fs.js b/core/src/fs.js new file mode 100644 index 00000000000..4a58f48f7c1 --- /dev/null +++ b/core/src/fs.js @@ -0,0 +1,82 @@ +import IDBMap from "@webreflection/idb-map"; +import withResolvers from "@webreflection/utils/with-resolvers"; +import { assign } from "polyscript/exports"; +import { $$ } from "basic-devtools"; + +const stop = (event) => { + event.preventDefault(); + event.stopImmediatePropagation(); +}; + +// ⚠️ these two constants MUST be passed as `fs` +// within the worker onBeforeRunAsync hook! +export const NAMESPACE = "@pyscript.fs"; +export const ERROR = "storage permissions not granted"; + +export const idb = new IDBMap(NAMESPACE); + +/** + * Ask a user action via dialog and returns the directory handler once granted. + * @param {{id?:string, mode?:"read"|"readwrite", hint?:"desktop"|"documents"|"downloads"|"music"|"pictures"|"videos"}} options + * @returns {Promise} + */ +export const getFileSystemDirectoryHandle = async (options) => { + if (!("showDirectoryPicker" in globalThis)) { + return Promise.reject( + new Error("showDirectoryPicker is not supported"), + ); + } + + const { promise, resolve, reject } = withResolvers(); + + const how = { id: "pyscript", mode: "readwrite", ...options }; + if (options.hint) how.startIn = options.hint; + + const transient = async () => { + try { + /* eslint-disable */ + const handler = await showDirectoryPicker(how); + /* eslint-enable */ + if ((await handler.requestPermission(how)) === "granted") { + resolve(handler); + return true; + } + } catch ({ message }) { + console.warn(message); + } + return false; + }; + + // in case the user decided to attach the event itself + // as opposite of relying our dialog walkthrough + if (navigator.userActivation?.isActive) { + if (!(await transient())) reject(new Error(ERROR)); + } else { + const dialog = assign(document.createElement("dialog"), { + className: "pyscript-fs", + innerHTML: [ + "ℹ️ Persistent FileSystem
", + "

PyScript would like to access a local folder.

", + "
", + "
", + ].join(""), + }); + + const [ok, cancel] = $$("button", dialog); + + ok.addEventListener("click", async (event) => { + stop(event); + if (await transient()) dialog.close(); + }); + + cancel.addEventListener("click", async (event) => { + stop(event); + reject(new Error(ERROR)); + dialog.close(); + }); + + document.body.appendChild(dialog).showModal(); + } + + return promise; +}; diff --git a/pyscript.core/src/hooks.js b/core/src/hooks.js similarity index 80% rename from pyscript.core/src/hooks.js rename to core/src/hooks.js index 921ae6a9338..9f108c633bc 100644 --- a/pyscript.core/src/hooks.js +++ b/core/src/hooks.js @@ -2,7 +2,7 @@ import { typedSet } from "type-checked-collections"; import { dedent } from "polyscript/exports"; import toJSONCallback from "to-json-callback"; -import stdlib from "./stdlib.js"; +import { stdlib, optional } from "./stdlib.js"; export const main = (name) => hooks.main[name]; export const worker = (name) => hooks.worker[name]; @@ -15,10 +15,11 @@ const code = (hooks, branch, key, lib) => { }; }; -export const codeFor = (branch) => { +export const codeFor = (branch, type) => { + const pylib = type === "mpy" ? stdlib.replace(optional, "") : stdlib; const hooks = {}; - code(hooks, branch, `codeBeforeRun`, stdlib); - code(hooks, branch, `codeBeforeRunAsync`, stdlib); + code(hooks, branch, `codeBeforeRun`, pylib); + code(hooks, branch, `codeBeforeRunAsync`, pylib); code(hooks, branch, `codeAfterRun`); code(hooks, branch, `codeAfterRunAsync`); return hooks; @@ -45,7 +46,7 @@ export const createFunction = (self, name) => { const SetFunction = typedSet({ typeof: "function" }); const SetString = typedSet({ typeof: "string" }); -const inputFailure = ` +export const inputFailure = ` import builtins def input(prompt=""): raise Exception("\\n ".join([ @@ -87,7 +88,19 @@ export const hooks = { /** @type {Set} */ onBeforeRun: new SetFunction(), /** @type {Set} */ - onBeforeRunAsync: new SetFunction(), + onBeforeRunAsync: new SetFunction([ + ({ interpreter }) => { + interpreter.registerJsModule("_pyscript", { + // cannot be imported from fs.js + // because this code is stringified + fs: { + ERROR: "storage permissions not granted", + NAMESPACE: "@pyscript.fs", + }, + interpreter, + }); + }, + ]), /** @type {Set} */ onAfterRun: new SetFunction(), /** @type {Set} */ diff --git a/pyscript.core/src/plugins-helper.js b/core/src/plugins-helper.js similarity index 100% rename from pyscript.core/src/plugins-helper.js rename to core/src/plugins-helper.js diff --git a/core/src/plugins.js b/core/src/plugins.js new file mode 100644 index 00000000000..324b79542ee --- /dev/null +++ b/core/src/plugins.js @@ -0,0 +1,38 @@ +// ⚠️ This file is an artifact: DO NOT MODIFY +export default { + codemirror: () => + import( + /* webpackIgnore: true */ + "./plugins/codemirror.js" + ), + ["deprecations-manager"]: () => + import( + /* webpackIgnore: true */ + "./plugins/deprecations-manager.js" + ), + donkey: () => + import( + /* webpackIgnore: true */ + "./plugins/donkey.js" + ), + error: () => + import( + /* webpackIgnore: true */ + "./plugins/error.js" + ), + ["py-editor"]: () => + import( + /* webpackIgnore: true */ + "./plugins/py-editor.js" + ), + ["py-game"]: () => + import( + /* webpackIgnore: true */ + "./plugins/py-game.js" + ), + ["py-terminal"]: () => + import( + /* webpackIgnore: true */ + "./plugins/py-terminal.js" + ), +}; diff --git a/core/src/plugins/codemirror.js b/core/src/plugins/codemirror.js new file mode 100644 index 00000000000..491bc75f54e --- /dev/null +++ b/core/src/plugins/codemirror.js @@ -0,0 +1,31 @@ +// lazy loaded on-demand codemirror related files +export default { + get core() { + return import(/* webpackIgnore: true */ "../3rd-party/codemirror.js"); + }, + get state() { + return import( + /* webpackIgnore: true */ "../3rd-party/codemirror_state.js" + ); + }, + get python() { + return import( + /* webpackIgnore: true */ "../3rd-party/codemirror_lang-python.js" + ); + }, + get language() { + return import( + /* webpackIgnore: true */ "../3rd-party/codemirror_language.js" + ); + }, + get view() { + return import( + /* webpackIgnore: true */ "../3rd-party/codemirror_view.js" + ); + }, + get commands() { + return import( + /* webpackIgnore: true */ "../3rd-party/codemirror_commands.js" + ); + }, +}; diff --git a/pyscript.core/src/plugins/deprecations-manager.js b/core/src/plugins/deprecations-manager.js similarity index 100% rename from pyscript.core/src/plugins/deprecations-manager.js rename to core/src/plugins/deprecations-manager.js index f57d18bd064..b9ce9356788 100644 --- a/pyscript.core/src/plugins/deprecations-manager.js +++ b/core/src/plugins/deprecations-manager.js @@ -1,6 +1,6 @@ // PyScript Derepcations Plugin -import { hooks } from "../core.js"; import { notify } from "./error.js"; +import { hooks } from "../core.js"; // react lazily on PyScript bootstrap hooks.main.onReady.add(checkDeprecations); diff --git a/core/src/plugins/donkey.js b/core/src/plugins/donkey.js new file mode 100644 index 00000000000..2f7fbb08467 --- /dev/null +++ b/core/src/plugins/donkey.js @@ -0,0 +1,121 @@ +import addPromiseListener from "add-promise-listener"; +import { assign, dedent } from "polyscript/exports"; + +const { stringify } = JSON; + +const invoke = (name, args) => `${name}(code, ${args.join(", ")})`; + +const donkey = ({ + type = "py", + persistent, + terminal, + config, + serviceWorker, +}) => { + const globals = terminal ? '{"__terminal__":__terminal__}' : "{}"; + const args = persistent ? ["globals()", "__locals__"] : [globals, "{}"]; + + const src = URL.createObjectURL( + new Blob([ + [ + // this array is to better minify this code once in production + "from pyscript import sync, config", + '__message__ = lambda e,v: f"\x1b[31m\x1b[1m{e.__name__}\x1b[0m: {v}"', + "__locals__ = {}", + 'if config["type"] == "py":', + " import sys", + " def __error__(_):", + " info = sys.exc_info()", + " return __message__(info[0], info[1])", + "else:", + " __error__ = lambda e: __message__(e.__class__, e.value)", + "def execute(code):", + ` try: return ${invoke("exec", args)};`, + " except Exception as e: print(__error__(e));", + "def evaluate(code):", + ` try: return ${invoke("eval", args)};`, + " except Exception as e: print(__error__(e));", + "sync.execute = execute", + "sync.evaluate = evaluate", + ].join("\n"), + ]), + ); + + // create the script that exposes the code to execute or evaluate + const script = assign(document.createElement("script"), { type, src }); + script.toggleAttribute("worker", true); + script.toggleAttribute("terminal", true); + if (terminal) script.setAttribute("target", terminal); + if (config) { + script.setAttribute( + "config", + typeof config === "string" ? config : stringify(config), + ); + } + if (serviceWorker) script.setAttribute("service-worker", serviceWorker); + + return addPromiseListener( + document.body.appendChild(script), + `${type}:done`, + { stopPropagation: true }, + ).then(() => { + URL.revokeObjectURL(src); + return script; + }); +}; + +const utils = async (options) => { + const script = await donkey(options); + const { xworker, process, terminal } = script; + const { execute, evaluate } = xworker.sync; + script.remove(); + return { + xworker, + process, + terminal, + execute, + evaluate, + }; +}; + +export default async (options = {}) => { + let farmer = await utils(options); + let working = false; + const kill = () => { + if (farmer) { + farmer.xworker.terminate(); + farmer.terminal.dispose(); + farmer = null; + } + working = false; + }; + const reload = async () => { + kill(); + farmer = await utils(options); + }; + const asyncTask = (method) => async (code) => { + // race condition ... a new task has been + // assigned while the previous one didn't finish + if (working) await reload(); + working = true; + try { + return await farmer[method](dedent(code)); + } catch (e) { + console.error(e); + } finally { + working = false; + } + }; + const asyncMethod = (method) => async () => { + if (working) await reload(); + else farmer?.terminal[method](); + }; + return { + process: asyncTask("process"), + execute: asyncTask("execute"), + evaluate: asyncTask("evaluate"), + clear: asyncMethod("clear"), + reset: asyncMethod("reset"), + kill, + }; +}; diff --git a/pyscript.core/src/plugins/error.js b/core/src/plugins/error.js similarity index 82% rename from pyscript.core/src/plugins/error.js rename to core/src/plugins/error.js index 7eb3dde2b42..2ff353131ee 100644 --- a/pyscript.core/src/plugins/error.js +++ b/core/src/plugins/error.js @@ -1,6 +1,12 @@ // PyScript Error Plugin +import { buffered } from "polyscript/exports"; import { hooks } from "../core.js"; +let dontBotherDOM = false; +export function notOnDOM() { + dontBotherDOM = true; +} + hooks.main.onReady.add(function override(pyScript) { // be sure this override happens only once hooks.main.onReady.delete(override); @@ -8,13 +14,15 @@ hooks.main.onReady.add(function override(pyScript) { // trap generic `stderr` to propagate to it regardless const { stderr } = pyScript.io; - // override it with our own logic - pyScript.io.stderr = (error, ...rest) => { + const cb = (error, ...rest) => { notify(error.message || error); // let other plugins or stderr hook, if any, do the rest return stderr(error, ...rest); }; + // override it with our own logic + pyScript.io.stderr = pyScript.type === "py" ? cb : buffered(cb); + // be sure uncaught Python errors are also visible addEventListener("error", ({ message }) => { if (message.startsWith("Uncaught PythonError")) notify(message); @@ -30,6 +38,7 @@ hooks.main.onReady.add(function override(pyScript) { * @param {string} message */ export function notify(message) { + if (dontBotherDOM) return; const div = document.createElement("div"); div.className = "py-error"; div.textContent = message; diff --git a/core/src/plugins/py-editor.js b/core/src/plugins/py-editor.js new file mode 100644 index 00000000000..39a918564c9 --- /dev/null +++ b/core/src/plugins/py-editor.js @@ -0,0 +1,467 @@ +// PyScript py-editor plugin +import withResolvers from "@webreflection/utils/with-resolvers"; +import { Hook, XWorker, dedent, defineProperties } from "polyscript/exports"; +import { TYPES, offline_interpreter, relative_url, stdlib } from "../core.js"; +import { notify } from "./error.js"; +import codemirror from "./codemirror.js"; + +const RUN_BUTTON = ``; +const STOP_BUTTON = ``; + +let id = 0; +const getID = (type) => `${type}-editor-${id++}`; + +const envs = new Map(); +const configs = new Map(); +const editors = new WeakMap(); + +const hooks = { + worker: { + codeBeforeRun: () => stdlib, + // works on both Pyodide and MicroPython + onReady: ({ runAsync, io }, { sync }) => { + io.stdout = io.buffered(sync.write); + io.stderr = io.buffered(sync.writeErr); + sync.revoke(); + sync.runAsync = runAsync; + }, + }, +}; + +const validate = (config, result) => { + if (typeof result === "boolean") throw `Invalid source: ${config}`; + return result; +}; + +const getRelatedScript = (target, type) => { + const editor = target.closest(`.${type}-editor-box`); + return editor?.parentNode?.previousElementSibling; +}; + +async function execute({ currentTarget }) { + const { env, pySrc, outDiv } = this; + const hasRunButton = !!currentTarget; + + if (hasRunButton) { + currentTarget.classList.add("running"); + currentTarget.innerHTML = STOP_BUTTON; + outDiv.innerHTML = ""; + } + + if (!envs.has(env)) { + const srcLink = URL.createObjectURL(new Blob([""])); + const details = { + type: this.interpreter, + serviceWorker: this.serviceWorker, + }; + const { config } = this; + if (config) { + // verify that config can be parsed and used + try { + details.configURL = relative_url(config); + if (config.endsWith(".toml")) { + const [{ parse }, toml] = await Promise.all([ + import( + /* webpackIgnore: true */ "../3rd-party/toml.js" + ), + fetch(config).then((r) => r.ok && r.text()), + ]); + details.config = parse(validate(config, toml)); + } else if (config.endsWith(".json")) { + const json = await fetch(config).then( + (r) => r.ok && r.json(), + ); + details.config = validate(config, json); + } else { + details.configURL = relative_url("./config.txt"); + details.config = JSON.parse(config); + } + details.version = offline_interpreter(details.config); + } catch (error) { + notify(error); + return; + } + } else { + details.config = {}; + } + + const xworker = XWorker.call(new Hook(null, hooks), srcLink, details); + + // expose xworker like in terminal or other workers to allow + // creation and destruction of editors on the fly + if (hasRunButton) { + for (const type of TYPES.keys()) { + const script = getRelatedScript(currentTarget, type); + if (script) { + defineProperties(script, { xworker: { value: xworker } }); + break; + } + } + } + + const { sync } = xworker; + const { promise, resolve } = withResolvers(); + envs.set(env, promise); + sync.revoke = () => { + URL.revokeObjectURL(srcLink); + resolve(xworker); + }; + } + + // wait for the env then set the target div + // before executing the current code + return envs.get(env).then((xworker) => { + xworker.onerror = ({ error }) => { + if (hasRunButton) { + outDiv.insertAdjacentHTML( + "beforeend", + `${ + error.message || error + }\n`, + ); + } + console.error(error); + }; + + const enable = () => { + if (hasRunButton) { + currentTarget.classList.remove("running"); + currentTarget.innerHTML = RUN_BUTTON; + const { previousElementSibling } = + currentTarget.closest("[data-env]").parentElement; + previousElementSibling?.dispatchEvent( + new Event("py-editor:done", { + bubbles: true, + cancelable: true, + }), + ); + } + }; + const { sync } = xworker; + sync.write = (str) => { + if (hasRunButton) outDiv.innerText += `${str}\n`; + else console.log(str); + }; + sync.writeErr = (str) => { + if (hasRunButton) { + outDiv.insertAdjacentHTML( + "beforeend", + `${str}\n`, + ); + } else { + notify(str); + console.error(str); + } + }; + sync.runAsync(pySrc).then(enable, enable); + }); +} + +const makeRunButton = (handler, type) => { + const runButton = document.createElement("button"); + runButton.className = `absolute ${type}-editor-run-button`; + runButton.innerHTML = RUN_BUTTON; + runButton.setAttribute("aria-label", "Python Script Run Button"); + runButton.addEventListener("click", async (event) => { + if ( + runButton.classList.contains("running") && + confirm("Stop evaluating this code?") + ) { + const script = getRelatedScript(runButton, type); + if (script) { + const editor = editors.get(script); + const content = editor.state.doc.toString(); + const clone = script.cloneNode(true); + clone.type = `${type}-editor`; + clone.textContent = content; + script.xworker.terminate(); + script.nextElementSibling.remove(); + script.replaceWith(clone); + editors.delete(script); + } + return; + } + runButton.blur(); + await handler.handleEvent(event); + }); + return runButton; +}; + +const makeEditorDiv = (handler, type) => { + const editorDiv = document.createElement("div"); + editorDiv.className = `${type}-editor-input`; + editorDiv.setAttribute("aria-label", "Python Script Area"); + + const runButton = makeRunButton(handler, type); + const editorShadowContainer = document.createElement("div"); + + // avoid outer elements intercepting key events (reveal as example) + editorShadowContainer.addEventListener("keydown", (event) => { + event.stopPropagation(); + }); + + editorDiv.append(runButton, editorShadowContainer); + + return editorDiv; +}; + +const makeOutDiv = (type) => { + const outDiv = document.createElement("div"); + outDiv.className = `${type}-editor-output`; + outDiv.id = `${getID(type)}-output`; + return outDiv; +}; + +const makeBoxDiv = (handler, type) => { + const boxDiv = document.createElement("div"); + boxDiv.className = `${type}-editor-box`; + + const editorDiv = makeEditorDiv(handler, type); + const outDiv = makeOutDiv(type); + boxDiv.append(editorDiv, outDiv); + + return [boxDiv, outDiv, editorDiv.querySelector("button")]; +}; + +const init = async (script, type, interpreter) => { + const [ + { basicSetup, EditorView }, + { Compartment }, + { python }, + { indentUnit }, + { keymap }, + { defaultKeymap, indentWithTab }, + ] = await Promise.all([ + codemirror.core, + codemirror.state, + codemirror.python, + codemirror.language, + codemirror.view, + codemirror.commands, + ]); + + let isSetup = script.hasAttribute("setup"); + const hasConfig = script.hasAttribute("config"); + const serviceWorker = script.getAttribute("service-worker"); + const env = `${interpreter}-${script.getAttribute("env") || getID(type)}`; + + // helps preventing too lazy ServiceWorker initialization on button run + if (serviceWorker) { + new XWorker("data:application/javascript,postMessage(0)", { + type: "dummy", + serviceWorker, + }).onmessage = ({ target }) => target.terminate(); + } + + if (hasConfig && configs.has(env)) { + throw new SyntaxError( + configs.get(env) + ? `duplicated config for env: ${env}` + : `unable to add a config to the env: ${env}`, + ); + } + + configs.set(env, hasConfig); + + let source = script.textContent; + + // verify the src points to a valid file that can be parsed + const { src } = script; + if (src) { + try { + source = validate( + src, + await fetch(src).then((b) => b.ok && b.text()), + ); + } catch (error) { + notify(error); + return; + } + } + + const context = { + // allow the listener to be overridden at distance + handleEvent: execute, + serviceWorker, + interpreter, + env, + config: hasConfig && script.getAttribute("config"), + get pySrc() { + return isSetup ? source : editor.state.doc.toString(); + }, + get outDiv() { + return isSetup ? null : outDiv; + }, + }; + + let target; + defineProperties(script, { + target: { get: () => target }, + handleEvent: { + get: () => context.handleEvent, + set: (callback) => { + // do not bother with logic if it was set back as its original handler + if (callback === execute) context.handleEvent = execute; + // in every other case be sure that if the listener override returned + // `false` nothing happens, otherwise keep doing what it always did + else { + context.handleEvent = async (event) => { + // trap the currentTarget ASAP (if any) + // otherwise it gets lost asynchronously + const { currentTarget } = event; + // augment a code snapshot before invoking the override + defineProperties(event, { + code: { value: context.pySrc }, + }); + // avoid executing the default handler if the override returned `false` + if ((await callback(event)) !== false) + await execute.call(context, { currentTarget }); + }; + } + }, + }, + code: { + get: () => context.pySrc, + set: (insert) => { + if (isSetup) return; + editor.update([ + editor.state.update({ + changes: { + from: 0, + to: editor.state.doc.length, + insert, + }, + }), + ]); + }, + }, + process: { + /** + * Simulate a setup node overriding the source to evaluate. + * @param {string} code the Python code to evaluate. + * @param {boolean} asRunButtonAction invoke the `Run` button handler. + * @returns {Promise<...>} fulfill once code has been evaluated. + */ + value(code, asRunButtonAction = false) { + if (asRunButtonAction) return listener(); + const wasSetup = isSetup; + const wasSource = source; + isSetup = true; + source = code; + const restore = () => { + isSetup = wasSetup; + source = wasSource; + }; + return context + .handleEvent({ currentTarget: null }) + .then(restore, restore); + }, + }, + }); + + const notifyEditor = () => { + const event = new Event(`${type}-editor`, { bubbles: true }); + script.dispatchEvent(event); + }; + + if (isSetup) { + await context.handleEvent({ currentTarget: null }); + notifyEditor(); + return; + } + + const selector = script.getAttribute("target"); + + if (selector) { + target = + document.getElementById(selector) || + document.querySelector(selector); + if (!target) throw new Error(`Unknown target ${selector}`); + } else { + target = document.createElement(`${type}-editor`); + target.style.display = "block"; + script.after(target); + } + + if (!target.id) target.id = getID(type); + if (!target.hasAttribute("exec-id")) target.setAttribute("exec-id", 0); + if (!target.hasAttribute("root")) target.setAttribute("root", target.id); + + // @see https://github.com/JeffersGlass/mkdocs-pyscript/blob/main/mkdocs_pyscript/js/makeblocks.js + const [boxDiv, outDiv, runButton] = makeBoxDiv(context, type); + boxDiv.dataset.env = script.hasAttribute("env") ? env : interpreter; + + const inputChild = boxDiv.querySelector(`.${type}-editor-input > div`); + const parent = inputChild.attachShadow({ mode: "open" }); + // avoid inheriting styles from the outer component + parent.innerHTML = ``; + + target.appendChild(boxDiv); + + const doc = dedent(script.textContent).trim(); + + // preserve user indentation, if any + const indentation = /^([ \t]+)/m.test(doc) ? RegExp.$1 : " "; + + const listener = () => runButton.click(); + const editor = new EditorView({ + extensions: [ + indentUnit.of(indentation), + new Compartment().of(python()), + keymap.of([ + ...defaultKeymap, + { key: "Ctrl-Enter", run: listener, preventDefault: true }, + { key: "Cmd-Enter", run: listener, preventDefault: true }, + { key: "Shift-Enter", run: listener, preventDefault: true }, + // @see https://codemirror.net/examples/tab/ + indentWithTab, + ]), + basicSetup, + ], + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + parent, + doc, + }); + + editors.set(script, editor); + editor.focus(); + notifyEditor(); +}; + +// avoid too greedy MutationObserver operations at distance +let timeout = 0; + +// avoid delayed initialization +let queue = Promise.resolve(); + +// reset interval value then check for new scripts +const resetTimeout = () => { + timeout = 0; + pyEditor(); +}; + +// triggered both ASAP on the living DOM and via MutationObserver later +const pyEditor = () => { + if (timeout) return; + timeout = setTimeout(resetTimeout, 250); + for (const [type, interpreter] of TYPES) { + const selector = `script[type="${type}-editor"]`; + for (const script of document.querySelectorAll(selector)) { + // avoid any further bootstrap by changing the type as active + script.type += "-active"; + // don't await in here or multiple calls might happen + // while the first script is being initialized + queue = queue.then(() => init(script, type, interpreter)); + } + } + return queue; +}; + +new MutationObserver(pyEditor).observe(document, { + childList: true, + subtree: true, +}); + +// try to check the current document ASAP +export default pyEditor(); diff --git a/core/src/plugins/py-game.js b/core/src/plugins/py-game.js new file mode 100644 index 00000000000..7ceb7652369 --- /dev/null +++ b/core/src/plugins/py-game.js @@ -0,0 +1,112 @@ +import { + dedent, + define, + createProgress, + loadProgress, +} from "polyscript/exports"; + +import { stdlib } from "../core.js"; +import { configDetails } from "../config.js"; +import { getText } from "../fetch.js"; + +const progress = createProgress("py-game"); + +const inputPatch = ` +import builtins +def input(prompt=""): + import js + return js.prompt(prompt) + +builtins.input = input +del builtins +del input +`; + +let toBeWarned = true; + +const hooks = { + main: { + onReady: async (wrap, script) => { + if (toBeWarned) { + toBeWarned = false; + console.warn("⚠️ EXPERIMENTAL `py-game` FEATURE"); + } + + let config = {}; + if (script.hasAttribute("config")) { + const value = script.getAttribute("config"); + const { json, toml, text, url } = await configDetails(value); + if (json) config = JSON.parse(text); + else if (toml) { + const { parse } = await import( + /* webpackIgnore: true */ "../3rd-party/toml.js" + ); + config = parse(text); + } + if (config.packages) { + await wrap.interpreter.loadPackage("micropip"); + const micropip = wrap.interpreter.pyimport("micropip"); + await micropip.install(config.packages, { + keep_going: true, + }); + micropip.destroy(); + } + await loadProgress( + "py-game", + progress, + wrap.interpreter, + config, + url ? new URL(url, location.href).href : location.href, + ); + } + + wrap.interpreter.registerJsModule("_pyscript", { + PyWorker() { + throw new Error( + "Unable to use PyWorker in py-game scripts", + ); + }, + js_import: (...urls) => + Promise.all(urls.map((url) => import(url))), + get target() { + return script.id; + }, + }); + + await wrap.interpreter.runPythonAsync(stdlib); + wrap.interpreter.runPython(inputPatch); + + let code = dedent(script.textContent); + if (script.src) code = await fetch(script.src).then(getText); + + const target = script.getAttribute("target") || "canvas"; + const canvas = document.getElementById(target); + wrap.interpreter.canvas.setCanvas2D(canvas); + + // allow 3rd party to hook themselves right before + // the code gets executed + const event = new CustomEvent("py-game", { + bubbles: true, + cancelable: true, + detail: { + canvas, + code, + config, + wrap, + }, + }); + script.dispatchEvent(event); + // run only if the default was not prevented + if (!event.defaultPrevented) + await wrap.interpreter.runPythonAsync(code); + }, + }, +}; + +define("py-game", { + config: { packages: ["pygame-ce"] }, + configURL: new URL("./config.txt", location.href).href, + interpreter: "pyodide", + env: "py-game", + hooks, +}); diff --git a/core/src/plugins/py-terminal.js b/core/src/plugins/py-terminal.js new file mode 100644 index 00000000000..cd61483a488 --- /dev/null +++ b/core/src/plugins/py-terminal.js @@ -0,0 +1,60 @@ +// PyScript py-terminal plugin +import { TYPES, relative_url } from "../core.js"; +import { notify } from "./error.js"; +import { customObserver } from "polyscript/exports"; + +// will contain all valid selectors +const SELECTORS = []; + +// avoid processing same elements twice +const processed = new WeakSet(); + +// show the error on main and +// stops the module from keep executing +const notifyAndThrow = (message) => { + notify(message); + throw new Error(message); +}; + +const onceOnMain = ({ attributes: { worker } }) => !worker; + +let addStyle = true; + +for (const type of TYPES.keys()) { + const selector = `script[type="${type}"][terminal],${type}-script[terminal]`; + SELECTORS.push(selector); + customObserver.set(selector, async (element) => { + // we currently support only one terminal on main as in "classic" + const terminals = document.querySelectorAll(SELECTORS.join(",")); + if ([].filter.call(terminals, onceOnMain).length > 1) + notifyAndThrow("You can use at most 1 main terminal"); + + // import styles lazily + if (addStyle) { + addStyle = false; + document.head.append( + Object.assign(document.createElement("link"), { + rel: "stylesheet", + href: relative_url("./xterm.css", import.meta.url), + }), + ); + } + + if (processed.has(element)) return; + processed.add(element); + + const bootstrap = (module) => module.default(element); + + // we can't be smart with template literals for the dynamic import + // or bundlers are incapable of producing multiple files around + if (type === "mpy") { + await import(/* webpackIgnore: true */ "./py-terminal/mpy.js").then( + bootstrap, + ); + } else { + await import(/* webpackIgnore: true */ "./py-terminal/py.js").then( + bootstrap, + ); + } + }); +} diff --git a/core/src/plugins/py-terminal/mpy.js b/core/src/plugins/py-terminal/mpy.js new file mode 100644 index 00000000000..a54d35c1a2a --- /dev/null +++ b/core/src/plugins/py-terminal/mpy.js @@ -0,0 +1,256 @@ +// PyScript pyodide terminal plugin +import withResolvers from "@webreflection/utils/with-resolvers"; +import { defineProperties } from "polyscript/exports"; +import { hooks, inputFailure } from "../../core.js"; + +const bootstrapped = new WeakSet(); + +// this callback will be serialized as string and it never needs +// to be invoked multiple times. Each xworker here is bootstrapped +// only once thanks to the `sync.is_pyterminal()` check. +const workerReady = ({ interpreter, io, run, type }, { sync }) => { + if (type !== "mpy" || !sync.is_pyterminal()) return; + + const { pyterminal_ready, pyterminal_read, pyterminal_write } = sync; + + interpreter.registerJsModule("_pyscript_input", { + input: pyterminal_read, + }); + + run( + [ + "from _pyscript_input import input", + "from polyscript import currentScript as _", + "__terminal__ = _.terminal", + "del _", + ].join(";"), + ); + + const missingReturn = new Uint8Array([13]); + io.stdout = (buffer) => { + if (buffer[0] === 10) pyterminal_write(missingReturn); + pyterminal_write(buffer); + }; + io.stderr = (error) => { + pyterminal_write(String(error.message || error)); + }; + + sync.pyterminal_stream_write = () => {}; + + // tiny shim of the code module with only interact + // to bootstrap a REPL like environment + interpreter.registerJsModule("code", { + interact() { + const encoder = new TextEncoderStream(); + encoder.readable.pipeTo( + new WritableStream({ + write(buffer) { + for (const c of buffer) interpreter.replProcessChar(c); + }, + }), + ); + + const writer = encoder.writable.getWriter(); + sync.pyterminal_stream_write = (buffer) => writer.write(buffer); + + interpreter.replInit(); + }, + }); + + pyterminal_ready(); +}; + +export default async (element) => { + // lazy load these only when a valid terminal is found + const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all([ + import(/* webpackIgnore: true */ "../../3rd-party/xterm.js"), + import(/* webpackIgnore: true */ "../../3rd-party/xterm_addon-fit.js"), + import( + /* webpackIgnore: true */ "../../3rd-party/xterm_addon-web-links.js" + ), + ]); + + const terminalOptions = { + disableStdin: false, + cursorBlink: true, + cursorStyle: "block", + lineHeight: 1.2, + }; + + let stream; + + // common main thread initialization for both worker + // or main case, bootstrapping the terminal on its target + const init = () => { + let target = element; + const selector = element.getAttribute("target"); + if (selector) { + target = + document.getElementById(selector) || + document.querySelector(selector); + if (!target) throw new Error(`Unknown target ${selector}`); + } else { + target = document.createElement("py-terminal"); + target.style.display = "block"; + element.after(target); + } + const terminal = new Terminal({ + theme: { + background: "#191A19", + foreground: "#F5F2E7", + }, + ...terminalOptions, + }); + const fitAddon = new FitAddon(); + terminal.loadAddon(fitAddon); + terminal.loadAddon(new WebLinksAddon()); + terminal.open(target); + fitAddon.fit(); + terminal.focus(); + defineProperties(element, { + terminal: { value: terminal }, + process: { + value: async (code) => { + for (const line of code.split(/(?:\r\n|\r|\n)/)) { + await stream.write(`${line}\r`); + } + }, + }, + }); + return terminal; + }; + + // branch logic for the worker + if (element.hasAttribute("worker")) { + // add a hook on the main thread to setup all sync helpers + // also bootstrapping the XTerm target on main *BUT* ... + hooks.main.onWorker.add(function worker(_, xworker) { + // ... as multiple workers will add multiple callbacks + // be sure no xworker is ever initialized twice! + if (bootstrapped.has(xworker)) return; + bootstrapped.add(xworker); + + // still cleanup this callback for future scripts/workers + hooks.main.onWorker.delete(worker); + + const terminal = init(); + + const { sync } = xworker; + + // handle the read mode on input + let promisedChunks = null; + let readChunks = ""; + + sync.is_pyterminal = () => true; + + // put the terminal in a read-only state + // frees the worker on \r + sync.pyterminal_read = (buffer) => { + terminal.write(buffer); + promisedChunks = withResolvers(); + return promisedChunks.promise; + }; + + // write if not reading input + sync.pyterminal_write = (buffer) => { + if (!promisedChunks) terminal.write(buffer); + }; + + // add the onData terminal listener which forwards to the worker + // everything typed in a queued char-by-char way + sync.pyterminal_ready = () => { + let queue = Promise.resolve(); + stream = { + write: (buffer) => + (queue = queue.then(() => + sync.pyterminal_stream_write(buffer), + )), + }; + terminal.onData((buffer) => { + if (promisedChunks) { + // handle backspace on input + if (buffer === "\x7f") { + // avoid over-greedy backspace + if (readChunks.length) { + readChunks = readChunks.slice(0, -1); + // override previous char position + // put an empty space to clear the char + // move back position again + buffer = "\b \b"; + } else buffer = ""; + } else readChunks += buffer; + if (buffer) { + terminal.write(buffer); + if (readChunks.endsWith("\r")) { + terminal.write("\n"); + promisedChunks.resolve(readChunks.slice(0, -1)); + promisedChunks = null; + readChunks = ""; + } + } + } else { + stream.write(buffer); + } + }); + }; + }); + + // setup remote thread JS/Python code for whenever the + // worker is ready to become a terminal + hooks.worker.onReady.add(workerReady); + } else { + // ⚠️ In an ideal world the inputFailure should never be used on main. + // However, Pyodide still can't compete with MicroPython REPL mode + // so while it's OK to keep that entry on main as default, we need + // to remove it ASAP from `mpy` use cases, otherwise MicroPython would + // also throw whenever an `input(...)` is required / digited. + hooks.main.codeBeforeRun.delete(inputFailure); + + // in the main case, just bootstrap XTerm without + // allowing any input as that's not possible / awkward + hooks.main.onReady.add(function main({ interpreter, io, run, type }) { + if (type !== "mpy") return; + + hooks.main.onReady.delete(main); + + const terminal = init(); + + const missingReturn = new Uint8Array([13]); + io.stdout = (buffer) => { + if (buffer[0] === 10) terminal.write(missingReturn); + terminal.write(buffer); + }; + + // expose the __terminal__ one-off reference + globalThis.__py_terminal__ = terminal; + run( + [ + "from js import prompt as input", + "from js import __py_terminal__ as __terminal__", + ].join(";"), + ); + delete globalThis.__py_terminal__; + + // NOTE: this is NOT the same as the one within + // the onWorkerReady callback! + interpreter.registerJsModule("code", { + interact() { + const encoder = new TextEncoderStream(); + encoder.readable.pipeTo( + new WritableStream({ + write(buffer) { + for (const c of buffer) + interpreter.replProcessChar(c); + }, + }), + ); + + stream = encoder.writable.getWriter(); + terminal.onData((buffer) => stream.write(buffer)); + + interpreter.replInit(); + }, + }); + }); + } +}; diff --git a/core/src/plugins/py-terminal/py.js b/core/src/plugins/py-terminal/py.js new file mode 100644 index 00000000000..ca35abeebed --- /dev/null +++ b/core/src/plugins/py-terminal/py.js @@ -0,0 +1,192 @@ +// PyScript py-terminal plugin +import { defineProperties } from "polyscript/exports"; +import { hooks } from "../../core.js"; + +const bootstrapped = new WeakSet(); + +// this callback will be serialized as string and it never needs +// to be invoked multiple times. Each xworker here is bootstrapped +// only once thanks to the `sync.is_pyterminal()` check. +const workerReady = ({ interpreter, io, run, type }, { sync }) => { + if (type !== "py" || !sync.is_pyterminal()) return; + + run( + [ + "from polyscript import currentScript as _", + "__terminal__ = _.terminal", + "del _", + ].join(";"), + ); + + let data = ""; + const { pyterminal_read, pyterminal_write } = sync; + const decoder = new TextDecoder(); + const generic = { + isatty: false, + write(buffer) { + data = decoder.decode(buffer); + pyterminal_write(data); + return buffer.length; + }, + }; + + io.stderr = (error) => { + pyterminal_write(String(error.message || error)); + }; + + interpreter.setStdout(generic); + interpreter.setStderr(generic); + interpreter.setStdin({ + isatty: false, + stdin: () => pyterminal_read(data), + }); +}; + +export default async (element) => { + // lazy load these only when a valid terminal is found + const [{ Terminal }, { Readline }, { FitAddon }, { WebLinksAddon }] = + await Promise.all([ + import(/* webpackIgnore: true */ "../../3rd-party/xterm.js"), + import( + /* webpackIgnore: true */ "../../3rd-party/xterm-readline.js" + ), + import( + /* webpackIgnore: true */ "../../3rd-party/xterm_addon-fit.js" + ), + import( + /* webpackIgnore: true */ "../../3rd-party/xterm_addon-web-links.js" + ), + ]); + + const readline = new Readline(); + + // common main thread initialization for both worker + // or main case, bootstrapping the terminal on its target + const init = (options) => { + let target = element; + const selector = element.getAttribute("target"); + if (selector) { + target = + document.getElementById(selector) || + document.querySelector(selector); + if (!target) throw new Error(`Unknown target ${selector}`); + } else { + target = document.createElement("py-terminal"); + target.style.display = "block"; + element.after(target); + } + const terminal = new Terminal({ + theme: { + background: "#191A19", + foreground: "#F5F2E7", + }, + ...options, + }); + const fitAddon = new FitAddon(); + terminal.loadAddon(fitAddon); + terminal.loadAddon(readline); + terminal.loadAddon(new WebLinksAddon()); + terminal.open(target); + fitAddon.fit(); + terminal.focus(); + defineProperties(element, { + terminal: { value: terminal }, + process: { + value: async (code) => { + for (const line of code.split(/(?:\r\n|\r|\n)/)) { + terminal.paste(`${line}`); + terminal.write("\r\n"); + do { + await new Promise((resolve) => + setTimeout(resolve, 0), + ); + } while (!readline.activeRead?.resolve); + readline.activeRead.resolve(line); + } + }, + }, + }); + return terminal; + }; + + // branch logic for the worker + if (element.hasAttribute("worker")) { + // add a hook on the main thread to setup all sync helpers + // also bootstrapping the XTerm target on main *BUT* ... + hooks.main.onWorker.add(function worker(_, xworker) { + // ... as multiple workers will add multiple callbacks + // be sure no xworker is ever initialized twice! + if (bootstrapped.has(xworker)) return; + bootstrapped.add(xworker); + + // still cleanup this callback for future scripts/workers + hooks.main.onWorker.delete(worker); + + init({ + disableStdin: false, + cursorBlink: true, + cursorStyle: "block", + lineHeight: 1.2, + }); + + xworker.sync.is_pyterminal = () => true; + xworker.sync.pyterminal_read = readline.read.bind(readline); + xworker.sync.pyterminal_write = readline.write.bind(readline); + }); + + // setup remote thread JS/Python code for whenever the + // worker is ready to become a terminal + hooks.worker.onReady.add(workerReady); + + // @see https://github.com/pyscript/pyscript/issues/2246 + const patchInput = [ + "import builtins as _b", + "from pyscript import sync as _s", + "_b.input = _s.pyterminal_read", + "del _b", + "del _s", + ].join("\n"); + + hooks.worker.codeBeforeRun.add(patchInput); + hooks.worker.codeBeforeRunAsync.add(patchInput); + } else { + // in the main case, just bootstrap XTerm without + // allowing any input as that's not possible / awkward + hooks.main.onReady.add(function main({ interpreter, io, run, type }) { + if (type !== "py") return; + + console.warn("py-terminal is read only on main thread"); + hooks.main.onReady.delete(main); + + // on main, it's easy to trash and clean the current terminal + globalThis.__py_terminal__ = init({ + disableStdin: true, + cursorBlink: false, + cursorStyle: "underline", + }); + run("from js import __py_terminal__ as __terminal__"); + delete globalThis.__py_terminal__; + + io.stderr = (error) => { + readline.write(String(error.message || error)); + }; + + let data = ""; + const decoder = new TextDecoder(); + const generic = { + isatty: false, + write(buffer) { + data = decoder.decode(buffer); + readline.write(data); + return buffer.length; + }, + }; + interpreter.setStdout(generic); + interpreter.setStderr(generic); + interpreter.setStdin({ + isatty: false, + stdin: () => readline.read(data), + }); + }); + } +}; diff --git a/core/src/service-worker.js b/core/src/service-worker.js new file mode 100644 index 00000000000..126f1a0f69c --- /dev/null +++ b/core/src/service-worker.js @@ -0,0 +1 @@ +import "polyscript/service-worker"; diff --git a/pyscript.core/src/stdlib.js b/core/src/stdlib.js similarity index 53% rename from pyscript.core/src/stdlib.js rename to core/src/stdlib.js index 48187729eb8..545a006e23e 100644 --- a/pyscript.core/src/stdlib.js +++ b/core/src/stdlib.js @@ -8,6 +8,27 @@ import pyscript from "./stdlib/pyscript.js"; +class Ignore extends Array { + #add = false; + #paths; + #array; + constructor(array, ...paths) { + super(); + this.#array = array; + this.#paths = paths; + } + push(...values) { + if (this.#add) super.push(...values); + return this.#array.push(...values); + } + path(path) { + for (const _path of this.#paths) { + // bails out at the first `true` value + if ((this.#add = path.startsWith(_path))) break; + } + } +} + const { entries } = Object; const python = [ @@ -16,16 +37,19 @@ const python = [ "_path = None", ]; +const ignore = new Ignore(python, "-"); + const write = (base, literal) => { for (const [key, value] of entries(literal)) { - python.push(`_path = _Path("${base}/${key}")`); + ignore.path(`${base}/${key}`); + ignore.push(`_path = _Path("${base}/${key}")`); if (typeof value === "string") { const code = JSON.stringify(value); - python.push(`_path.write_text(${code})`); + ignore.push(`_path.write_text(${code},encoding="utf-8")`); } else { // @see https://github.com/pyscript/pyscript/pull/1813#issuecomment-1781502909 - python.push(`if not _os.path.exists("${base}/${key}"):`); - python.push(" _path.mkdir(parents=True, exist_ok=True)"); + ignore.push(`if not _os.path.exists("${base}/${key}"):`); + ignore.push(" _path.mkdir(parents=True, exist_ok=True)"); write(`${base}/${key}`, value); } } @@ -42,4 +66,5 @@ python.push( ); python.push("\n"); -export default python.join("\n"); +export const stdlib = python.join("\n"); +export const optional = ignore.join("\n"); diff --git a/core/src/stdlib/pyscript.js b/core/src/stdlib/pyscript.js new file mode 100644 index 00000000000..3c4ea4f98f5 --- /dev/null +++ b/core/src/stdlib/pyscript.js @@ -0,0 +1,19 @@ +// ⚠️ This file is an artifact: DO NOT MODIFY +export default { + "pyscript": { + "__init__.py": "from polyscript import lazy_py_modules as py_import\nfrom pyscript.magic_js import RUNNING_IN_WORKER,PyWorker,config,current_target,document,js_import,js_modules,sync,window\nfrom pyscript.display import HTML,display\nfrom pyscript.fetch import fetch\nfrom pyscript.storage import Storage,storage\nfrom pyscript.websocket import WebSocket\nfrom pyscript.events import when,Event\nif not RUNNING_IN_WORKER:from pyscript.workers import create_named_worker,workers", + "display.py": "_L='_repr_mimebundle_'\n_K='image/svg+xml'\n_J='application/json'\n_I='__repr__'\n_H='savefig'\n_G='text/html'\n_F='image/jpeg'\n_E='application/javascript'\n_D='utf-8'\n_C='text/plain'\n_B='image/png'\n_A=None\nimport base64,html,io,re\nfrom pyscript.magic_js import current_target,document,window\n_MIME_METHODS={_H:_B,'_repr_javascript_':_E,'_repr_json_':_J,'_repr_latex':'text/latex','_repr_png_':_B,'_repr_jpeg_':_F,'_repr_pdf_':'application/pdf','_repr_svg_':_K,'_repr_markdown_':'text/markdown','_repr_html_':_G,_I:_C}\ndef _render_image(mime,value,meta):\n\tA=value\n\tif isinstance(A,bytes):A=base64.b64encode(A).decode(_D)\n\tB=re.compile('^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$')\n\tif len(A)>0 and not B.match(A):A=base64.b64encode(A.encode(_D)).decode(_D)\n\tC=f\"data:{mime};charset=utf-8;base64,{A}\";D=' '.join(['{k}=\"{v}\"'for(A,B)in meta.items()]);return f''\ndef _identity(value,meta):return value\n_MIME_RENDERERS={_C:html.escape,_G:_identity,_B:lambda value,meta:_render_image(_B,value,meta),_F:lambda value,meta:_render_image(_F,value,meta),_K:_identity,_J:_identity,_E:lambda value,meta:f\" + + + + +

+
+
diff --git a/pyscript.core/test/config-url.html b/core/tests/javascript/config-url.html
similarity index 51%
rename from pyscript.core/test/config-url.html
rename to core/tests/javascript/config-url.html
index eb0ad1ff31c..9f28969dd57 100644
--- a/pyscript.core/test/config-url.html
+++ b/core/tests/javascript/config-url.html
@@ -4,13 +4,21 @@
   
   
   PyScript Next Plugin
-  
-  
+  
+  
   
   
   
 
diff --git a/pyscript.core/test/config-url/config.json b/core/tests/javascript/config-url/config.json
similarity index 100%
rename from pyscript.core/test/config-url/config.json
rename to core/tests/javascript/config-url/config.json
diff --git a/pyscript.core/test/config-url/src/test.py b/core/tests/javascript/config-url/src/test.py
similarity index 100%
rename from pyscript.core/test/config-url/src/test.py
rename to core/tests/javascript/config-url/src/test.py
diff --git a/core/tests/javascript/config_type.html b/core/tests/javascript/config_type.html
new file mode 100644
index 00000000000..e75b60d6856
--- /dev/null
+++ b/core/tests/javascript/config_type.html
@@ -0,0 +1,23 @@
+
+
+
+    
+    
+    
+    
+
+
+    
+    
+
+
diff --git a/pyscript.core/test/a.py b/core/tests/javascript/fetch/a.py
similarity index 100%
rename from pyscript.core/test/a.py
rename to core/tests/javascript/fetch/a.py
diff --git a/pyscript.core/test/config.json b/core/tests/javascript/fetch/config.json
similarity index 100%
rename from pyscript.core/test/config.json
rename to core/tests/javascript/fetch/config.json
diff --git a/core/tests/javascript/fetch/index.html b/core/tests/javascript/fetch/index.html
new file mode 100644
index 00000000000..701a6d34f20
--- /dev/null
+++ b/core/tests/javascript/fetch/index.html
@@ -0,0 +1,95 @@
+
+
+    
+        
+        
+        
+    
+    
+      
+      
+      
+    
+
diff --git a/core/tests/javascript/ffi.html b/core/tests/javascript/ffi.html
new file mode 100644
index 00000000000..16f7ece424a
--- /dev/null
+++ b/core/tests/javascript/ffi.html
@@ -0,0 +1,26 @@
+
+
+    
+        
+        
+        PyScript FFI
+        
+        
+    
+    
+      
+      
+    
+
diff --git a/pyscript.core/test/hooks.html b/core/tests/javascript/hooks.html
similarity index 90%
rename from pyscript.core/test/hooks.html
rename to core/tests/javascript/hooks.html
index b706a15dbae..857ed4f5c22 100644
--- a/pyscript.core/test/hooks.html
+++ b/core/tests/javascript/hooks.html
@@ -4,13 +4,13 @@
   
   
   PyScript Next Plugin Bug?
-  
+  
   
 
 
-  
-  
 
diff --git a/core/tests/javascript/issue-2093/error.js b/core/tests/javascript/issue-2093/error.js
new file mode 100644
index 00000000000..e7dd853a03e
--- /dev/null
+++ b/core/tests/javascript/issue-2093/error.js
@@ -0,0 +1,6 @@
+const { error } = console;
+
+console.error = (...args) => {
+  error(...args);
+  document.documentElement.classList.add('errored');
+};
diff --git a/core/tests/javascript/issue-2093/index.html b/core/tests/javascript/issue-2093/index.html
new file mode 100644
index 00000000000..ff6720c1727
--- /dev/null
+++ b/core/tests/javascript/issue-2093/index.html
@@ -0,0 +1,16 @@
+
+
+    
+        
+        
+        
+        
+        
+    
+    
+      
+    
+
diff --git a/core/tests/javascript/js-storage.html b/core/tests/javascript/js-storage.html
new file mode 100644
index 00000000000..7a3d1f1e70c
--- /dev/null
+++ b/core/tests/javascript/js-storage.html
@@ -0,0 +1,28 @@
+
+
+
+    
+    
+    
+    
+
+
+  
+
+
diff --git a/pyscript.core/test/js_modules.html b/core/tests/javascript/js_modules.html
similarity index 90%
rename from pyscript.core/test/js_modules.html
rename to core/tests/javascript/js_modules.html
index b012c51660d..bb0c5e90557 100644
--- a/pyscript.core/test/js_modules.html
+++ b/core/tests/javascript/js_modules.html
@@ -3,8 +3,8 @@
 
     
     
-    
-    
+    
+    
 
 
     
diff --git a/pyscript.core/test/js_modules.js b/core/tests/javascript/js_modules.js
similarity index 100%
rename from pyscript.core/test/js_modules.js
rename to core/tests/javascript/js_modules.js
diff --git a/core/tests/javascript/loader/index.html b/core/tests/javascript/loader/index.html
new file mode 100644
index 00000000000..4e0bd4c81e9
--- /dev/null
+++ b/core/tests/javascript/loader/index.html
@@ -0,0 +1,29 @@
+
+
+
+  
+  
+  
+  
+
+
+  
+    packages = ["matplotlib"]
+  
+  
+
+
diff --git a/core/tests/javascript/media.html b/core/tests/javascript/media.html
new file mode 100644
index 00000000000..449fee1ef98
--- /dev/null
+++ b/core/tests/javascript/media.html
@@ -0,0 +1,39 @@
+
+
+
+  Pyodide Media Module Test
+  
+  
+
+
+

Pyodide Media Module Test

+
Running tests...
+ + + + diff --git a/core/tests/javascript/mpy-error.html b/core/tests/javascript/mpy-error.html new file mode 100644 index 00000000000..a8c62206bec --- /dev/null +++ b/core/tests/javascript/mpy-error.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/core/tests/javascript/mpy-no-error.html b/core/tests/javascript/mpy-no-error.html new file mode 100644 index 00000000000..6084dcc2388 --- /dev/null +++ b/core/tests/javascript/mpy-no-error.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/core/tests/javascript/mpy-no-error.toml b/core/tests/javascript/mpy-no-error.toml new file mode 100644 index 00000000000..4e7f1f7e4d3 --- /dev/null +++ b/core/tests/javascript/mpy-no-error.toml @@ -0,0 +1 @@ +plugins = ["!error"] diff --git a/pyscript.core/test/mpy.html b/core/tests/javascript/mpy.html similarity index 88% rename from pyscript.core/test/mpy.html rename to core/tests/javascript/mpy.html index 4f0ae4b69e4..1d928af0e4b 100644 --- a/pyscript.core/test/mpy.html +++ b/core/tests/javascript/mpy.html @@ -9,8 +9,8 @@ document.documentElement.classList.add('done'); }); - - + + + + diff --git a/pyscript.core/test/py-terminal-worker.html b/core/tests/javascript/py-terminal-worker.html similarity index 52% rename from pyscript.core/test/py-terminal-worker.html rename to core/tests/javascript/py-terminal-worker.html index 720e51e340f..ae791faec19 100644 --- a/pyscript.core/test/py-terminal-worker.html +++ b/core/tests/javascript/py-terminal-worker.html @@ -4,11 +4,12 @@ PyTerminal Main - - + + - + + diff --git a/core/tests/javascript/py-terminal.html b/core/tests/javascript/py-terminal.html new file mode 100644 index 00000000000..701d36217a8 --- /dev/null +++ b/core/tests/javascript/py-terminal.html @@ -0,0 +1,18 @@ + + + + + + PyTerminal + + + + + + + + diff --git a/core/tests/javascript/py-terminals.html b/core/tests/javascript/py-terminals.html new file mode 100644 index 00000000000..1e0c0132911 --- /dev/null +++ b/core/tests/javascript/py-terminals.html @@ -0,0 +1,27 @@ + + + + + + PyTerminal Main + + + + + + + + + diff --git a/core/tests/javascript/pyodide-cache/cached.toml b/core/tests/javascript/pyodide-cache/cached.toml new file mode 100644 index 00000000000..ec4f4aa85c5 --- /dev/null +++ b/core/tests/javascript/pyodide-cache/cached.toml @@ -0,0 +1 @@ +packages = ["numpy", "matplotlib"] diff --git a/core/tests/javascript/pyodide-cache/index.html b/core/tests/javascript/pyodide-cache/index.html new file mode 100644 index 00000000000..506997de05d --- /dev/null +++ b/core/tests/javascript/pyodide-cache/index.html @@ -0,0 +1,41 @@ + + + + + + + + + diff --git a/core/tests/javascript/pyodide-cache/index.py b/core/tests/javascript/pyodide-cache/index.py new file mode 100644 index 00000000000..de77e97fa59 --- /dev/null +++ b/core/tests/javascript/pyodide-cache/index.py @@ -0,0 +1,6 @@ +import numpy as np +import matplotlib as mpl + +# just do something with the packages +print(len(dir(np))) +print(len(dir(mpl))) diff --git a/core/tests/javascript/pyodide-cache/never.toml b/core/tests/javascript/pyodide-cache/never.toml new file mode 100644 index 00000000000..a13dd158b34 --- /dev/null +++ b/core/tests/javascript/pyodide-cache/never.toml @@ -0,0 +1,2 @@ +packages_cache = "never" +packages = ["numpy", "matplotlib"] diff --git a/core/tests/javascript/pyodide-lockfile/index.html b/core/tests/javascript/pyodide-lockfile/index.html new file mode 100644 index 00000000000..28ad1a3531a --- /dev/null +++ b/core/tests/javascript/pyodide-lockfile/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/core/tests/javascript/storage.html b/core/tests/javascript/storage.html new file mode 100644 index 00000000000..3aea830bf70 --- /dev/null +++ b/core/tests/javascript/storage.html @@ -0,0 +1,46 @@ + + + + + + @pyscript/core storage + + + + + + + diff --git a/pyscript.core/test/terminal.py b/core/tests/javascript/terminal.py similarity index 100% rename from pyscript.core/test/terminal.py rename to core/tests/javascript/terminal.py diff --git a/core/tests/javascript/workers/config.toml b/core/tests/javascript/workers/config.toml new file mode 100644 index 00000000000..7cb628e8bd5 --- /dev/null +++ b/core/tests/javascript/workers/config.toml @@ -0,0 +1,2 @@ +[files] +"./test.py" = "./test.py" diff --git a/core/tests/javascript/workers/create_named/index.html b/core/tests/javascript/workers/create_named/index.html new file mode 100644 index 00000000000..faedf30403f --- /dev/null +++ b/core/tests/javascript/workers/create_named/index.html @@ -0,0 +1,18 @@ + + + + mpy using py named worker + + + + + + + + diff --git a/core/tests/javascript/workers/mpy/index.html b/core/tests/javascript/workers/mpy/index.html new file mode 100644 index 00000000000..31d74920630 --- /dev/null +++ b/core/tests/javascript/workers/mpy/index.html @@ -0,0 +1,16 @@ + + + + mpy using py named worker + + + + + + + + + diff --git a/core/tests/javascript/workers/py/index.html b/core/tests/javascript/workers/py/index.html new file mode 100644 index 00000000000..46c2117fb66 --- /dev/null +++ b/core/tests/javascript/workers/py/index.html @@ -0,0 +1,16 @@ + + + + py using mpy named worker + + + + + + + + + diff --git a/core/tests/javascript/workers/test.py b/core/tests/javascript/workers/test.py new file mode 100644 index 00000000000..08b5dc70f2d --- /dev/null +++ b/core/tests/javascript/workers/test.py @@ -0,0 +1,13 @@ +from pyscript import document, workers + + +async def test(name): + # retrieve sync utilities from the named worker + named = await workers[name] + + # invoke the runtime_version __export__ + show it + version = await named.runtime_version() + document.body.append(version) + + # flag the expectations around name done + document.documentElement.classList.add(name) diff --git a/core/tests/javascript/workers/worker.py b/core/tests/javascript/workers/worker.py new file mode 100644 index 00000000000..3b81275327a --- /dev/null +++ b/core/tests/javascript/workers/worker.py @@ -0,0 +1,7 @@ +def runtime_version(): + import sys + + return sys.version + + +__export__ = ["runtime_version"] diff --git a/core/tests/javascript/ws/index.html b/core/tests/javascript/ws/index.html new file mode 100644 index 00000000000..323b8cb3ff1 --- /dev/null +++ b/core/tests/javascript/ws/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/core/tests/javascript/ws/index.js b/core/tests/javascript/ws/index.js new file mode 100644 index 00000000000..d26d84f942c --- /dev/null +++ b/core/tests/javascript/ws/index.js @@ -0,0 +1,35 @@ +import { serve, file } from 'bun'; + +import path, { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; + +const dir = dirname(fileURLToPath(import.meta.url)); + +console.log('http://localhost:5037/'); + +serve({ + port: 5037, + fetch(req, server) { + if (server.upgrade(req)) return; + const url = new URL(req.url); + let { pathname } = url; + if (pathname === '/') pathname = '/index.html'; + else if (/^\/dist\//.test(pathname)) pathname = `/../../..${pathname}`; + else if (pathname === '/favicon.ico') + return new Response('Not Found', { status: 404 }); + const response = new Response(file(`${dir}${pathname}`)); + const { headers } = response; + headers.set('Cross-Origin-Opener-Policy', 'same-origin'); + headers.set('Cross-Origin-Embedder-Policy', 'require-corp'); + headers.set('Cross-Origin-Resource-Policy', 'cross-origin'); + return response; + }, + websocket: { + message(ws, message) { + ws.send(message); + }, + close() { + process.exit(0); + } + }, +}); diff --git a/core/tests/javascript/ws/index.spec.js b/core/tests/javascript/ws/index.spec.js new file mode 100644 index 00000000000..669be352f8a --- /dev/null +++ b/core/tests/javascript/ws/index.spec.js @@ -0,0 +1,6 @@ +import { test, expect } from '@playwright/test'; + +test('MicroPython WebSocket', async ({ page }) => { + await page.goto('http://localhost:5037/'); + await page.waitForSelector('html.ok'); +}); diff --git a/core/tests/js_tests.spec.js b/core/tests/js_tests.spec.js new file mode 100644 index 00000000000..b891b4095a7 --- /dev/null +++ b/core/tests/js_tests.spec.js @@ -0,0 +1,194 @@ +import { test, expect } from '@playwright/test'; + +test.setTimeout(120 * 1000); + +test('MicroPython display', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/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/tests/javascript/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')); +}); + +test('MicroPython + Pyodide js_modules', async ({ page }) => { + const logs = []; + page.on('console', msg => { + const text = msg.text(); + if (!text.startsWith('[')) + logs.push(text); + }); + await page.goto('http://localhost:8080/tests/javascript/js_modules.html'); + await page.waitForSelector('html.done'); + await expect(logs.length).toBe(6); + await expect(logs[0]).toBe(logs[1]); + await expect(logs[1]).toBe(logs[2]); + await expect(logs[3]).toBe(logs[4]); + await expect(logs[4]).toBe(logs[5]); +}); + +test('MicroPython + configURL', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/config-url.html'); + await page.waitForSelector('html.main.worker'); +}); + +test('Pyodide + terminal on Main', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/py-terminal-main.html'); + await page.waitForSelector('html.ok'); +}); + + +test('Pyodide + terminal on Worker', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/py-terminal-worker.html'); + await page.waitForSelector('html.ok'); +}); + +test('Pyodide + multiple terminals via Worker', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/py-terminals.html'); + await page.waitForSelector('html.first.second'); +}); + +test('MicroPython + Pyodide fetch', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/fetch/index.html'); + await page.waitForSelector('html.mpy.py'); +}); + +test('MicroPython + Pyodide ffi', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/ffi.html'); + await page.waitForSelector('html.mpy.py'); +}); + +test('MicroPython + Storage', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/storage.html'); + await page.waitForSelector('html.ok'); +}); + +test('MicroPython + JS Storage', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/js-storage.html'); + await page.waitForSelector('html.ok'); +}); + +test('MicroPython using named Pyodide Worker', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/workers/mpy/index.html'); + await page.waitForSelector('html.pyodide_version'); +}); + +test('MicroPython creating a named Pyodide Worker', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/workers/create_named/index.html'); + await page.waitForSelector('html.pyodide_version'); +}); + +test('Pyodide using named MicroPython Worker', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/workers/py/index.html'); + await page.waitForSelector('html.micropython_version'); +}); + +test('MicroPython Editor setup error', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/issue-2093/index.html'); + await page.waitForSelector('html.errored'); +}); + +test('MicroPython async @when listener', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/async-listener.html'); + await page.waitForSelector('html.ok'); +}); + +test('Pyodide loader', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/loader/index.html'); + await page.waitForSelector('html.ok'); + const body = await page.evaluate(() => document.body.textContent); + await expect(body.includes('Loaded Pyodide')).toBe(true); +}); + +test('Py and Mpy config["type"]', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/config_type.html'); + await page.waitForSelector('html.mpy.py'); +}); + +test('Pyodide lockFileURL vs CDN', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/pyodide-cache/'); + await page.waitForSelector('html.done'); + const body = await page.evaluate(() => document.body.textContent); + await expect(body).toBe('OK'); +}); + +test('Pyodide pinned lockFileURL', async ({ page }) => { + const logs = []; + page.on('console', msg => { + const text = msg.text(); + if (!text.startsWith('[')) + logs.push(text); + }); + await page.goto('http://localhost:8080/tests/javascript/pyodide-lockfile/'); + await page.waitForSelector('html.done'); + let body = await page.evaluate(() => document.body.lastChild.textContent); + await expect(body).toBe('OK'); + await expect(!!logs.splice(0).length).toBe(true); + await page.reload(); + await page.waitForSelector('html.done'); + body = await page.evaluate(() => document.body.lastChild.textContent); + await expect(body).toBe('OK'); + await expect(logs.splice(0).length).toBe(0); +}); + +test('MicroPython buffered error', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/mpy-error.html'); + await page.waitForSelector('html.ok'); + const body = await page.evaluate(() => document.body.textContent.trim()); + await expect(body).toBe('This is an error'); +}); + +test('MicroPython buffered NO error', async ({ page }) => { + await page.goto('http://localhost:8080/tests/javascript/mpy-no-error.html'); + await page.waitForSelector('html.ok'); + const body = await page.evaluate(() => document.body.textContent.trim()); + await expect(body).toBe(''); +}); + +test('Pyodide media module', async ({ page }) => { + await page.context().grantPermissions(['camera', 'microphone']); + await page.context().addInitScript(() => { + const originalEnumerateDevices = navigator.mediaDevices.enumerateDevices; + navigator.mediaDevices.enumerateDevices = async function() { + const realDevices = await originalEnumerateDevices.call(this); + if (!realDevices || realDevices.length === 0) { + return [ + { deviceId: 'camera1', groupId: 'group1', kind: 'videoinput', label: 'Simulated Camera' }, + { deviceId: 'mic1', groupId: 'group2', kind: 'audioinput', label: 'Simulated Microphone' } + ]; + } + return realDevices; + }; + }); + await page.goto('http://localhost:8080/tests/javascript/media.html'); + await page.waitForSelector('html.media-ok', { timeout: 10000 }); + const isSuccess = await page.evaluate(() => document.documentElement.classList.contains('media-ok')); + expect(isSuccess).toBe(true); +}); diff --git a/core/tests/manual/a.py b/core/tests/manual/a.py new file mode 100644 index 00000000000..e1b904b7caa --- /dev/null +++ b/core/tests/manual/a.py @@ -0,0 +1 @@ +print("a") diff --git a/pyscript.core/test/all-done.html b/core/tests/manual/all-done.html similarity index 88% rename from pyscript.core/test/all-done.html rename to core/tests/manual/all-done.html index a0848175535..031f972f870 100644 --- a/pyscript.core/test/all-done.html +++ b/core/tests/manual/all-done.html @@ -3,9 +3,9 @@ - + + + + + import asyncio + print('py-script sleep') + await asyncio.sleep(1) + print('py-script done') + + + + diff --git a/pyscript.core/test/bad.toml b/core/tests/manual/bad.toml similarity index 100% rename from pyscript.core/test/bad.toml rename to core/tests/manual/bad.toml diff --git a/core/tests/manual/camera.html b/core/tests/manual/camera.html new file mode 100644 index 00000000000..d04ff55dbae --- /dev/null +++ b/core/tests/manual/camera.html @@ -0,0 +1,24 @@ + + + + + + PyScript Media Example + + + + + + + + + + + + + +
+ + + + diff --git a/core/tests/manual/camera.py b/core/tests/manual/camera.py new file mode 100644 index 00000000000..a1fd3cfe344 --- /dev/null +++ b/core/tests/manual/camera.py @@ -0,0 +1,31 @@ +from pyscript import display, document, media, when, window +from pyscript.web import page + +devicesSelect = page["#devices"][0] +video = page["video"][0] +devices = {} + + +async def list_media_devices(event=None): + """List the available media devices.""" + global devices + for i, device in enumerate(await media.list_devices()): + devices[device.id] = device + label = f"{i} - ({device.kind}) {device.label} [{device.id}]" + devicesSelect.options.add(value=device.id, html=label) + + +@when("click", "#pick-device") +async def connect_to_device(e): + """Connect to the selected device.""" + device = devices[devicesSelect.value] + video.srcObject = await device.get_stream() + + +@when("click", "#snap") +async def camera_click(e): + """Take a picture and download it.""" + video.snap().download() + + +await list_media_devices() diff --git a/pyscript.core/test/click.html b/core/tests/manual/click.html similarity index 86% rename from pyscript.core/test/click.html rename to core/tests/manual/click.html index 576c87b9c7a..378e9f99a4c 100644 --- a/pyscript.core/test/click.html +++ b/core/tests/manual/click.html @@ -4,8 +4,8 @@ PyScript Next Plugin Bug? - - + + + + + + + diff --git a/pyscript.core/test/combo.html b/core/tests/manual/combo.html similarity index 69% rename from pyscript.core/test/combo.html rename to core/tests/manual/combo.html index fc66a9f610e..aca99474918 100644 --- a/pyscript.core/test/combo.html +++ b/core/tests/manual/combo.html @@ -4,11 +4,11 @@ PyScript Error - - + + [[fetch]] - files = ["a.py"] + files = ["./a.py"] + + files = [ diff --git a/pyscript.core/test/config/ambiguous-config.html b/core/tests/manual/config/ambiguous-config.html similarity index 79% rename from pyscript.core/test/config/ambiguous-config.html rename to core/tests/manual/config/ambiguous-config.html index a7ea3b4f4be..52b7eb85b7f 100644 --- a/pyscript.core/test/config/ambiguous-config.html +++ b/core/tests/manual/config/ambiguous-config.html @@ -9,8 +9,8 @@ document.body.innerHTML += `

${message}

`; }); - - + + name = "first" diff --git a/pyscript.core/test/config/index.html b/core/tests/manual/config/index.html similarity index 100% rename from pyscript.core/test/config/index.html rename to core/tests/manual/config/index.html diff --git a/pyscript.core/test/config/same-config.html b/core/tests/manual/config/same-config.html similarity index 80% rename from pyscript.core/test/config/same-config.html rename to core/tests/manual/config/same-config.html index b13486e3a9a..9b89afcbb1b 100644 --- a/pyscript.core/test/config/same-config.html +++ b/core/tests/manual/config/same-config.html @@ -9,8 +9,8 @@ document.body.innerHTML += `

${message}

`; }); - - + + OK diff --git a/pyscript.core/test/config/too-many-config.html b/core/tests/manual/config/too-many-config.html similarity index 80% rename from pyscript.core/test/config/too-many-config.html rename to core/tests/manual/config/too-many-config.html index 5957191cdab..47e9d2b9e47 100644 --- a/pyscript.core/test/config/too-many-config.html +++ b/core/tests/manual/config/too-many-config.html @@ -9,8 +9,8 @@ document.body.innerHTML += `

${message}

`; }); - - + + diff --git a/pyscript.core/test/config/too-many-py-config.html b/core/tests/manual/config/too-many-py-config.html similarity index 79% rename from pyscript.core/test/config/too-many-py-config.html rename to core/tests/manual/config/too-many-py-config.html index b79f102cf5e..1c71230bd17 100644 --- a/pyscript.core/test/config/too-many-py-config.html +++ b/core/tests/manual/config/too-many-py-config.html @@ -9,8 +9,8 @@ document.body.innerHTML += `

${message}

`; }); - - + + name = "first" diff --git a/pyscript.core/test/create-element.html b/core/tests/manual/create-element.html similarity index 86% rename from pyscript.core/test/create-element.html rename to core/tests/manual/create-element.html index f85436066ce..0dcad343c91 100644 --- a/pyscript.core/test/create-element.html +++ b/core/tests/manual/create-element.html @@ -1,8 +1,8 @@ - - + + + + - - + + + + +
+ + + + + diff --git a/core/tests/manual/donkey/index.js b/core/tests/manual/donkey/index.js new file mode 100644 index 00000000000..870a714b74d --- /dev/null +++ b/core/tests/manual/donkey/index.js @@ -0,0 +1,43 @@ +import { donkey } from '../../../dist/core.js'; + +const runButton = document.querySelector('#run'); +const clearButton = document.querySelector('#clear'); +const killButton = document.querySelector('#kill'); + +const { + execute, // exec(expression) + evaluate, // eval(expression) + process, // process(code) + clear, + kill, +} = await donkey({ terminal: '#container' }); + +clearButton.onclick = async () => { + killButton.disabled = true; + clearButton.disabled = true; + await clear(); + runButton.disabled = false; +}; +killButton.onclick = () => { + killButton.disabled = true; + clearButton.disabled = true; + runButton.disabled = true; + kill(); +}; + +runButton.disabled = false; +runButton.onclick = async () => { + killButton.disabled = false; + clearButton.disabled = false; + runButton.disabled = true; + // multiline code + await execute(` + a = 1 + 2 + print(f'1 + 2 = {a}') + `); + // single expression evaluation + const name = await evaluate('input("what is your name? ")'); + alert(`Hello ${name}`); + killButton.disabled = true; + runButton.disabled = false; +}; diff --git a/core/tests/manual/emoji.html b/core/tests/manual/emoji.html new file mode 100644 index 00000000000..5dbe3cee8bd --- /dev/null +++ b/core/tests/manual/emoji.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/core/tests/manual/emoji.py b/core/tests/manual/emoji.py new file mode 100644 index 00000000000..9aaf0ae2d9f --- /dev/null +++ b/core/tests/manual/emoji.py @@ -0,0 +1,17 @@ +import sys + +print(sys.version) +RED = chr(0x1F534) # LARGE RED CIRCLE +GREEN = chr(0x1F7E2) # LARGE GREEN CIRCLE +MOUSE = chr(0x1F42D) # MOUSE FACE +EARTH = chr(0x1F30E) # EARTH GLOBE AMERICAS +FACE = chr(0x1F610) # NEUTRAL FACE +BASMALA = chr(0xFDFD) # ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM + +print("[", RED, "]") +print("[", MOUSE, "]") +print("[", EARTH, "]") +print("[", FACE, "]") +print("[", FACE * 3, "]") +print("[", BASMALA, "]") +print("[", BASMALA + GREEN, "]") diff --git a/pyscript.core/test/error.html b/core/tests/manual/error.html similarity index 80% rename from pyscript.core/test/error.html rename to core/tests/manual/error.html index 3b6850aa54a..f888ed28b65 100644 --- a/pyscript.core/test/error.html +++ b/core/tests/manual/error.html @@ -4,8 +4,8 @@ PyScript Next Plugin - - + + + + + + plugins = ["!error"] + + + + + +
+ + diff --git a/core/tests/manual/error/pyscript.toml b/core/tests/manual/error/pyscript.toml new file mode 100644 index 00000000000..4e7f1f7e4d3 --- /dev/null +++ b/core/tests/manual/error/pyscript.toml @@ -0,0 +1 @@ +plugins = ["!error"] diff --git a/core/tests/manual/fs/index.html b/core/tests/manual/fs/index.html new file mode 100644 index 00000000000..438e6fd0d28 --- /dev/null +++ b/core/tests/manual/fs/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/core/tests/manual/fs/index.py b/core/tests/manual/fs/index.py new file mode 100644 index 00000000000..5bff05bfef3 --- /dev/null +++ b/core/tests/manual/fs/index.py @@ -0,0 +1,46 @@ +import os +from pyscript import RUNNING_IN_WORKER, fs + + +TEST = "implicit" + +if TEST == "implicit": + await fs.mount("/persistent") + + print( + (RUNNING_IN_WORKER and "Worker") or "Main", + os.listdir("/persistent"), + ) + + from random import random + + with open("/persistent/random.txt", "w") as f: + f.write(str(random())) + + await fs.sync("/persistent") + +elif not RUNNING_IN_WORKER: + from pyscript import document + + button = document.createElement("button") + button.textContent = "mount" + document.body.append(button) + + async def mount(event): + try: + await fs.mount("/persistent") + print(os.listdir("/persistent")) + button.textContent = "unmount" + button.onclick = unmount + + except: + import js + + js.alert("unable to grant access") + + async def unmount(event): + await fs.unmount("/persistent") + button.textContent = "mount" + button.onclick = mount + + button.onclick = mount diff --git a/core/tests/manual/game/aliens.css b/core/tests/manual/game/aliens.css new file mode 100644 index 00000000000..f7a2fc48246 --- /dev/null +++ b/core/tests/manual/game/aliens.css @@ -0,0 +1,30 @@ +/* (c) https://github.com/ryanking13/pyodide-pygame-demo/blob/main/examples/aliens.html */ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 0; + padding: 20px; + background-color: #f4f4f4; + color: #333; +} +.demo { + background-color: #fff; + margin: 20px auto; + max-width: 1000px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border-radius: 8px; + overflow: hidden; +} +.demo-header { + background-color: #007bff; + color: #fff; + padding: 15px 20px; + font-size: 20px; +} +.demo-content { + padding: 20px; +} + +#canvas { + margin: 0 auto; + display: block; +} diff --git a/core/tests/manual/game/aliens.py b/core/tests/manual/game/aliens.py new file mode 100644 index 00000000000..78ebf656766 --- /dev/null +++ b/core/tests/manual/game/aliens.py @@ -0,0 +1,399 @@ +"""(c) https://github.com/ryanking13/pyodide-pygame-demo/blob/main/examples/aliens.html +pygame.examples.aliens + +Shows a mini game where you have to defend against aliens. + +What does it show you about pygame? + +* pygame.sprite, the difference between Sprite and Group. +* dirty rectangle optimization for processing for speed. +* music with pygame.mixer.music, including fadeout +* sound effects with pygame.Sound +* event processing, keyboard handling, QUIT handling. +* a main loop frame limited with a game clock from the pygame.time module +* fullscreen switching. + + +Controls +-------- + +* Left and right arrows to move. +* Space bar to shoot. +* f key to toggle between fullscreen. + +""" + +import asyncio +import random +import os +import pathlib + +import pyscript + +# import basic pygame modules +import pygame + +# see if we can load more than standard BMP +if not pygame.image.get_extended(): + msg = "Sorry, extended image module required" + raise SystemExit(msg) + + +# game constants +MAX_SHOTS = 2 # most player bullets onscreen +ALIEN_ODDS = 22 # chances a new alien appears +BOMB_ODDS = 60 # chances a new bomb will drop +ALIEN_RELOAD = 12 # frames between new aliens +SCREENRECT = pygame.Rect(0, 0, 640, 480) +SCORE = 0 + + +main_dir = str(pathlib.Path(pygame.__file__).parent / "examples") + + +def load_image(file): + """loads an image, prepares it for play""" + file = os.path.join(main_dir, "data", file) + try: + surface = pygame.image.load(file) + except pygame.error: + msg = f'Could not load image "{file}" {pygame.get_error()}' + raise SystemExit(msg) + return surface.convert() + + +def load_sound(file): + """because pygame can be be compiled without mixer.""" + if not pygame.mixer: + return None + file = os.path.join(main_dir, "data", file) + try: + return pygame.mixer.Sound(file) + except pygame.error: + print(f"Warning, unable to load, {file}") + return None + + +# Each type of game object gets an init and an update function. +# The update function is called once per frame, and it is when each object should +# change its current position and state. +# +# The Player object actually gets a "move" function instead of update, +# since it is passed extra information about the keyboard. + + +class Player(pygame.sprite.Sprite): + """Representing the player as a moon buggy type car.""" + + speed = 10 + bounce = 24 + gun_offset = -11 + images = [] + + def __init__(self): + pygame.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=SCREENRECT.midbottom) + self.reloading = False + self.origtop = self.rect.top + self.facing = -1 + + def move(self, direction): + if direction: + self.facing = direction + self.rect.move_ip(direction * self.speed, 0) + self.rect = self.rect.clamp(SCREENRECT) + if direction < 0: + self.image = self.images[0] + elif direction > 0: + self.image = self.images[1] + self.rect.top = self.origtop - (self.rect.left // self.bounce % 2) + + def gunpos(self): + pos = self.facing * self.gun_offset + self.rect.centerx + return pos, self.rect.top + + +class Alien(pygame.sprite.Sprite): + """An alien space ship. That slowly moves down the screen.""" + + speed = 13 + animcycle = 12 + images = [] + + def __init__(self): + pygame.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect() + self.facing = random.choice((-1, 1)) * Alien.speed + self.frame = 0 + if self.facing < 0: + self.rect.right = SCREENRECT.right + + def update(self): + self.rect.move_ip(self.facing, 0) + if not SCREENRECT.contains(self.rect): + self.facing = -self.facing + self.rect.top = self.rect.bottom + 1 + self.rect = self.rect.clamp(SCREENRECT) + self.frame = self.frame + 1 + self.image = self.images[self.frame // self.animcycle % 3] + + +class Explosion(pygame.sprite.Sprite): + """An explosion. Hopefully the Alien and not the player!""" + + defaultlife = 12 + animcycle = 3 + images = [] + + def __init__(self, actor): + pygame.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(center=actor.rect.center) + self.life = self.defaultlife + + def update(self): + """called every time around the game loop. + + Show the explosion surface for 'defaultlife'. + Every game tick(update), we decrease the 'life'. + + Also we animate the explosion. + """ + self.life = self.life - 1 + self.image = self.images[self.life // self.animcycle % 2] + if self.life <= 0: + self.kill() + + +class Shot(pygame.sprite.Sprite): + """a bullet the Player sprite fires.""" + + speed = -11 + images = [] + + def __init__(self, pos): + pygame.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=pos) + + def update(self): + """called every time around the game loop. + + Every tick we move the shot upwards. + """ + self.rect.move_ip(0, self.speed) + if self.rect.top <= 0: + self.kill() + + +class Bomb(pygame.sprite.Sprite): + """A bomb the aliens drop.""" + + speed = 9 + images = [] + + def __init__(self, alien): + pygame.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=alien.rect.move(0, 5).midbottom) + + def update(self): + """called every time around the game loop. + + Every frame we move the sprite 'rect' down. + When it reaches the bottom we: + + - make an explosion. + - remove the Bomb. + """ + self.rect.move_ip(0, self.speed) + if self.rect.bottom >= 470: + Explosion(self) + self.kill() + + +class Score(pygame.sprite.Sprite): + """to keep track of the score.""" + + def __init__(self): + pygame.sprite.Sprite.__init__(self) + self.font = pygame.Font(None, 20) + self.font.set_italic(1) + self.color = "white" + self.lastscore = -1 + self.update() + self.rect = self.image.get_rect().move(10, 450) + + def update(self): + """We only update the score in update() when it has changed.""" + if self.lastscore != SCORE: + self.lastscore = SCORE + msg = "Score: %d" % SCORE + self.image = self.font.render(msg, 0, self.color) + + +async def main(winstyle=0): + # Initialize pygame + pygame.mixer.pre_init(44100, 32, 2, 1024) + pygame.init() + if pygame.mixer and not pygame.mixer.get_init(): + print("Warning, no sound") + pygame.mixer = None + + fullscreen = False + # Set the display mode + winstyle = 0 # |FULLSCREEN + screen = pygame.display.set_mode(SCREENRECT.size, winstyle) + + # Load images, assign to sprite classes + # (do this before the classes are used, after screen setup) + img = load_image("player1.gif") + Player.images = [img, pygame.transform.flip(img, 1, 0)] + img = load_image("explosion1.gif") + Explosion.images = [img, pygame.transform.flip(img, 1, 1)] + Alien.images = [load_image(im) for im in ("alien1.gif", "alien2.gif", "alien3.gif")] + Bomb.images = [load_image("bomb.gif")] + Shot.images = [load_image("shot.gif")] + + # decorate the game window + icon = pygame.transform.scale(Alien.images[0], (32, 32)) + pygame.display.set_icon(icon) + pygame.display.set_caption("Pygame Aliens") + pygame.mouse.set_visible(0) + + # create the background, tile the bgd image + bgdtile = load_image("background.gif") + background = pygame.Surface(SCREENRECT.size) + for x in range(0, SCREENRECT.width, bgdtile.get_width()): + background.blit(bgdtile, (x, 0)) + screen.blit(background, (0, 0)) + pygame.display.flip() + + # load the sound effects + boom_sound = load_sound("boom.wav") + shoot_sound = load_sound("car_door.wav") + if pygame.mixer: + music = os.path.join(main_dir, "data", "house_lo.wav") + pygame.mixer.music.load(music) + pygame.mixer.music.play(-1) + + # Initialize Game Groups + aliens = pygame.sprite.Group() + shots = pygame.sprite.Group() + bombs = pygame.sprite.Group() + all = pygame.sprite.RenderUpdates() + lastalien = pygame.sprite.GroupSingle() + + # assign default groups to each sprite class + Player.containers = all + Alien.containers = aliens, all, lastalien + Shot.containers = shots, all + Bomb.containers = bombs, all + Explosion.containers = all + Score.containers = all + + # Create Some Starting Values + global score + alienreload = ALIEN_RELOAD + _clock = pygame.Clock() + + # initialize our starting sprites + global SCORE + player = Player() + Alien() # note, this 'lives' because it goes into a sprite group + if pygame.font: + all.add(Score()) + + # Run our main loop whilst the player is alive. + while player.alive(): + # get input + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return + if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + return + if event.type == pygame.KEYDOWN and event.key == pygame.K_f: + if not fullscreen: + print("Changing to FULLSCREEN") + screen_backup = screen.copy() + screen = pygame.display.set_mode( + SCREENRECT.size, winstyle | pygame.FULLSCREEN, bestdepth + ) + screen.blit(screen_backup, (0, 0)) + else: + print("Changing to windowed mode") + screen_backup = screen.copy() + screen = pygame.display.set_mode( + SCREENRECT.size, winstyle, bestdepth + ) + screen.blit(screen_backup, (0, 0)) + pygame.display.flip() + fullscreen = not fullscreen + + keystate = pygame.key.get_pressed() + + # clear/erase the last drawn sprites + all.clear(screen, background) + + # update all the sprites + all.update() + + # handle player input + direction = keystate[pygame.K_RIGHT] - keystate[pygame.K_LEFT] + player.move(direction) + firing = keystate[pygame.K_SPACE] + if not player.reloading and firing and len(shots) < MAX_SHOTS: + Shot(player.gunpos()) + if pygame.mixer: + shoot_sound.play() + player.reloading = firing + + # Create new alien + if alienreload: + alienreload = alienreload - 1 + elif not int(random.random() * ALIEN_ODDS): + Alien() + alienreload = ALIEN_RELOAD + + # Drop bombs + if lastalien and not int(random.random() * BOMB_ODDS): + Bomb(lastalien.sprite) + + # Detect collisions between aliens and players. + for alien in pygame.sprite.spritecollide(player, aliens, 1): + if pygame.mixer: + boom_sound.play() + Explosion(alien) + Explosion(player) + SCORE = SCORE + 1 + player.kill() + + # See if shots hit the aliens. + for alien in pygame.sprite.groupcollide(aliens, shots, 1, 1): + if pygame.mixer: + boom_sound.play() + Explosion(alien) + SCORE = SCORE + 1 + + # See if alien bombs hit the player. + for bomb in pygame.sprite.spritecollide(player, bombs, 1): + if pygame.mixer: + boom_sound.play() + Explosion(player) + Explosion(bomb) + player.kill() + + # draw the scene + dirty = all.draw(screen) + pygame.display.update(dirty) + + # cap the framerate at 40fps. Also called 40HZ or 40 times per second. + await asyncio.sleep(0.025) + + if pygame.mixer: + pygame.mixer.music.fadeout(1000) + + +main() diff --git a/pyscript.core/test/pyscript_dom/tests/__init__.py b/core/tests/manual/game/config.toml similarity index 100% rename from pyscript.core/test/pyscript_dom/tests/__init__.py rename to core/tests/manual/game/config.toml diff --git a/core/tests/manual/game/index.html b/core/tests/manual/game/index.html new file mode 100644 index 00000000000..17489f3881d --- /dev/null +++ b/core/tests/manual/game/index.html @@ -0,0 +1,19 @@ + + + + + + + + + + + +
+
pygame.examples.aliens
+
+ +
+
+ + diff --git a/pyscript.core/test/html-decode.html b/core/tests/manual/html-decode.html similarity index 88% rename from pyscript.core/test/html-decode.html rename to core/tests/manual/html-decode.html index 471ec382c04..1db840c4696 100644 --- a/pyscript.core/test/html-decode.html +++ b/core/tests/manual/html-decode.html @@ -1,8 +1,8 @@ - - + + diff --git a/pyscript.core/test/index.html b/core/tests/manual/index.html similarity index 79% rename from pyscript.core/test/index.html rename to core/tests/manual/index.html index 7c537c014ca..f243947e5c3 100644 --- a/pyscript.core/test/index.html +++ b/core/tests/manual/index.html @@ -7,8 +7,8 @@ - - + + - - + + - - input("what's your name?") + + print(input("what's your name? ")) - - input("what's your name?") + + print(input("what's your name? ")) diff --git a/core/tests/manual/interpreter.html b/core/tests/manual/interpreter.html new file mode 100644 index 00000000000..5405dca0650 --- /dev/null +++ b/core/tests/manual/interpreter.html @@ -0,0 +1,16 @@ + + + + Pyodide Worker Version + + + + + + + + + diff --git a/core/tests/manual/issue-2228/index.html b/core/tests/manual/issue-2228/index.html new file mode 100644 index 00000000000..04b28592aa8 --- /dev/null +++ b/core/tests/manual/issue-2228/index.html @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/core/tests/manual/issue-2246/index.html b/core/tests/manual/issue-2246/index.html new file mode 100644 index 00000000000..adb148331ca --- /dev/null +++ b/core/tests/manual/issue-2246/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/core/tests/manual/issue-2246/main.py b/core/tests/manual/issue-2246/main.py new file mode 100644 index 00000000000..3c7f04bcff8 --- /dev/null +++ b/core/tests/manual/issue-2246/main.py @@ -0,0 +1 @@ +print(input("What food would you like me to get from the shop? ")) diff --git a/core/tests/manual/issue-2302/assets/genuary25-18.m4a b/core/tests/manual/issue-2302/assets/genuary25-18.m4a new file mode 100644 index 00000000000..aa10617e4aa Binary files /dev/null and b/core/tests/manual/issue-2302/assets/genuary25-18.m4a differ diff --git a/core/tests/manual/issue-2302/glue/multipyjs.py b/core/tests/manual/issue-2302/glue/multipyjs.py new file mode 100644 index 00000000000..dd483f52255 --- /dev/null +++ b/core/tests/manual/issue-2302/glue/multipyjs.py @@ -0,0 +1,20 @@ +from pyscript import config + +MICROPYTHON = config["type"] == "mpy" + +if MICROPYTHON: + def new(obj, *args, **kwargs): + return obj.new(*args, kwargs) if kwargs else obj.new(*args) + def call(obj, *args, **kwargs): + return obj(*args, kwargs) if kwargs else obj(*args) +else: + def new(obj, *args, **kwargs): + return obj.new(*args, **kwargs) + def call(obj, *args, **kwargs): + return obj(*args, **kwargs) + +if not MICROPYTHON: + import pyodide_js + pyodide_js.setDebug(True) + +from pyscript.ffi import to_js, create_proxy diff --git a/core/tests/manual/issue-2302/glue/perlin-0.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl b/core/tests/manual/issue-2302/glue/perlin-0.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl new file mode 100644 index 00000000000..718ace2e725 Binary files /dev/null and b/core/tests/manual/issue-2302/glue/perlin-0.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl differ diff --git a/core/tests/manual/issue-2302/index.html b/core/tests/manual/issue-2302/index.html new file mode 100644 index 00000000000..a2ec422b739 --- /dev/null +++ b/core/tests/manual/issue-2302/index.html @@ -0,0 +1,69 @@ + + + + Genuary + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + diff --git a/core/tests/manual/issue-2302/libfft.py b/core/tests/manual/issue-2302/libfft.py new file mode 100644 index 00000000000..226842800c6 --- /dev/null +++ b/core/tests/manual/issue-2302/libfft.py @@ -0,0 +1,83 @@ +from dataclasses import dataclass, field +import sys + +@dataclass +class BeatSync: + fft_res: int = field() + + on_beat: bool = False + beat: int = -1 + since_last_beat: float = sys.maxsize + + _prev: int = 0 + _count: int = 0 + _bins: list[int] = field(default_factory=list) + _last_detection: float = -1.0 + _threshold: int = 50 + _diff: int = 40 + _cooldown: float = 0.2 + + _highest: int = 0 + + def __post_init__(self): + self._bins = [int(13/16*self.fft_res/2)+17, int(13/16*self.fft_res/2)+18] + + def reset(self): + self.beat = -1 + self._prev = 0 + self._count = 0 + self._last_detection = -1.0 + self.since_last_beat = sys.maxsize + # print('bs reset') + + def update(self, data, running_time): + self._count += 1 + self.since_last_beat = running_time - self._last_detection + d = sum(data[bin] for bin in self._bins) + if d < self._threshold: + self.on_beat = False + elif d - self._prev < self._diff: + self.on_beat = False + elif self.since_last_beat < self._cooldown: + self.on_beat = False + else: + self._last_detection = running_time + self.since_last_beat = 0 + self.on_beat = True + self.beat += 1 + self._prev = d + +@dataclass +class FreqIntensity: + freq: float = field() + fft_res: int = field() + + intensity: float = 0.0 + intensity_slew: float = 0.0 + scale_min: float = 0.0 + scale_max: float = 350 + max: float = 0.0 + _sample_rate: int = 48000 + _bin_indexes: list[int] = field(default_factory=list) + _harmonics: int = 8 + _slew_factor: float = 0.8 + + def __post_init__(self): + self._bin_indexes = [ + round((harmonic+1) * self.freq / self._sample_rate * self.fft_res / 2) + for harmonic in range(self._harmonics) + ] + print(self._bin_indexes) + + def update(self, data): + intensity = 0.0 + for bin in range(self._harmonics): + intensity += data[self._bin_indexes[bin]]/(bin+1) + self.intensity = intensity + self.intensity_slew = self._slew_factor * self.intensity_slew + (1 - self._slew_factor) * intensity + self.max = max(intensity, self.max) + + @property + def intensity_scaled(self): + raw = max(0, min(1.0, (self.intensity_slew - self.scale_min)/(self.scale_max - self.scale_min))) + return raw * raw diff --git a/core/tests/manual/issue-2302/libthree.py b/core/tests/manual/issue-2302/libthree.py new file mode 100644 index 00000000000..2c0c675d528 --- /dev/null +++ b/core/tests/manual/issue-2302/libthree.py @@ -0,0 +1,189 @@ +import asyncio +from dataclasses import dataclass, field +from typing import Callable + +from pyscript import document, window + +from pyscript.js_modules import three as THREE +from pyscript.js_modules.stats_gl import default as StatsGL +from pyscript.js_modules import lsgeo, line2, linemat + +from multipyjs import MICROPYTHON, new, call, to_js, create_proxy + +@dataclass +class SoundPlayer: + sound: THREE.Audio = field() + on_start: Callable[[], None] = field() + on_stop: Callable[[], None] = field(default=lambda: None) + + _start_time: float = -1.0 + + def play(self): + self.sound.stop() + self.on_start() + self._start_time = self.sound.context.currentTime + self.sound.play() + + def stop(self): + self.sound.stop() + self.on_stop() + self._start_time = -1.0 + + def toggle(self): + if self.sound.isPlaying: + self.stop() + else: + self.play() + + @property + def running_time(self): + if self.sound.isPlaying: + return self.sound.context.currentTime - self._start_time + elif self._start_time != -1.0: + self.stop() + return 0.0 + +def get_renderer(): + renderer = new(THREE.WebGLRenderer, antialias=True) + renderer.setSize(window.innerWidth, window.innerHeight) + renderer.setPixelRatio(window.devicePixelRatio) + renderer.setClearColor(0xF5F0DC) + pyterms = list(document.getElementsByTagName("py-terminal")) + if pyterms: + pyterm = pyterms[0] + pyterm.parentNode.removeChild(pyterm) + document.getElementById("pyterm").appendChild(pyterm) + + document.getElementById("threejs").appendChild(renderer.domElement) + + initial = {0: "115px", 1: "calc(100vh - 120px)"} + @create_proxy + def split_element_style(dimension, size, gutter_size, index): + if index in initial: + result = {dimension: initial.pop(index)} + else: + result = {dimension: f"calc({int(size)}vh - {gutter_size}px)"} + return to_js(result) + + call( + window.Split, + ["#pyterm", "#threejs"], + direction="vertical", + elementStyle=split_element_style, + minSize=0, + maxSize=to_js([120, 10000]), + ) + return renderer + +def get_ortho_camera(view_size): + aspect_ratio = window.innerWidth / window.innerHeight + camera = new( + THREE.OrthographicCamera, + -view_size * aspect_ratio, # Left + view_size * aspect_ratio, # Right + view_size, # Top + -view_size, # Bottom + -view_size, # Near plane + view_size, # Far plane + ) + camera.updateProjectionMatrix() + camera.position.set(0, 0, 0) + return camera + +def get_loading_manager(): + loading_mgr = new(THREE.LoadingManager) + ev = asyncio.Event() + + @create_proxy + def on_start(url, itemsLoaded, itemsTotal): + print(f'[{itemsLoaded}/{itemsTotal}] Started loading file: {url}') + loading_mgr.onStart = on_start + + @create_proxy + def on_progress(url, itemsLoaded, itemsTotal): + print(f'[{itemsLoaded}/{itemsTotal}] Loading file: {url}') + loading_mgr.onProgress = on_progress + + @create_proxy + def on_error(url): + print(f'There was a problem loading {url}') + loading_mgr.onError = on_error + + @create_proxy + def on_load(): + print('Loading assets complete!') + ev.set() + loading_mgr.onLoad = on_load + + return loading_mgr, ev + + +def get_perspective_camera(): + aspect_ratio = window.innerWidth / window.innerHeight + camera = new( + THREE.PerspectiveCamera, + 45, # fov + aspect_ratio, + 0.25, # near plane + 300, # far plane + ) + camera.position.set(0, 0, 30) + return camera + +def get_stats_gl(renderer): + stats = new(StatsGL, trackGPU=True, horizontal=False) + stats.init(renderer) + stats.dom.style.removeProperty("left") + stats.dom.style.right = "90px" + document.getElementById("stats").appendChild(stats.dom) + return stats + +def bg_from_v(*vertices): + geometry = new(THREE.BufferGeometry) + vertices_f32a = new(Float32Array, vertices) + attr = new(THREE.Float32BufferAttribute, vertices_f32a, 3) + return geometry.setAttribute('position', attr) + +def bg_from_p(*points): + buf = new(THREE.BufferGeometry) + buf.setFromPoints( + [new(THREE.Vector3, p[0], p[1], p[2]) for p in points] + ) + return buf + +def clear(): + # toggle stats and terminal? + stats_style = document.getElementById("stats-off").style + if stats_style.display == "none": + # turn stuff back on + stats_style.removeProperty("display") + document.getElementById("pyterm").style.height = "115px" + document.getElementById("threejs").style.height = "calc(100vh - 120px)" + for e in document.getElementsByClassName("gutter"): + e.style.removeProperty("display") + for e in document.getElementsByClassName("xterm-helper-textarea"): + e.focus() + break + return + + # no longer focus on xterm + document.activeElement.blur() + # hide stats + document.getElementById("stats-off").style.display = "none" + # hide pyterm and split gutter + document.getElementById("pyterm").style.height = "0vh" + document.getElementById("threejs").style.height = "100vh" + for e in document.getElementsByClassName("gutter"): + e.style.display = "none" + # hide ltk ad + for e in document.getElementsByClassName("ltk-built-with"): + e.style.display = "none" + # hide pyscript ad + for e in document.getElementsByTagName("div"): + style = e.getAttribute("style") + if style and style.startswith("z-index:999"): + e.style.display = "none" + for e in document.getElementsByTagName("svg"): + style = e.getAttribute("style") + if style and style.startswith("z-index:999"): + e.style.display = "none" diff --git a/core/tests/manual/issue-2302/main.py b/core/tests/manual/issue-2302/main.py new file mode 100644 index 00000000000..f2a6abf5db9 --- /dev/null +++ b/core/tests/manual/issue-2302/main.py @@ -0,0 +1,285 @@ +print("Starting up...") + +from array import array +import asyncio +import math +import time + +from pyscript import document, window, PyWorker + +from libthree import THREE, clear, SoundPlayer +from libthree import get_renderer, get_ortho_camera +from libthree import get_loading_manager, get_stats_gl +from libthree import lsgeo, line2, linemat, lsgeo +from libfft import BeatSync + +from multipyjs import MICROPYTHON, new, call, to_js, create_proxy + +from js import Float32Array + +scene = new(THREE.Scene) + +view_size = 1 +renderer = get_renderer() +camera = get_ortho_camera(view_size) +loading_mgr, loaded_event = get_loading_manager() + +t_loader = new(THREE.TextureLoader, loading_mgr) +t_loader.setPath('assets/') + +light = new(THREE.AmbientLight, 0xffffff, 1.0) +scene.add(light) + +fft_res = 2048 +audio_listener = new(THREE.AudioListener) +camera.add(audio_listener) +sound = new(THREE.Audio, audio_listener) +audio_loader = new(THREE.AudioLoader, loading_mgr) +analyser = new(THREE.AudioAnalyser, sound, fft_res) + +@create_proxy +def on_audio_load(buffer): + sound.setBuffer(buffer) + sound.setVolume(0.9) + sound.setLoop(False) + +audio_loader.load("assets/genuary25-18.m4a", on_audio_load) + +spheres = new(THREE.Group) +scene.add(spheres) + +line_basic_mat = new( + THREE.LineBasicMaterial, + color=0xffffff, +) + +zero_mat = new( + linemat.LineMaterial, + color=0x662503, + linewidth=3, +) + +other_mat = new( + linemat.LineMaterial, + color=0x662503, + linewidth=1.5, +) + +grid_mat = new( + linemat.LineMaterial, + color=0x662503, + linewidth=1, + dashed=True, + dashScale=1, + dashSize=0.5, + gapSize=1, + dashOffset=0, +) + +lines = [new(THREE.Group), new(THREE.Group)] +scene.add(lines[0]) +scene.add(lines[1]) + +def draw_lines(line_coords, mat_name, spy=False): + if spy: + line_coords_f32a = new(Float32Array, line_coords.length) + _it = line_coords.items + for i in range(line_coords.length): + line_coords_f32a[i] = _it[i] + else: + line_coords_f32a = new(Float32Array, line_coords) + if mat_name == 'zero': + mat = zero_mat + elif mat_name == 'grid': + mat = grid_mat + else: + mat = other_mat + + geo = new(THREE.BufferGeometry) + geo.setAttribute('position', new(THREE.BufferAttribute, line_coords_f32a, 3)) + seg = new(THREE.LineSegments, geo, line_basic_mat) + + lsg = new(lsgeo.LineSegmentsGeometry) + lsg.fromLineSegments(seg) + l1 = new(line2.Line2, lsg, mat) + l1.computeLineDistances() + l2 = new(line2.Line2, lsg, mat) + l2.computeLineDistances() + lines[0].add(l1) + lines[1].add(l2) + + seg.geometry.dispose() + del geo + del seg + +def drawing_done(): + maybe_with_spy = "with SPy" if USE_SPY else "with pure Python" + print(f"Time elapsed computing {maybe_with_spy}:", time.time() - start_ts) + drawing_event.set() + +grid_width = 0 +grid_height = 0 +scroll_offset = 0 +def scale_lines(grid_ws=None, grid_hs=None, offset=None): + global grid_width, grid_height, scroll_offset + + if grid_ws: + grid_width = grid_ws + else: + grid_ws = grid_width + + if grid_hs: + grid_height = grid_hs + else: + grid_hs = grid_height + + if offset: + scroll_offset = offset + else: + offset = scroll_offset + + scale = 2.04/grid_hs + lines[0].scale.set(scale, scale, scale) + lines[1].scale.set(scale, scale, scale) + lines[0].position.set((offset - grid_ws/2) * scale, -grid_hs/2 * scale, 0) + lines[1].position.set((offset + grid_ws/2) * scale, -grid_hs/2 * scale, 0) + +def append_p(lines, p1, p2): + lines.append(p1[0]) + lines.append(p1[1]) + lines.append(0) + lines.append(p2[0]) + lines.append(p2[1]) + lines.append(0) + +def initial_calc(): + grid_w = int(1920 * 4) + grid_h = 1080 * 2 + grid_scale = 10 + noise_factor = 500 + grid_hs = int(grid_h/grid_scale) + grid_ws = int(grid_w/grid_scale) + crossfade_range = int(grid_ws/12.5) + + def grid_lines(): + lines = array("d") + grid_goal = 24 + grid_size_i = int(round((grid_ws - crossfade_range) / grid_goal)) + grid_actual = (grid_ws - crossfade_range) / grid_size_i + for i in range(0, grid_size_i): + x = i * grid_actual + append_p(lines, (x, 0), (x, grid_hs)) + for y in range(0, grid_hs, grid_goal): + append_p(lines, (0, y), (grid_ws-crossfade_range, y)) + return lines + + import perlin + spy_perlin = perlin.lib + spy_perlin.init() + spy_perlin.seed(44) + scale_lines(grid_ws - crossfade_range, grid_hs) + print("Computing the height map") + spy_perlin.make_height_map(grid_ws, grid_hs) + spy_perlin.update_height_map(grid_ws, grid_hs, grid_scale / noise_factor, 0) + print("Cross-fading the height map") + spy_perlin.crossfade_height_map(grid_ws, grid_hs, crossfade_range) + print("Drawing grid") + draw_lines(grid_lines(), 'grid') + print("Marching squares") + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, 0), 'zero', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, 0.3), 'positive', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, -0.3), 'negative', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, 0.45), 'positive', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, -0.45), 'negative', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, 0.6), 'positive', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, -0.6), 'negative', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, -0.8), 'negative', spy=True) + draw_lines(spy_perlin.marching_squares(grid_ws, grid_hs, 0.8), 'positive', spy=True) + drawing_done() + +drawing_event = asyncio.Event() +start_ts = time.time() + +USE_SPY = True +if USE_SPY: + initial_calc() +else: + worker = PyWorker("./worker.py", type="pyodide", configURL="./pyscript.toml") + worker.sync.draw_lines = draw_lines + worker.sync.drawing_done = drawing_done + worker.sync.scale_lines = scale_lines + worker.sync.print = print + +@create_proxy +def on_tap(event): + clear() + player.toggle() +document.addEventListener("click", on_tap) + +@create_proxy +def on_key_down(event): + element = document.activeElement + _class = element.getAttribute("class") + in_xterm = element.tagName != "BODY" and _class and "xterm" in _class + + if event.code == "Backquote": + # Screenshot mode. + clear() + elif not in_xterm: + # Don't react to those bindings when typing code. + if event.code == "Space": + player.toggle() +document.addEventListener("keydown", on_key_down) + +@create_proxy +def on_window_resize(event): + aspect_ratio = window.innerWidth / window.innerHeight + if camera.type == "OrthographicCamera": + camera.left = -view_size * aspect_ratio + camera.right = view_size * aspect_ratio + camera.top = view_size + camera.bottom = -view_size + camera.updateProjectionMatrix() + elif camera.type == "PerspectiveCamera": + camera.aspect = window.innerWidth / window.innerHeight + camera.updateProjectionMatrix() + else: + raise ValueError("Unknown camera type") + renderer.setSize(window.innerWidth, window.innerHeight) + scale_lines() + +window.addEventListener("resize", on_window_resize) + +@create_proxy +def animate(now=0.0): + data = analyser.getFrequencyData()#.to_py() in Pyodide + audio_now = player.running_time + bs.update(data, audio_now) + + if grid_width: + offset = -((20 * audio_now) % grid_width) + scale_lines(offset=offset) + + renderer.render(scene, camera) + stats_gl.update() + +def reset(): + global scroll_offset + bs.reset() + scale_lines() + +def on_stop(): + global scroll_offset + bs.reset() + scale_lines() + +await loaded_event.wait() + +stats_gl = get_stats_gl(renderer) +player = SoundPlayer(sound=sound, on_start=reset, on_stop=on_stop) +bs = BeatSync(fft_res=fft_res) +renderer.setAnimationLoop(animate) +print("Waiting for the contours...") + +await drawing_event.wait() +print("Tap the map to start...") diff --git a/core/tests/manual/issue-2302/perlin_py.py b/core/tests/manual/issue-2302/perlin_py.py new file mode 100644 index 00000000000..8141e8f7545 --- /dev/null +++ b/core/tests/manual/issue-2302/perlin_py.py @@ -0,0 +1,110 @@ +# Translated from https://github.com/josephg/noisejs. +from libthree import THREE +from multipyjs import new + +class V3: + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def __repr__(self): + return f"V3({self.x}, {self.y}, {self.z})" + + def dot2(self, x, y): + return self.x * x + self.y * y + + def dot3(self, x, y, z): + return self.x * x + self.y * y + self.z * z + + def to_js(self, scale=1.0): + return new(THREE.Vector3, self.x * scale, self.y * scale, self.z * scale) + +PERM = [0] * 512 +V3_P = [0] * 512 # assigned V3s in seed() +P = [151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180] +V3_I = [V3(1, 1, 0), V3(-1, 1, 0), V3(1, -1, 0), V3(-1, -1, 0), + V3(1, 0, 1), V3(-1, 0, 1), V3(1, 0, -1), V3(-1, 0, -1), + V3(0, 1, 1), V3(0, -1, 1), V3(0, 1, -1), V3(0, -1, -1)] + +def seed(s): + if isinstance(s, float) and 0.0 < s < 1.0: + s *= 65536 + + s = int(s) + if s < 256: + s |= s << 8 + + for i in range(256): + if i & 1: + v = P[i] ^ (s & 255) + else: + v = P[i] ^ ((s >> 8) & 255) + + PERM[i] = PERM[i + 256] = v + V3_P[i] = V3_P[i + 256] = V3_I[v % 12] + +seed(0) + +def fade(t): + return t * t * t * (t * (t * 6 - 15) + 10) + +def lerp(a, b, t): + return (1 - t) * a + t * b + +def perlin3(x, y, z): + # grid cells + x_c = int(x) + y_c = int(y) + z_c = int(z) + # relative coords within the cell + x -= x_c + y -= y_c + z -= z_c + # wrap cells + x_c &= 255 + y_c &= 255 + z_c &= 255 + # noise contributions to corners + n000 = V3_P[x_c + PERM[y_c + PERM[z_c]]].dot3(x, y, z) + n001 = V3_P[x_c + PERM[y_c + PERM[z_c + 1]]].dot3(x, y, z - 1) + n010 = V3_P[x_c + PERM[y_c + 1 + PERM[z_c]]].dot3(x, y - 1, z) + n011 = V3_P[x_c + PERM[y_c + 1 + PERM[z_c + 1]]].dot3(x, y - 1, z - 1) + n100 = V3_P[x_c + 1 + PERM[y_c + PERM[z_c]]].dot3(x - 1, y, z) + n101 = V3_P[x_c + 1 + PERM[y_c + PERM[z_c + 1]]].dot3(x - 1, y, z - 1) + n110 = V3_P[x_c + 1 + PERM[y_c + 1 + PERM[z_c]]].dot3(x - 1, y - 1, z) + n111 = V3_P[x_c + 1 + PERM[y_c + 1 + PERM[z_c + 1]]].dot3(x - 1, y - 1, z - 1) + # fade curve + u = fade(x) + v = fade(y) + w = fade(z) + # interpolation + return lerp( + lerp(lerp(n000, n100, u), lerp(n001, n101, u), w), + lerp(lerp(n010, n110, u), lerp(n011, n111, u), w), + v, + ) + +def curl2(x, y, z): + # https://www.bit-101.com/2017/2021/07/curl-noise/ + delta = 0.01 + n1 = perlin3(x + delta, y, z) + n2 = perlin3(x - delta, y, z) + cy = -(n1 - n2) / (delta * 2) + n1 = perlin3(x, y + delta, z) + n2 = perlin3(x, y - delta, z) + cx = -(n1 - n2) / (delta * 2) + print(n1, n2) + return V3(cx, cy, 0) diff --git a/core/tests/manual/issue-2302/pyscript.toml b/core/tests/manual/issue-2302/pyscript.toml new file mode 100644 index 00000000000..36409b57f2f --- /dev/null +++ b/core/tests/manual/issue-2302/pyscript.toml @@ -0,0 +1,16 @@ +name = "Marching Squares with SPy Copy Copy" +packages = [ "cffi", "./glue/perlin-0.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl",] + +[files] +"./libthree.py" = "" +"./libfft.py" = "" +"./perlin_py.py" = "" +"./worker.py" = "" +"./glue/multipyjs.py" = "./multipyjs.py" + +[js_modules.main] +"https://cdn.jsdelivr.net/npm/three@v0.173.0/build/three.module.js" = "three" +"https://cdn.jsdelivr.net/npm/three@v0.173.0/examples/jsm/lines/LineMaterial.js" = "linemat" +"https://cdn.jsdelivr.net/npm/three@v0.173.0/examples/jsm/lines/Line2.js" = "line2" +"https://cdn.jsdelivr.net/npm/three@v0.173.0/examples/jsm/lines/LineSegmentsGeometry.js" = "lsgeo" +"https://cdn.jsdelivr.net/npm/stats-gl@3.6.0/dist/main.js" = "stats_gl" diff --git a/core/tests/manual/issue-2302/worker.py b/core/tests/manual/issue-2302/worker.py new file mode 100644 index 00000000000..bc857738af8 --- /dev/null +++ b/core/tests/manual/issue-2302/worker.py @@ -0,0 +1,141 @@ +from array import array + +from pyscript import sync, window +from perlin_py import perlin3, seed + +grid_w = int(1920 * 4) +grid_h = 1080 * 2 +grid_scale = 10 +noise_factor = 500 +grid_hs = int(grid_h/grid_scale) +grid_ws = int(grid_w/grid_scale) +crossfade_range = int(grid_ws/12.5) +height_map = array("d", [0.0] * (grid_hs * grid_ws)) +edge_table = [ + (), # 0 + ((3, 2),), # 1 + ((2, 1),), # 2 + ((3, 1),), # 3 + ((0, 1),), # 4 + ((0, 3), (1, 2)), # 5 (ambiguous) + ((0, 2),), # 6 + ((0, 3),), # 7 + ((0, 3),), # 8 + ((0, 2),), # 9 + ((0, 1), (2, 3)), # 10 (ambiguous) + ((0, 1),), # 11 + ((3, 1),), # 12 + ((2, 1),), # 13 + ((3, 2),), # 14 + (), # 15 +] + +def update_height_map(z): + i = 0 + for y in range(0, grid_h, grid_scale): + for x in range(0, grid_w, grid_scale): + # 3 octaves of noise + n = perlin3(x/noise_factor, y/noise_factor, z) + n += 0.50 * perlin3(2*x/noise_factor, 2*y/noise_factor, z) + n += 0.25 * perlin3(4*x/noise_factor, 4*y/noise_factor, z) + height_map[i] = n + i += 1 + +def crossfade_height_map(): + for y in range(grid_hs): + for x in range(crossfade_range): + pos_i = y*grid_ws + x + neg_i = y*grid_ws + grid_ws - crossfade_range + x + weight = x/crossfade_range + old_pos = height_map[pos_i] + old_neg = height_map[neg_i] + height_map[neg_i] = height_map[pos_i] = weight * old_pos + (1.0 - weight) * old_neg + + +def _crossfade_height_map(): + for y in range(grid_hs): + for x in range(crossfade_range): + pos_i = y*grid_ws + x + neg_i = y*grid_ws + grid_ws - x - 1 + old_pos = height_map[pos_i] + old_neg = height_map[neg_i] + weight = 0.5 - x/crossfade_range/2 + height_map[pos_i] = (1.0 - weight) * old_pos + weight * old_neg + height_map[neg_i] = (1.0 - weight) * old_neg + weight * old_pos + +def interpolate(sq_threshold, v1, v2): + if v1 == v2: + return v1 + return (sq_threshold - v1) / (v2 - v1) + +stats = {'maxx': 0, 'maxy': 0, 'minx': 0, 'miny': 0} +def append_p(lines, p1, p2): + lines.append(p1[0]) + lines.append(p1[1]) + lines.append(0) + lines.append(p2[0]) + lines.append(p2[1]) + lines.append(0) + stats['maxy'] = max(p1[1], p2[1], stats['maxy']) + stats['miny'] = min(p1[1], p2[1], stats['miny']) + stats['maxx'] = max(p1[0], p2[0], stats['maxx']) + stats['minx'] = min(p1[0], p2[0], stats['minx']) + +def marching_squares(height_map, sq_threshold): + lines = array("d") + + for y in range(grid_hs-1): + for x in range(grid_ws-1): #cf + tl = height_map[y*grid_ws + x] + tr = height_map[y*grid_ws + x+1] + bl = height_map[(y+1)*grid_ws + x] + br = height_map[(y+1)*grid_ws + x+1] + + sq_idx = 0 + if tl > sq_threshold: + sq_idx |= 8 + if tr > sq_threshold: + sq_idx |= 4 + if br > sq_threshold: + sq_idx |= 2 + if bl > sq_threshold: + sq_idx |= 1 + + edge_points = [ + (x + interpolate(sq_threshold, tl, tr), y), + (x + 1, y + interpolate(sq_threshold, tr, br)), + (x + interpolate(sq_threshold, bl, br), y + 1), + (x, y + interpolate(sq_threshold, tl, bl)), + ] + + for a, b in edge_table[sq_idx]: + append_p(lines, edge_points[a], edge_points[b]) + + return lines + +def grid_lines(): + lines = array("d") + for x in range(0, grid_ws - crossfade_range, 26): + append_p(lines, (x, 0), (x, grid_hs)) + for y in range(0, grid_hs, 24): + append_p(lines, (0, y), (grid_ws-crossfade_range, y)) + return lines + +seed(44) +sync.scale_lines(grid_ws - crossfade_range, grid_hs) +sync.print("Computing the height map") +update_height_map(0) +sync.print("Cross-fading the height map") +crossfade_height_map() +sync.draw_lines(grid_lines(), 'grid') +sync.draw_lines(marching_squares(height_map, 0), 'zero') +sync.draw_lines(marching_squares(height_map, 0.3), 'positive') +sync.draw_lines(marching_squares(height_map, -0.3), 'negative') +sync.draw_lines(marching_squares(height_map, 0.45), 'positive') +sync.draw_lines(marching_squares(height_map, -0.45), 'negative') +sync.draw_lines(marching_squares(height_map, 0.6), 'positive') +sync.draw_lines(marching_squares(height_map, -0.6), 'negative') +sync.draw_lines(marching_squares(height_map, -0.8), 'negative') +sync.draw_lines(marching_squares(height_map, 0.8), 'positive') +print(stats) +sync.drawing_done() diff --git a/core/tests/manual/issue-2304/index.html b/core/tests/manual/issue-2304/index.html new file mode 100644 index 00000000000..fe1805db52f --- /dev/null +++ b/core/tests/manual/issue-2304/index.html @@ -0,0 +1,12 @@ + + + + + + + +
Status:
+ + + + diff --git a/core/tests/manual/issue-2304/main.py b/core/tests/manual/issue-2304/main.py new file mode 100644 index 00000000000..cf5eb6ae006 --- /dev/null +++ b/core/tests/manual/issue-2304/main.py @@ -0,0 +1,34 @@ +import sys +print("Starting test...") + +# Try NumPy +try: + import numpy as np + arr = np.array([1, 2, 3]) + print(f"NumPy works: {arr.mean()}") +except Exception as e: + print(f"NumPy error: {e}") + +# Try PyGame without NumPy first +try: + print("Testing PyGame...") + import pygame + screen = pygame.display.set_mode((200, 200)) + screen.fill((255, 0, 0)) # Fill with red + pygame.display.flip() + print("PyGame works!") +except Exception as e: + print(f"PyGame error: {e}") + +# Now try PyGame with NumPy +try: + print("Testing PyGame+NumPy...") + color_array = np.random.randint(0, 255, size=(50, 50, 3), dtype=np.uint8) + surface = pygame.surfarray.make_surface(color_array) + screen.blit(surface, (75, 75)) + pygame.display.flip() + print("PyGame+NumPy integration works!") +except Exception as e: + print(f"PyGame+NumPy integration error: {e}") + +print("Test completed") diff --git a/core/tests/manual/issue-2304/pyscript.toml b/core/tests/manual/issue-2304/pyscript.toml new file mode 100644 index 00000000000..28cd14bd37a --- /dev/null +++ b/core/tests/manual/issue-2304/pyscript.toml @@ -0,0 +1,2 @@ +name = "PyGame Numpy Minimal Example Copy" +packages = [ "numpy", ] diff --git a/core/tests/manual/issue-7015/config.toml b/core/tests/manual/issue-7015/config.toml new file mode 100644 index 00000000000..76507883737 --- /dev/null +++ b/core/tests/manual/issue-7015/config.toml @@ -0,0 +1,4 @@ +packages = [ + "https://cdn.holoviz.org/panel/wheels/bokeh-3.5.0-py3-none-any.whl", + "https://cdn.holoviz.org/panel/1.5.0-b.2/dist/wheels/panel-1.5.0b2-py3-none-any.whl" +] diff --git a/core/tests/manual/issue-7015/index.html b/core/tests/manual/issue-7015/index.html new file mode 100644 index 00000000000..6b7301a1d61 --- /dev/null +++ b/core/tests/manual/issue-7015/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + +
+ + diff --git a/core/tests/manual/issue-7015/main.py b/core/tests/manual/issue-7015/main.py new file mode 100644 index 00000000000..6e6927f0009 --- /dev/null +++ b/core/tests/manual/issue-7015/main.py @@ -0,0 +1,12 @@ +import panel as pn + +pn.extension(sizing_mode="stretch_width") + +slider = pn.widgets.FloatSlider(start=0, end=10, name="amplitude") + + +def callback(new): + return f"Amplitude is: {new}" + + +pn.Row(slider, pn.bind(callback, slider)).servable(target="simple_app") diff --git a/pyscript.core/test/multi.html b/core/tests/manual/multi.html similarity index 87% rename from pyscript.core/test/multi.html rename to core/tests/manual/multi.html index ce3e62b2ddf..e85ba5262cf 100644 --- a/pyscript.core/test/multi.html +++ b/core/tests/manual/multi.html @@ -3,7 +3,7 @@ - + + + + + + + + + + + + diff --git a/pyscript.core/test/no-error.html b/core/tests/manual/no-error.html similarity index 79% rename from pyscript.core/test/no-error.html rename to core/tests/manual/no-error.html index 92e06f13c29..858f7a6689f 100644 --- a/pyscript.core/test/no-error.html +++ b/core/tests/manual/no-error.html @@ -4,8 +4,8 @@ PyScript Next No Plugin - - + + plugins = ['!error'] + + diff --git a/core/tests/manual/no_sab/worker.py b/core/tests/manual/no_sab/worker.py new file mode 100644 index 00000000000..ffdf6c02155 --- /dev/null +++ b/core/tests/manual/no_sab/worker.py @@ -0,0 +1,3 @@ +from pyscript import sync + +sync.get_class = lambda: "ok" diff --git a/pyscript.core/test/piratical.html b/core/tests/manual/piratical/index.html similarity index 80% rename from pyscript.core/test/piratical.html rename to core/tests/manual/piratical/index.html index 317f5d8fa5c..209cfb22e06 100644 --- a/pyscript.core/test/piratical.html +++ b/core/tests/manual/piratical/index.html @@ -4,8 +4,8 @@ Arrr - Piratical PyScript - - + +

Arrr

diff --git a/pyscript.core/test/piratical.py b/core/tests/manual/piratical/piratical.py similarity index 100% rename from pyscript.core/test/piratical.py rename to core/tests/manual/piratical/piratical.py diff --git a/pyscript.core/test/piratical.toml b/core/tests/manual/piratical/piratical.toml similarity index 100% rename from pyscript.core/test/piratical.toml rename to core/tests/manual/piratical/piratical.toml diff --git a/core/tests/manual/py-editor-failure.html b/core/tests/manual/py-editor-failure.html new file mode 100644 index 00000000000..6294d051f2a --- /dev/null +++ b/core/tests/manual/py-editor-failure.html @@ -0,0 +1,15 @@ + + + + + + PyEditor Failure + + + + + + + + + diff --git a/pyscript.core/test/py-editor.html b/core/tests/manual/py-editor.html similarity index 82% rename from pyscript.core/test/py-editor.html rename to core/tests/manual/py-editor.html index ad8f8272c67..000dda50e7b 100644 --- a/pyscript.core/test/py-editor.html +++ b/core/tests/manual/py-editor.html @@ -3,9 +3,9 @@ - PyTerminal - - + PyEditor + + + + + + + + + + + + + + diff --git a/core/tests/manual/py-editor/issue-2056.html b/core/tests/manual/py-editor/issue-2056.html new file mode 100644 index 00000000000..3106c4fcda3 --- /dev/null +++ b/core/tests/manual/py-editor/issue-2056.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/core/tests/manual/py-editor/service-worker.html b/core/tests/manual/py-editor/service-worker.html new file mode 100644 index 00000000000..d42b333ec7a --- /dev/null +++ b/core/tests/manual/py-editor/service-worker.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/core/tests/manual/py-editor/sw.js b/core/tests/manual/py-editor/sw.js new file mode 100644 index 00000000000..1e1996cfbf0 --- /dev/null +++ b/core/tests/manual/py-editor/sw.js @@ -0,0 +1 @@ +const{isArray:e}=Array,t=new Map,s=e=>{e.stopImmediatePropagation(),e.preventDefault()};var n=Object.freeze({__proto__:null,activate:e=>e.waitUntil(clients.claim()),fetch:e=>{const{request:n}=e;"POST"===n.method&&n.url===`${location.href}?sabayon`&&(s(e),e.respondWith(n.json().then((async e=>{const{promise:s,resolve:o}=Promise.withResolvers(),a=e.join(",");t.set(a,o);for(const t of await clients.matchAll())t.postMessage(e);return s.then((e=>new Response(`[${e.join(",")}]`,n.headers)))}))))},install:()=>skipWaiting(),message:n=>{const{data:o}=n;if(e(o)&&4===o.length){const[e,a,i,r]=o,l=[e,a,i].join(",");t.has(l)&&(s(n),t.get(l)(r),t.delete(l))}}});for(const e in n)addEventListener(e,n[e]); diff --git a/core/tests/manual/py-editor/task1.py b/core/tests/manual/py-editor/task1.py new file mode 100644 index 00000000000..014e073d39a --- /dev/null +++ b/core/tests/manual/py-editor/task1.py @@ -0,0 +1,5 @@ +from pyscript import window + +window.console.log("OK") + +a = 1 diff --git a/core/tests/manual/py-terminals/index.html b/core/tests/manual/py-terminals/index.html new file mode 100644 index 00000000000..3d41ea8ba65 --- /dev/null +++ b/core/tests/manual/py-terminals/index.html @@ -0,0 +1,18 @@ + + + + + + Document + + + + + diff --git a/core/tests/manual/py-terminals/no-repl.html b/core/tests/manual/py-terminals/no-repl.html new file mode 100644 index 00000000000..ecd1d2f2f7c --- /dev/null +++ b/core/tests/manual/py-terminals/no-repl.html @@ -0,0 +1,20 @@ + + + + + + PyTerminal Prompt: NO REPL + + + + + + + + diff --git a/core/tests/manual/py-terminals/repl.html b/core/tests/manual/py-terminals/repl.html new file mode 100644 index 00000000000..e9b5f4766c0 --- /dev/null +++ b/core/tests/manual/py-terminals/repl.html @@ -0,0 +1,28 @@ + + + + + + PyTerminal Prompt: REPL + + + + + + + + diff --git a/core/tests/manual/py_modules.html b/core/tests/manual/py_modules.html new file mode 100644 index 00000000000..bb69b06c3ca --- /dev/null +++ b/core/tests/manual/py_modules.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/core/tests/manual/service-worker/index.html b/core/tests/manual/service-worker/index.html new file mode 100644 index 00000000000..a07332b41f0 --- /dev/null +++ b/core/tests/manual/service-worker/index.html @@ -0,0 +1,16 @@ + + + + Service Worker + + + + + + + + + diff --git a/core/tests/manual/service-worker/mini-coi.js b/core/tests/manual/service-worker/mini-coi.js new file mode 100644 index 00000000000..b7a23bf2d1f --- /dev/null +++ b/core/tests/manual/service-worker/mini-coi.js @@ -0,0 +1,28 @@ +/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */ +/*! mini-coi - Andrea Giammarchi and contributors, licensed under MIT */ +(({ document: d, navigator: { serviceWorker: s } }) => { + if (d) { + const { currentScript: c } = d; + s.register(c.src, { scope: c.getAttribute('scope') || '.' }).then(r => { + r.addEventListener('updatefound', () => location.reload()); + if (r.active && !s.controller) location.reload(); + }); + } + else { + addEventListener('install', () => skipWaiting()); + addEventListener('activate', e => e.waitUntil(clients.claim())); + addEventListener('fetch', e => { + const { request: r } = e; + if (r.cache === 'only-if-cached' && r.mode !== 'same-origin') return; + e.respondWith(fetch(r).then(r => { + const { body, status, statusText } = r; + if (!status || status > 399) return r; + const h = new Headers(r.headers); + h.set('Cross-Origin-Opener-Policy', 'same-origin'); + h.set('Cross-Origin-Embedder-Policy', 'require-corp'); + h.set('Cross-Origin-Resource-Policy', 'cross-origin'); + return new Response(body, { status, statusText, headers: h }); + })); + }); + } +})(self); diff --git a/core/tests/manual/service-worker/sabayon.js b/core/tests/manual/service-worker/sabayon.js new file mode 100644 index 00000000000..1e1996cfbf0 --- /dev/null +++ b/core/tests/manual/service-worker/sabayon.js @@ -0,0 +1 @@ +const{isArray:e}=Array,t=new Map,s=e=>{e.stopImmediatePropagation(),e.preventDefault()};var n=Object.freeze({__proto__:null,activate:e=>e.waitUntil(clients.claim()),fetch:e=>{const{request:n}=e;"POST"===n.method&&n.url===`${location.href}?sabayon`&&(s(e),e.respondWith(n.json().then((async e=>{const{promise:s,resolve:o}=Promise.withResolvers(),a=e.join(",");t.set(a,o);for(const t of await clients.matchAll())t.postMessage(e);return s.then((e=>new Response(`[${e.join(",")}]`,n.headers)))}))))},install:()=>skipWaiting(),message:n=>{const{data:o}=n;if(e(o)&&4===o.length){const[e,a,i,r]=o,l=[e,a,i].join(",");t.has(l)&&(s(n),t.get(l)(r),t.delete(l))}}});for(const e in n)addEventListener(e,n[e]); diff --git a/core/tests/manual/shenanigans.py b/core/tests/manual/shenanigans.py new file mode 100644 index 00000000000..4fa59bcd37b --- /dev/null +++ b/core/tests/manual/shenanigans.py @@ -0,0 +1,3 @@ +import sys + +print(sys.shenanigans) diff --git a/pyscript.core/test/split-config.html b/core/tests/manual/split-config.html similarity index 75% rename from pyscript.core/test/split-config.html rename to core/tests/manual/split-config.html index 434426bc101..48bf8e71b80 100644 --- a/pyscript.core/test/split-config.html +++ b/core/tests/manual/split-config.html @@ -5,13 +5,13 @@ PyScript Config - + [[fetch]] - files = ["a.py"] + files = ["./a.py"] + + + + + + + diff --git a/core/tests/manual/submit.py b/core/tests/manual/submit.py new file mode 100644 index 00000000000..e6136ee343d --- /dev/null +++ b/core/tests/manual/submit.py @@ -0,0 +1,6 @@ +from pyscript import document + + +def submit(event): + editor = document.querySelector("#editor") + editor.process(editor.code, True) diff --git a/pyscript.core/test/target.html b/core/tests/manual/target.html similarity index 92% rename from pyscript.core/test/target.html rename to core/tests/manual/target.html index 90703d60ea3..525d0e79f3d 100644 --- a/pyscript.core/test/target.html +++ b/core/tests/manual/target.html @@ -4,8 +4,8 @@ @pyscript/core - - + + diff --git a/pyscript.core/test/test_display_HTML.html b/core/tests/manual/test_display_HTML.html similarity index 77% rename from pyscript.core/test/test_display_HTML.html rename to core/tests/manual/test_display_HTML.html index ffd44a7024c..5a0909f0a8f 100644 --- a/pyscript.core/test/test_display_HTML.html +++ b/core/tests/manual/test_display_HTML.html @@ -4,8 +4,8 @@ PyScript Next: Display HTML - - + + diff --git a/pyscript.core/test/test_when.html b/core/tests/manual/test_when.html similarity index 81% rename from pyscript.core/test/test_when.html rename to core/tests/manual/test_when.html index 84d9b7ee63b..d322412e729 100644 --- a/pyscript.core/test/test_when.html +++ b/core/tests/manual/test_when.html @@ -4,8 +4,8 @@ PyScript Next: When Decorator - - + +

Click for a hi!

diff --git a/pyscript.core/test/worker.html b/core/tests/manual/worker.html similarity index 90% rename from pyscript.core/test/worker.html rename to core/tests/manual/worker.html index 0258328caec..5738444cc86 100644 --- a/pyscript.core/test/worker.html +++ b/core/tests/manual/worker.html @@ -4,11 +4,11 @@ PyScript Next - + + + + + + + + + + + +
+ +
+

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/core/tests/python/main.py b/core/tests/python/main.py new file mode 100644 index 00000000000..483c8797761 --- /dev/null +++ b/core/tests/python/main.py @@ -0,0 +1,8 @@ +import json + +import upytest +from pyscript import web + +result = await upytest.run("./tests", random=True) +output = web.div(json.dumps(result), id="result") +web.page.append(output) diff --git a/core/tests/python/settings_mpy.json b/core/tests/python/settings_mpy.json new file mode 100644 index 00000000000..fb46cf3b3ff --- /dev/null +++ b/core/tests/python/settings_mpy.json @@ -0,0 +1,27 @@ +{ + "files": { + "https://raw.githubusercontent.com/ntoll/upytest/1.0.9/upytest.py": "", + "./tests/test_config.py": "tests/test_config.py", + "./tests/test_current_target.py": "tests/test_current_target.py", + "./tests/test_display.py": "tests/test_display.py", + "./tests/test_document.py": "tests/test_document.py", + "./tests/test_fetch.py": "tests/test_fetch.py", + "./tests/test_ffi.py": "tests/test_ffi.py", + "./tests/test_js_modules.py": "tests/test_js_modules.py", + "./tests/test_media.py": "tests/test_media.py", + "./tests/test_storage.py": "tests/test_storage.py", + "./tests/test_running_in_worker.py": "tests/test_running_in_worker.py", + "./tests/test_web.py": "tests/test_web.py", + "./tests/test_websocket.py": "tests/test_websocket.py", + "./tests/test_events.py": "tests/test_events.py", + "./tests/test_window.py": "tests/test_window.py" + }, + "js_modules": { + "main": { + "./example_js_module.js": "greeting" + }, + "worker": { + "./example_js_worker_module.js": "greeting_worker" + } + } +} diff --git a/core/tests/python/settings_py.json b/core/tests/python/settings_py.json new file mode 100644 index 00000000000..c9167d513d0 --- /dev/null +++ b/core/tests/python/settings_py.json @@ -0,0 +1,28 @@ +{ + "files": { + "https://raw.githubusercontent.com/ntoll/upytest/1.0.9/upytest.py": "", + "./tests/test_config.py": "tests/test_config.py", + "./tests/test_current_target.py": "tests/test_current_target.py", + "./tests/test_display.py": "tests/test_display.py", + "./tests/test_document.py": "tests/test_document.py", + "./tests/test_fetch.py": "tests/test_fetch.py", + "./tests/test_ffi.py": "tests/test_ffi.py", + "./tests/test_media.py": "tests/test_media.py", + "./tests/test_js_modules.py": "tests/test_js_modules.py", + "./tests/test_storage.py": "tests/test_storage.py", + "./tests/test_running_in_worker.py": "tests/test_running_in_worker.py", + "./tests/test_web.py": "tests/test_web.py", + "./tests/test_websocket.py": "tests/test_websocket.py", + "./tests/test_events.py": "tests/test_events.py", + "./tests/test_window.py": "tests/test_window.py" + }, + "js_modules": { + "main": { + "./example_js_module.js": "greeting" + }, + "worker": { + "./example_js_worker_module.js": "greeting_worker" + } + }, + "packages": ["Pillow" ] +} diff --git a/core/tests/python/tests/test_config.py b/core/tests/python/tests/test_config.py new file mode 100644 index 00000000000..976aefd5459 --- /dev/null +++ b/core/tests/python/tests/test_config.py @@ -0,0 +1,20 @@ +""" +Tests for the pyscript.config dictionary. +""" + +from pyscript import config, document, fetch +from upytest import is_micropython + + +async def test_config_reads_expected_settings_correctly(): + """ + The config dictionary should read expected settings for this test suite. + + Just grab the raw JSON for the settings and compare it to the config + dictionary. + """ + settings = "/settings_mpy.json" if is_micropython else "/settings_py.json" + url = document.location.href.rsplit("/", 1)[0] + settings + raw_config = await fetch(url).json() + for key, value in raw_config.items(): + assert config[key] == value, f"Expected {key} to be {value}, got {config[key]}" diff --git a/core/tests/python/tests/test_current_target.py b/core/tests/python/tests/test_current_target.py new file mode 100644 index 00000000000..cc4e24d2301 --- /dev/null +++ b/core/tests/python/tests/test_current_target.py @@ -0,0 +1,19 @@ +""" +Ensure the pyscript.current_target function returns the expected target +element's id. +""" + +from pyscript import RUNNING_IN_WORKER, current_target +from upytest import is_micropython + + +def test_current_target(): + """ + The current_target function should return the expected target element's id. + """ + expected = "py-0" + if is_micropython: + expected = "mpy-w0-target" if RUNNING_IN_WORKER else "mpy-0" + elif RUNNING_IN_WORKER: + expected = "py-w0-target" + assert current_target() == expected, f"Expected {expected} got {current_target()}" diff --git a/core/tests/python/tests/test_display.py b/core/tests/python/tests/test_display.py new file mode 100644 index 00000000000..d891bf7cca0 --- /dev/null +++ b/core/tests/python/tests/test_display.py @@ -0,0 +1,289 @@ +""" +Tests for the display function in PyScript. +""" + +import asyncio + +import upytest +from pyscript import HTML, RUNNING_IN_WORKER, display, py_import, web + + +async def get_display_container(): + """ + Get the element that contains the output of the display function. + """ + if RUNNING_IN_WORKER: + # Needed to ensure the DOM has time to catch up with the display calls + # made in the worker thread. + await asyncio.sleep(0.01) + py_display = web.page.find("script-py") + if len(py_display) == 1: + return py_display[0] + mpy_display = web.page.find("script-mpy") + if len(mpy_display) == 1: + return mpy_display[0] + return None + + +async def setup(): + """ + Setup function for the test_display.py module. Remove all references to the + display output in the DOM so we always start from a clean state. + """ + container = await get_display_container() + if container: + container.replaceChildren() + target_container = web.page.find("#test-element-container")[0] + target_container.innerHTML = "" + + +async def teardown(): + """ + Like setup. + """ + container = await get_display_container() + if container: + container.replaceChildren() + target_container = web.page.find("#test-element-container")[0] + target_container.innerHTML = "" + + +async def test_simple_display(): + """ + Test the display function with a simple string. + """ + display("Hello, world") + container = await get_display_container() + assert len(container.children) == 1, "Expected one child in the display container." + assert ( + container.children[0].tagName == "DIV" + ), "Expected a div element in the display container." + assert container.children[0].innerHTML == "Hello, world" + + +async def test_consecutive_display(): + """ + Display order should be preserved. + """ + display("hello 1") + display("hello 2") + container = await get_display_container() + assert ( + len(container.children) == 2 + ), "Expected two children in the display container." + assert container.children[0].innerHTML == "hello 1" + assert container.children[1].innerHTML == "hello 2" + + +def test_target_parameter(): + """ + The output from display is placed in the target element. + """ + display("hello world", target="test-element-container") + target = web.page.find("#test-element-container")[0] + assert target.innerText == "hello world" + + +def test_target_parameter_with_hash(): + """ + The target parameter can have a hash in front of it. + """ + display("hello world", target="#test-element-container") + target = web.page.find("#test-element-container")[0] + assert target.innerText == "hello world" + + +def test_non_existing_id_target_raises_value_error(): + """ + If the target parameter is set to a non-existing element, a ValueError should be raised. + """ + with upytest.raises(ValueError): + display("hello world", target="non-existing") + + +def test_empty_string_target_raises_value_error(): + """ + If the target parameter is an empty string, a ValueError should be raised. + """ + with upytest.raises(ValueError) as exc: + display("hello world", target="") + assert str(exc.exception) == "Cannot have an empty target" + + +def test_non_string_target_values_raise_typerror(): + """ + The target parameter must be a string. + """ + with upytest.raises(TypeError) as exc: + display("hello world", target=True) + assert str(exc.exception) == "target must be str or None, not bool" + + with upytest.raises(TypeError) as exc: + display("hello world", target=123) + assert str(exc.exception) == "target must be str or None, not int" + + +async def test_tag_target_attribute(): + """ + The order and arrangement of the display calls (including targets) should be preserved. + """ + display("item 1") + display("item 2", target="test-element-container") + display("item 3") + container = await get_display_container() + assert ( + len(container.children) == 2 + ), "Expected two children in the display container." + assert container.children[0].innerHTML == "item 1" + assert container.children[1].innerHTML == "item 3" + target = web.page.find("#test-element-container")[0] + assert target.innerText == "item 2" + + +async def test_multiple_display_calls_same_tag(): + """ + Multiple display calls in the same script tag should be displayed in order. + """ + display("item 1") + display("item 2") + container = await get_display_container() + assert ( + len(container.children) == 2 + ), "Expected two children in the display container." + assert container.children[0].innerHTML == "item 1" + assert container.children[1].innerHTML == "item 2" + + +async def test_append_true(): + """ + Explicit append flag as true should append to the expected container element. + """ + display("item 1", append=True) + display("item 2", append=True) + container = await get_display_container() + assert ( + len(container.children) == 2 + ), "Expected two children in the display container." + assert container.children[0].innerHTML == "item 1" + assert container.children[1].innerHTML == "item 2" + + +async def test_append_false(): + """ + Explicit append flag as false should replace the expected container element. + """ + display("item 1", append=False) + display("item 2", append=False) + container = await get_display_container() + assert container.innerText == "item 2" + + +async def test_display_multiple_values(): + """ + Display multiple values in the same call. + """ + display("hello", "world") + container = await get_display_container() + assert container.innerText == "hello\nworld", container.innerText + + +async def test_display_multiple_append_false(): + display("hello", "world", append=False) + container = await get_display_container() + assert container.innerText == "world" + + +def test_display_multiple_append_false_with_target(): + """ + 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 + """ + + class Circle: + r = 0 + + def _repr_svg_(self): + return ( + f'' + f'' + ) + + circle = Circle() + circle.r += 5 + display(circle, circle, target="test-element-container", append=False) + target = web.page.find("#test-element-container")[0] + assert target.innerHTML == circle._repr_svg_() + + +async def test_display_list_dict_tuple(): + """ + Display a list, dictionary, and tuple with the expected __repr__. + + NOTE: MicroPython doesn't (yet) have ordered dicts. Hence the rather odd + check that the dictionary is displayed as a string. + """ + l = ["A", 1, "!"] + d = {"B": 2, "List": l} + t = ("C", 3, "!") + display(l, d, t) + container = await get_display_container() + l2, d2, t2 = container.innerText.split("\n") + assert l == eval(l2) + assert d == eval(d2) + assert t == eval(t2) + + +async def test_display_should_escape(): + display("

hello world

") + container = await get_display_container() + assert container[0].innerHTML == "<p>hello world</p>" + assert container.innerText == "

hello world

" + + +async def test_display_HTML(): + display(HTML("

hello world

")) + container = await get_display_container() + assert container[0].innerHTML == "

hello world

" + assert container.innerText == "hello world" + + +@upytest.skip( + "Pyodide main thread only", + skip_when=upytest.is_micropython or RUNNING_IN_WORKER, +) +async def test_image_display(): + """ + Check an image is displayed correctly. + """ + _mpl = await py_import("matplotlib") + import matplotlib.pyplot as plt + + xpoints = [3, 6, 9] + ypoints = [1, 2, 3] + plt.plot(xpoints, ypoints) + display(plt) + container = await get_display_container() + img = container.find("img")[0] + img_src = img.getAttribute("src").replace( + "data:image/png;charset=utf-8;base64,", "" + ) + assert len(img_src) > 0 + + +@upytest.skip( + "Pyodide main thread only", + skip_when=upytest.is_micropython or RUNNING_IN_WORKER, +) +async def test_image_renders_correctly(): + """ + This is just a sanity check to make sure that images are rendered + in a reasonable way. + """ + from PIL import Image + + img = Image.new("RGB", (4, 4), color=(0, 0, 0)) + display(img, target="test-element-container", append=False) + target = web.page.find("#test-element-container")[0] + img = target.find("img")[0] + assert img.src.startswith("data:image/png;charset=utf-8;base64") diff --git a/core/tests/python/tests/test_document.py b/core/tests/python/tests/test_document.py new file mode 100644 index 00000000000..24aa4176fe8 --- /dev/null +++ b/core/tests/python/tests/test_document.py @@ -0,0 +1,17 @@ +""" +Sanity check for the pyscript.document object. +""" + +from pyscript import document + + +def test_document(): + """ + The document object should be available and we can change its attributes + (in this case, the title). + """ + title = document.title + assert title + document.title = "A new title" + assert document.title == "A new title" + document.title = title diff --git a/core/tests/python/tests/test_events.py b/core/tests/python/tests/test_events.py new file mode 100644 index 00000000000..f9e37b99e59 --- /dev/null +++ b/core/tests/python/tests/test_events.py @@ -0,0 +1,360 @@ +""" +Tests for the when function and Event class. +""" + +import asyncio + +import upytest +from pyscript import RUNNING_IN_WORKER, web, Event, when + + +def get_container(): + return web.page.find("#test-element-container")[0] + + +def setup(): + container = get_container() + container.innerHTML = "" + + +def teardown(): + container = get_container() + container.innerHTML = "" + + +def test_event_add_listener(): + """ + Adding a listener to an event should add it to the list of listeners. It + should only be added once. + """ + event = Event() + listener = lambda x: x + event.add_listener(listener) + event.add_listener(listener) + assert len(event._listeners) == 1 # Only one item added. + assert listener in event._listeners # The item is the expected listener. + + +def test_event_remove_listener(): + """ + Removing a listener from an event should remove it from the list of + listeners. + """ + event = Event() + listener1 = lambda x: x + listener2 = lambda x: x + event.add_listener(listener1) + event.add_listener(listener2) + assert len(event._listeners) == 2 # Two listeners added. + assert listener1 in event._listeners # The first listener is in the list. + assert listener2 in event._listeners # The second listener is in the list. + event.remove_listener(listener1) + assert len(event._listeners) == 1 # Only one item remains. + assert listener2 in event._listeners # The second listener is in the list. + + +def test_event_remove_all_listeners(): + """ + Removing all listeners from an event should clear the list of listeners. + """ + event = Event() + listener1 = lambda x: x + listener2 = lambda x: x + event.add_listener(listener1) + event.add_listener(listener2) + assert len(event._listeners) == 2 # Two listeners added. + event.remove_listener() + assert len(event._listeners) == 0 # No listeners remain. + + +def test_event_trigger(): + """ + Triggering an event should call all of the listeners with the provided + arguments. + """ + event = Event() + counter = 0 + + def listener(x): + nonlocal counter + counter += 1 + assert x == "ok" + + event.add_listener(listener) + assert counter == 0 # The listener has not been triggered yet. + event.trigger("ok") + assert counter == 1 # The listener has been triggered with the expected result. + + +async def test_event_trigger_with_awaitable(): + """ + Triggering an event with an awaitable listener should call the listener + with the provided arguments. + """ + call_flag = asyncio.Event() + event = Event() + counter = 0 + + async def listener(x): + nonlocal counter + counter += 1 + assert x == "ok" + call_flag.set() + + event.add_listener(listener) + assert counter == 0 # The listener has not been triggered yet. + event.trigger("ok") + await call_flag.wait() + assert counter == 1 # The listener has been triggered with the expected result. + + +async def test_when_decorator_with_event(): + """ + When the decorated function takes a single parameter, + it should be passed the event object. + """ + btn = web.button("foo_button", id="foo_id") + container = get_container() + container.append(btn) + + called = False + call_flag = asyncio.Event() + + @when("click", selector="#foo_id") + def foo(evt): + nonlocal called + called = evt + call_flag.set() + + btn.click() + await call_flag.wait() + assert called.target.id == "foo_id" + + +async def test_when_decorator_without_event(): + """ + When the decorated function takes no parameters (not including 'self'), + it should be called without the event object. + """ + btn = web.button("foo_button", id="foo_id") + container = get_container() + container.append(btn) + + called = False + call_flag = asyncio.Event() + + @web.when("click", selector="#foo_id") + def foo(): + nonlocal called + called = True + call_flag.set() + + btn.click() + await call_flag.wait() + assert called is True + + +async def test_when_decorator_with_event_as_async_handler(): + """ + When the decorated function takes a single parameter, + it should be passed the event object. Async version. + """ + btn = web.button("foo_button", id="foo_id") + container = get_container() + container.append(btn) + + called = False + call_flag = asyncio.Event() + + @when("click", selector="#foo_id") + async def foo(evt): + nonlocal called + called = evt + call_flag.set() + + btn.click() + await call_flag.wait() + assert called.target.id == "foo_id" + + +async def test_when_decorator_without_event_as_async_handler(): + """ + When the decorated function takes no parameters (not including 'self'), + it should be called without the event object. Async version. + """ + btn = web.button("foo_button", id="foo_id") + container = get_container() + container.append(btn) + + called = False + call_flag = asyncio.Event() + + @web.when("click", selector="#foo_id") + async def foo(): + nonlocal called + called = True + call_flag.set() + + btn.click() + await call_flag.wait() + assert called is True + + +async def test_two_when_decorators(): + """ + When decorating a function twice, both should function + """ + btn = web.button("foo_button", id="foo_id") + container = get_container() + container.append(btn) + + called1 = False + called2 = False + call_flag1 = asyncio.Event() + call_flag2 = asyncio.Event() + + @when("click", selector="#foo_id") + def foo1(evt): + nonlocal called1 + called1 = True + call_flag1.set() + + @when("click", selector="#foo_id") + def foo2(evt): + nonlocal called2 + called2 = True + call_flag2.set() + + btn.click() + await call_flag1.wait() + await call_flag2.wait() + assert called1 + assert called2 + + +async def test_when_decorator_multiple_elements(): + """ + The @when decorator's selector should successfully select multiple + DOM elements + """ + btn1 = web.button( + "foo_button1", + id="foo_id1", + classes=[ + "foo_class", + ], + ) + btn2 = web.button( + "foo_button2", + id="foo_id2", + classes=[ + "foo_class", + ], + ) + container = get_container() + container.append(btn1) + container.append(btn2) + + counter = 0 + call_flag1 = asyncio.Event() + call_flag2 = asyncio.Event() + + @when("click", selector=".foo_class") + def foo(evt): + nonlocal counter + counter += 1 + if evt.target.id == "foo_id1": + call_flag1.set() + else: + call_flag2.set() + + assert counter == 0, counter + btn1.click() + await call_flag1.wait() + assert counter == 1, counter + btn2.click() + await call_flag2.wait() + assert counter == 2, counter + + +@upytest.skip( + "Only works in Pyodide on main thread", + skip_when=upytest.is_micropython or RUNNING_IN_WORKER, +) +def test_when_decorator_invalid_selector(): + """ + When the selector parameter of @when is invalid, it should raise an error. + """ + if upytest.is_micropython: + from jsffi import JsException + else: + from pyodide.ffi import JsException + + with upytest.raises(JsException) as e: + + @when("click", selector="#.bad") + def foo(evt): ... + + assert "'#.bad' is not a valid selector" in str(e.exception), str(e.exception) + + +def test_when_decorates_an_event(): + """ + When the @when decorator is used on a function to handle an Event instance, + the function should be called when the Event object is triggered. + """ + + whenable = Event() + counter = 0 + + # When as a decorator. + @when(whenable) + def handler(result): + """ + A function that should be called when the whenable object is triggered. + + The result generated by the whenable object should be passed to the + function. + """ + nonlocal counter + counter += 1 + assert result == "ok" + + # The function should not be called until the whenable object is triggered. + assert counter == 0 + # Trigger the whenable object. + whenable.trigger("ok") + # The function should have been called when the whenable object was + # triggered. + assert counter == 1 + + +def test_when_called_with_an_event_and_handler(): + """ + The when function should be able to be called with an Event object, + and a handler function. + """ + whenable = Event() + counter = 0 + + def handler(result): + """ + A function that should be called when the whenable object is triggered. + + The result generated by the whenable object should be passed to the + function. + """ + nonlocal counter + counter += 1 + assert result == "ok" + + # When as a function. + when(whenable, handler) + + # The function should not be called until the whenable object is triggered. + assert counter == 0 + # Trigger the whenable object. + whenable.trigger("ok") + # The function should have been called when the whenable object was + # triggered. + assert counter == 1 diff --git a/core/tests/python/tests/test_fetch.py b/core/tests/python/tests/test_fetch.py new file mode 100644 index 00000000000..0af2322a751 --- /dev/null +++ b/core/tests/python/tests/test_fetch.py @@ -0,0 +1,83 @@ +""" +Ensure the pyscript.test function behaves as expected. +""" + +from pyscript import fetch + + +async def test_fetch_json(): + """ + The fetch function should return the expected JSON response. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1") + assert response.ok + data = await response.json() + assert data["userId"] == 1 + assert data["id"] == 1 + assert data["title"] == "delectus aut autem" + assert data["completed"] is False + + +async def test_fetch_text(): + """ + The fetch function should return the expected text response. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1") + assert response.ok + text = await response.text() + assert "delectus aut autem" in text + assert "completed" in text + assert "false" in text + assert "1" in text + + +async def test_fetch_bytearray(): + """ + The fetch function should return the expected bytearray response. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1") + assert response.ok + data = await response.bytearray() + assert b"delectus aut autem" in data + assert b"completed" in data + assert b"false" in data + assert b"1" in data + + +async def test_fetch_array_buffer(): + """ + The fetch function should return the expected array buffer response. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1") + assert response.ok + data = await response.arrayBuffer() + bytes_ = bytes(data) + assert b"delectus aut autem" in bytes_ + assert b"completed" in bytes_ + assert b"false" in bytes_ + assert b"1" in bytes_ + + +async def test_fetch_ok(): + """ + The fetch function should return a response with ok set to True for an + existing URL. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1") + assert response.ok + assert response.status == 200 + data = await response.json() + assert data["userId"] == 1 + assert data["id"] == 1 + assert data["title"] == "delectus aut autem" + assert data["completed"] is False + + +async def test_fetch_not_ok(): + """ + The fetch function should return a response with ok set to False for a + non-existent URL. + """ + response = await fetch("https://jsonplaceholder.typicode.com/todos/1000") + assert not response.ok + assert response.status == 404 diff --git a/core/tests/python/tests/test_ffi.py b/core/tests/python/tests/test_ffi.py new file mode 100644 index 00000000000..4957598484e --- /dev/null +++ b/core/tests/python/tests/test_ffi.py @@ -0,0 +1,40 @@ +""" +Exercise (as much as is possible) the pyscript.ffi namespace. +""" + +import upytest +from pyscript import ffi + + +def test_create_proxy(): + """ + The create_proxy function should return a proxy object that is callable. + """ + + def func(): + return 42 + + proxy = ffi.create_proxy(func) + assert proxy() == 42 + if upytest.is_micropython: + from jsffi import JsProxy + else: + from pyodide.ffi import JsProxy + assert isinstance(proxy, JsProxy) + + +def test_to_js(): + """ + The to_js function should convert a Python object to a JavaScript object. + In this instance, a Python dict should be converted to a JavaScript object + represented by a JsProxy object. + """ + obj = {"a": 1, "b": 2} + js_obj = ffi.to_js(obj) + assert js_obj.a == 1 + assert js_obj.b == 2 + if upytest.is_micropython: + from jsffi import JsProxy + else: + from pyodide.ffi import JsProxy + assert isinstance(js_obj, JsProxy) diff --git a/core/tests/python/tests/test_js_modules.py b/core/tests/python/tests/test_js_modules.py new file mode 100644 index 00000000000..db474a9426a --- /dev/null +++ b/core/tests/python/tests/test_js_modules.py @@ -0,0 +1,52 @@ +""" +Ensure referenced JavaScript modules are available via the pyscript.js_modules +object. +""" + +import upytest +from pyscript import RUNNING_IN_WORKER + + +@upytest.skip("Main thread only.", skip_when=RUNNING_IN_WORKER) +def test_js_module_is_available_on_main(): + """ + The "hello" function in the example_js_module.js file is available via the + js_modules object while running in the main thread. See the settings.json + file for the configuration that makes this possible. + """ + from pyscript.js_modules import greeting + + assert greeting.hello() == "Hello from JavaScript!" + + +@upytest.skip("Worker only.", skip_when=not RUNNING_IN_WORKER) +def test_js_module_is_available_on_worker(): + """ + The "hello" function in the example_js_module.js file is available via the + js_modules object while running in a worker. See the settings.json file for + the configuration that makes this possible. + """ + from pyscript.js_modules import greeting + + assert greeting.hello() == "Hello from JavaScript!" + + +@upytest.skip("Worker only.", skip_when=not RUNNING_IN_WORKER) +def test_js_module_is_available_on_worker(): + """ + The "hello" function in the example_js_worker_module.js file is available + via the js_modules object while running in a worker. + """ + from pyscript.js_modules import greeting_worker + + assert greeting_worker.hello() == "Hello from JavaScript in a web worker!" + + +@upytest.skip("Main thread only.", skip_when=RUNNING_IN_WORKER) +def test_js_worker_module_is_not_available_on_main(): + """ + The "hello" function in the example_js_worker_module.js file is not + available via the js_modules object while running in the main thread. + """ + with upytest.raises(ImportError): + from pyscript.js_modules import greeting_worker diff --git a/core/tests/python/tests/test_media.py b/core/tests/python/tests/test_media.py new file mode 100644 index 00000000000..fd9658383cb --- /dev/null +++ b/core/tests/python/tests/test_media.py @@ -0,0 +1,87 @@ +"""" +Tests for the PyScript media module. +""" + +from pyscript import media +import upytest + +from pyscript import media + + +@upytest.skip( + "Uses Pyodide-specific to_js function in MicroPython", + skip_when=upytest.is_micropython, +) +async def test_device_enumeration(): + """Test enumerating media devices.""" + devices = await media.list_devices() + assert isinstance(devices, list), "list_devices should return a list" + + # If devices are found, verify they have the expected functionality + if devices: + device = devices[0] + + # Test real device properties exist (but don't assert on their values) + # Browser security might restrict actual values until permissions are granted + assert hasattr(device, "id"), "Device should have id property" + assert hasattr(device, "kind"), "Device should have kind property" + assert device.kind in [ + "videoinput", + "audioinput", + "audiooutput", + ], f"Device should have a valid kind, got: {device.kind}" + + # Verify dictionary access works with actual device + assert ( + device["id"] == device.id + ), "Dictionary access should match property access" + assert ( + device["kind"] == device.kind + ), "Dictionary access should match property access" + + +@upytest.skip("Waiting on a bug-fix in MicroPython, for this test to work.", skip_when=upytest.is_micropython) +async def test_video_stream_acquisition(): + """Test video stream.""" + try: + # Load a video stream + stream = await media.Device.load(video=True) + + # Verify we get a real stream with expected properties + assert hasattr(stream, "active"), "Stream should have active property" + + # Check for video tracks, but don't fail if permissions aren't granted + if stream._dom_element and hasattr(stream._dom_element, "getVideoTracks"): + tracks = stream._dom_element.getVideoTracks() + if tracks.length > 0: + assert True, "Video stream has video tracks" + except Exception as e: + # If the browser blocks access, the test should still pass + # This is because we're testing the API works, not that permissions are granted + assert ( + True + ), f"Stream acquisition attempted but may require permissions: {str(e)}" + + +@upytest.skip("Waiting on a bug-fix in MicroPython, for this test to work.", skip_when=upytest.is_micropython) +async def test_custom_video_constraints(): + """Test loading video with custom constraints.""" + try: + # Define custom constraints + constraints = {"width": 640, "height": 480} + + # Load stream with custom constraints + stream = await media.Device.load(video=constraints) + + # Basic stream property check + assert hasattr(stream, "active"), "Stream should have active property" + + # Check for tracks only if we have access + if stream._dom_element and hasattr(stream._dom_element, "getVideoTracks"): + tracks = stream._dom_element.getVideoTracks() + if tracks.length > 0 and hasattr(tracks[0], "getSettings"): + # Settings verification is optional - browsers may handle constraints differently + pass + except Exception as e: + # If the browser blocks access, test that the API structure works + assert True, f"Custom constraint test attempted: {str(e)}" diff --git a/core/tests/python/tests/test_running_in_worker.py b/core/tests/python/tests/test_running_in_worker.py new file mode 100644 index 00000000000..de7b6b89fbc --- /dev/null +++ b/core/tests/python/tests/test_running_in_worker.py @@ -0,0 +1,27 @@ +""" +Ensure the pyscript.RUNNING_IN_WORKER flag is set correctly (a sanity check). +""" + +import upytest +from pyscript import RUNNING_IN_WORKER, document + +# In the test suite, running in a worker is flagged by the presence of the +# "worker" query string. We do this to avoid using RUNNING_IN_WORKER to skip +# tests that check RUNNING_IN_WORKER. +in_worker = "worker" in document.location.search.lower() + + +@upytest.skip("Main thread only.", skip_when=in_worker) +def test_running_in_main(): + """ + The flag should be False. + """ + assert RUNNING_IN_WORKER is False + + +@upytest.skip("Worker only.", skip_when=not in_worker) +def test_running_in_worker(): + """ + The flag should be True. + """ + assert RUNNING_IN_WORKER is True diff --git a/core/tests/python/tests/test_storage.py b/core/tests/python/tests/test_storage.py new file mode 100644 index 00000000000..674a82b3977 --- /dev/null +++ b/core/tests/python/tests/test_storage.py @@ -0,0 +1,88 @@ +""" +Ensure the pyscript.storage object behaves as a Python dict. +""" + +from pyscript import Storage, storage + +test_store = None + + +async def setup(): + global test_store + if test_store is None: + test_store = await storage("test_store") + test_store.clear() + await test_store.sync() + + +async def teardown(): + if test_store: + test_store.clear() + await test_store.sync() + + +async def test_storage_as_dict(): + """ + The storage object should behave as a Python dict. + """ + # Assign + test_store["a"] = 1 + # Retrieve + assert test_store["a"] == 1 + assert "a" in test_store + assert len(test_store) == 1 + # Iterate + for k, v in test_store.items(): + assert k == "a" + assert v == 1 + # Remove + del test_store["a"] + assert "a" not in test_store + assert len(test_store) == 0 + + +async def test_storage_types(): + """ + The storage object should support different types of values. + """ + test_store["boolean"] = False + test_store["integer"] = 42 + test_store["float"] = 3.14 + test_store["string"] = "hello" + test_store["none"] = None + test_store["list"] = [1, 2, 3] + test_store["dict"] = {"a": 1, "b": 2} + test_store["tuple"] = (1, 2, 3) + test_store["bytearray"] = bytearray(b"hello") + test_store["memoryview"] = memoryview(b"hello") + await test_store.sync() + assert test_store["boolean"] is False + assert isinstance(test_store["boolean"], bool) + assert test_store["integer"] == 42 + assert isinstance(test_store["integer"], int) + assert test_store["float"] == 3.14 + assert isinstance(test_store["float"], float) + assert test_store["string"] == "hello" + assert isinstance(test_store["string"], str) + assert test_store["none"] is None + assert test_store["list"] == [1, 2, 3] + assert isinstance(test_store["list"], list) + assert test_store["dict"] == {"a": 1, "b": 2} + assert isinstance(test_store["dict"], dict) + assert test_store["tuple"] == (1, 2, 3) + assert isinstance(test_store["tuple"], tuple) + assert test_store["bytearray"] == bytearray(b"hello") + assert isinstance(test_store["bytearray"], bytearray) + assert test_store["memoryview"] == memoryview(b"hello") + assert isinstance(test_store["memoryview"], memoryview) + + +async def test_storage_clear(): + """ + The clear method should remove all items from the storage object. + """ + test_store["a"] = 1 + test_store["b"] = 2 + assert len(test_store) == 2 + test_store.clear() + assert len(test_store) == 0 diff --git a/core/tests/python/tests/test_util.py b/core/tests/python/tests/test_util.py new file mode 100644 index 00000000000..ebf15c6b6de --- /dev/null +++ b/core/tests/python/tests/test_util.py @@ -0,0 +1,48 @@ +import upytest +import js +from pyscript import util + + +def test_as_bytearray(): + """ + Test the as_bytearray function correctly converts a JavaScript ArrayBuffer + to a Python bytearray. + """ + msg = b"Hello, world!" + buffer = js.ArrayBuffer.new(len(msg)) + ui8a = js.Uint8Array.new(buffer) + for b in msg: + ui8a[i] = b + ba = util.as_bytearray(buffer) + assert isinstance(ba, bytearray) + assert ba == msg + + +def test_not_supported(): + """ + Test the NotSupported class raises an exception when trying to access + attributes or call the object. + """ + ns = util.NotSupported("test", "This is not supported.") + with upytest.raises(AttributeError) as e: + ns.test + assert str(e.exception) == "This is not supported.", str(e.exception) + with upytest.raises(AttributeError) as e: + ns.test = 1 + assert str(e.exception) == "This is not supported.", str(e.exception) + with upytest.raises(TypeError) as e: + ns() + assert str(e.exception) == "This is not supported.", str(e.exception) + + +def test_is_awaitable(): + """ + Test the is_awaitable function correctly identifies an asynchronous + function. + """ + + async def async_func(): + yield + + assert util.is_awaitable(async_func) + assert not util.is_awaitable(lambda: None) diff --git a/core/tests/python/tests/test_web.py b/core/tests/python/tests/test_web.py new file mode 100644 index 00000000000..19bc8ab44bb --- /dev/null +++ b/core/tests/python/tests/test_web.py @@ -0,0 +1,1187 @@ +""" +Tests for the pyscript.web module. +""" + +import asyncio + +import upytest +from pyscript import RUNNING_IN_WORKER, document, web, when + + +def setup(): + container = web.page.find("#test-element-container")[0] + container.innerHTML = "" + + +def teardown(): + container = web.page.find("#test-element-container")[0] + container.innerHTML = "" + + +def test_getitem_by_id(): + """ + An element with an id in the DOM can be retrieved by id. + """ + result = web.page.find("#div-no-classes") + # There is a single result. + assert len(result) == 1 + # The result is a div. + assert result[0].get_tag_name() == "div" + + +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 = web.page.find(f".{expected_class}") + + # 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 = web.page.find(".multi-elems") + + for element in elements: + assert element.innerHTML == f"Content {element.id.replace('#', '')}" + + new_content = "New Content" + elements.innerHTML = new_content + for element in elements: + assert element.innerHTML == 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 = web.page.find(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.id == parent_div.id + ), f"The parent of the new element should be the parent div, but got {div.parent} instead of {parent_div}" + # EXPECT the new element to be an Element + assert isinstance(div, web.Element), "The new element should be an Element" + # EXPECT the div attributes to be == to how they are configured in the page + assert ( + div.innerHTML == "Child 1" + ), f"The innerHTML of the div should be 'Child 1', but got {div.innerHTML}" + assert ( + div.id == "test_selector_w_children_child_1" + ), f"The id of the div should be 'test_selector_w_children_child_1', but got {div.id}" + + def test_equality(self): + # GIVEN 2 different Elements pointing to the same underlying element + id_ = "test_id_selector" + selector = f"#{id_}" + div = web.page.find(selector)[0] + div2 = web.page.find(selector)[0] + + # EXPECT them to be equal + assert div.id == div2.id + # EXPECT them to be different objects + assert div is not div2 + + # EXPECT their value to always be equal + assert div.innerHTML == div2.innerHTML + div.innerHTML = "some value" + + assert div.innerHTML == div2.innerHTML == "some value" + + def test_append_element(self): + id_ = "element-append-tests" + div = web.page.find(f"#{id_}")[0] + len_children_before = len(div.children) + new_el = web.p("new element") + div.append(new_el) + assert len(div.children) == len_children_before + 1 + assert div.children[-1].id == new_el.id + + def test_append_dom_element_element(self): + id_ = "element-append-tests" + div = web.page.find(f"#{id_}")[0] + len_children_before = len(div.children) + new_el = web.p("new element") + div.append(new_el._dom_element) + assert len(div.children) == len_children_before + 1 + assert div.children[-1].id == new_el.id + + def test_append_collection(self): + id_ = "element-append-tests" + div = web.page.find(f"#{id_}")[0] + len_children_before = len(div.children) + collection = web.page.find(".collection") + div.append(collection) + assert len(div.children) == len_children_before + len(collection) + + for i in range(len(collection)): + assert div.children[-1 - i].id == collection[-1 - i].id + + def test_read_classes(self): + id_ = "test_class_selector" + expected_class = "a-test-class" + div = web.page.find(f"#{id_}")[0] + assert div.classes == [expected_class] + + def test_add_remove_class(self): + id_ = "div-no-classes" + classname = "tester-class" + div = web.page.find(f"#{id_}")[0] + assert not div.classes + div.classes.add(classname) + same_div = web.page.find(f"#{id_}")[0] + assert div.classes == [classname] == same_div.classes + div.classes.remove(classname) + assert div.classes == [] == same_div.classes + + async def test_when_decorator(self): + called = False + + just_a_button = web.page.find("#a-test-button")[0] + call_flag = asyncio.Event() + + @when("click", just_a_button) + def on_click(event): + nonlocal called + called = True + call_flag.set() + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk dom getting in the way + assert not called + just_a_button._dom_element.click() + await call_flag.wait() + assert called + + async def test_when_decorator_on_event(self): + called = False + + another_button = web.page.find("#another-test-button")[0] + call_flag = asyncio.Event() + + assert another_button.on_click is not None + assert isinstance(another_button.on_click, web.Event) + + @when(another_button.on_click) + def on_click(event): + nonlocal called + called = True + call_flag.set() + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk dom getting in the way + assert not called + another_button._dom_element.click() + await call_flag.wait() + assert called + + async def test_on_event_with_default_handler(self): + called = False + call_flag = asyncio.Event() + + def handler(event): + nonlocal called + called = True + call_flag.set() + + b = web.button("Click me", on_click=handler) + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk dom getting in the way + assert not called + b._dom_element.click() + await call_flag.wait() + assert called + + def test_on_event_must_be_actual_event(self): + """ + Any on_FOO event must relate to an actual FOO event on the element. + """ + b = web.button("Click me") + # Non-existent event causes a ValueError + with upytest.raises(ValueError): + b.on_chicken + # Buttons have an underlying "click" event so this will work. + assert b.on_click + + def test_inner_html_attribute(self): + # GIVEN an existing element on the page with a known empty text content + div = web.page.find("#element_attribute_tests")[0] + + # WHEN we set the html attribute + div.innerHTML = "New Content" + + # EXPECT the element html and underlying JS Element innerHTML property + # to match what we expect and what + assert div.innerHTML == div._dom_element.innerHTML == "New Content" + assert div.textContent == div._dom_element.textContent == "New Content" + + def test_text_attribute(self): + # GIVEN an existing element on the page with a known empty text content + div = web.page.find("#element_attribute_tests")[0] + + # WHEN we set the html attribute + div.textContent = "New Content" + + # EXPECT the element html and underlying JS Element innerHTML property + # to match what we expect and what + assert ( + div.innerHTML + == div._dom_element.innerHTML + == "<b>New Content</b>" + ) + assert div.textContent == div._dom_element.textContent == "New Content" + + +class TestCollection: + + def test_iter_eq_children(self): + elements = web.page.find(".multi-elems") + assert list(elements) == list(elements.elements) + assert len(elements) == 3 + + def test_slices(self): + elements = web.page.find(".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 = web.page.find(selector) + for el in elements: + assert el.style["background-color"] != "red" + + elements.style["background-color"] = "red" + + for i, el in enumerate(web.page.find(selector)): + assert elements[i].style["background-color"] == "red" + assert el.style["background-color"] == "red" + + elements.style.remove("background-color") + + for i, el in enumerate(web.page.find(selector)): + assert el.style["background-color"] != "red" + assert elements[i].style["background-color"] != "red" + + @upytest.skip( + "Flakey in Pyodide on Worker", + skip_when=RUNNING_IN_WORKER and not upytest.is_micropython, + ) + async def test_when_decorator(self): + called = False + call_flag = asyncio.Event() + + buttons_collection = web.page["button"] + + @when("click", buttons_collection) + def on_click(event): + nonlocal called + called = True + call_flag.set() + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk dom getting in the way + assert not called + for button in buttons_collection: + button._dom_element.click() + await call_flag.wait() + assert called + called = False + call_flag.clear() + + async def test_when_decorator_on_event(self): + call_counter = 0 + call_flag = asyncio.Event() + + buttons_collection = web.page.find("button") + number_of_clicks = len(buttons_collection) + + @when(buttons_collection.on_click) + def on_click(event): + nonlocal call_counter + call_counter += 1 + if call_counter == number_of_clicks: + call_flag.set() + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk dom getting in the way + assert call_counter == 0 + for button in buttons_collection: + button._dom_element.click() + await call_flag.wait() + assert call_counter == number_of_clicks + + +class TestCreation: + + def test_create_document_element(self): + # TODO: This test should probably be removed since it's testing the elements + # module. + new_el = web.div("new element") + new_el.id = "new_el_id" + assert isinstance(new_el, web.Element) + assert new_el._dom_element.tagName == "DIV" + # EXPECT the new element to be associated with the document + assert new_el.parent is None + web.page.body.append(new_el) + + assert web.page.find("#new_el_id")[0].parent.tagName == web.page.body.tagName + + def test_create_element_child(self): + selector = "#element-creation-test" + parent_div = web.page.find(selector)[0] + + # Creating an element from another element automatically creates that element + # as a child of the original element + new_el = web.p( + "a div", + classes=["code-description"], + innerHTML="Ciao PyScripters!", + id="test-new-el", + ) + parent_div.append(new_el) + + assert isinstance(new_el, web.Element) + assert new_el._dom_element.tagName == "P" + + # EXPECT the new element to be associated with the document + assert new_el.parent.id == parent_div.id + assert web.page.find(selector)[0].children[0].id == new_el.id + + +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 = web.page.find(f"#{id_}") + input_el = result[0] + assert input_el._dom_element.type == expected_type + assert ( + input_el.value == f"Content {id_}" == input_el._dom_element.value + ), f"Expected '{input_el.value}' to be 'Content {id_}' to be '{input_el._dom_element.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 = web.page.find(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 + ), f"Expected '{input_el.value}' to be 'Content {id_}' to be '{input_el._dom_element.value}'" + + new_value = f"Content {id_}" + input_el.value = new_value + + # TODO: We only attach attributes to the classes that have them now which means we + # would have to have some other way to help users if using attributes that aren't + # actually on the class. Maybe a job for __setattr__? + # + # def test_element_without_value(self): + # result = web.page.find(f"#tests-terminal"][0] + # with upytest.raises(AttributeError): + # result.value = "some value" + # + # def test_element_without_value_via_collection(self): + # result = web.page.find(f"#tests-terminal"] + # with upytest.raises(AttributeError): + # result.value = "some value" + + +class TestSelect: + + def test_select_options_iter(self): + select = web.page.find("#test_select_element_w_options")[0] + + for i, option in enumerate(select.options, 1): + assert option.value == f"{i}" + assert option.innerHTML == f"Option {i}" + + def test_select_options_len(self): + select = web.page.find("#test_select_element_w_options")[0] + assert len(select.options) == 2 + + def test_select_options_clear(self): + select = web.page.find("#test_select_element_to_clear")[0] + assert len(select.options) == 3 + + select.options.clear() + + assert len(select.options) == 0 + + def test_select_element_add(self): + # GIVEN the existing select element with no options + select = web.page.find("#test_select_element")[0] + + # EXPECT the select element to have no options + assert len(select.options) == 0 + + # WHEN we add an option + select.options.add(value="1", html="Option 1") + + # EXPECT the select element to have 1 option matching the attributes + # we passed in + assert len(select.options) == 1 + assert select.options[0].value == "1" + assert select.options[0].innerHTML == "Option 1" + + # WHEN we add another option (blank this time) + select.options.add("") + + # EXPECT the select element to have 2 options + assert len(select.options) == 2 + + # EXPECT the last option to have an empty value and html + assert select.options[1].value == "" + assert select.options[1].innerHTML == "" + + # WHEN we add another option (this time adding it in between the other 2 + # options by using an integer index) + select.options.add(value="2", html="Option 2", before=1) + + # EXPECT the select element to have 3 options + assert len(select.options) == 3 + + # EXPECT the middle option to have the value and html we passed in + assert select.options[0].value == "1" + assert select.options[0].innerHTML == "Option 1" + assert select.options[1].value == "2" + assert select.options[1].innerHTML == "Option 2" + assert select.options[2].value == "" + assert select.options[2].innerHTML == "" + + # WHEN we add another option (this time adding it in between the other 2 + # options but using the option itself) + select.options.add( + value="3", html="Option 3", before=select.options[2], selected=True + ) + + # EXPECT the select element to have 3 options + assert len(select.options) == 4 + + # EXPECT the middle option to have the value and html we passed in + assert select.options[0].value == "1" + assert select.options[0].innerHTML == "Option 1" + assert select.options[0].selected == select.options[0]._dom_element.selected + assert select.options[0].selected is False + assert select.options[1].value == "2" + assert select.options[1].innerHTML == "Option 2" + assert select.options[2].value == "3" + assert select.options[2].innerHTML == "Option 3" + assert select.options[2].selected == select.options[2]._dom_element.selected + assert select.options[2].selected is True + assert select.options[3].value == "" + assert select.options[3].innerHTML == "" + + # WHEN we add another option (this time adding it in between the other 2 + # options but using the JS element of the option itself) + select.options.add( + value="2a", html="Option 2a", before=select.options[2]._dom_element + ) + + # EXPECT the select element to have 3 options + assert len(select.options) == 5 + + # EXPECT the middle option to have the value and html we passed in + assert select.options[0].value == "1" + assert select.options[0].innerHTML == "Option 1" + assert select.options[1].value == "2" + assert select.options[1].innerHTML == "Option 2" + assert select.options[2].value == "2a" + assert select.options[2].innerHTML == "Option 2a" + assert select.options[3].value == "3" + assert select.options[3].innerHTML == "Option 3" + assert select.options[4].value == "" + assert select.options[4].innerHTML == "" + + def test_select_options_remove(self): + # GIVEN the existing select element with 3 options + select = web.page.find("#test_select_element_to_remove")[0] + + # EXPECT the select element to have 3 options + assert len(select.options) == 4 + # EXPECT the options to have the values originally set + assert select.options[0].value == "1" + assert select.options[1].value == "2" + assert select.options[2].value == "3" + assert select.options[3].value == "4" + + # WHEN we remove the second option (index starts at 0) + select.options.remove(1) + + # EXPECT the select element to have 2 options + assert len(select.options) == 3 + # EXPECT the options to have the values originally set but the second + assert select.options[0].value == "1" + assert select.options[1].value == "3" + assert select.options[2].value == "4" + + def test_select_get_selected_option(self): + # GIVEN the existing select element with one selected option + select = web.page.find("#test_select_element_w_options")[0] + + # WHEN we get the selected option + selected_option = select.options.selected + + # EXPECT the selected option to be correct + assert selected_option.value == "2" + assert selected_option.innerHTML == "Option 2" + assert selected_option.selected == selected_option._dom_element.selected + assert selected_option.selected is True + + +class TestElements: + """ + This class tests all elements in the pyweb.ui.elements module. It creates + an element of each type, both executing in the main thread and in a worker. + It runs each test for each interpreter defined in `INTERPRETERS` + + Each individual element test looks for the element properties, sets a value + on each the supported properties and checks if the element was created correctly + and all it's properties were set correctly. + """ + + def __init__(self): + # This module's setup function ensures self.container is empty. + self.container = web.page.find("#test-element-container")[0] + + def _create_el_and_basic_asserts( + self, + el_type, + el_text=None, + properties=None, + additional_selector_rules=None, + ): + """ + Create an element with all its properties set then check if the + element was created correctly and all its properties were set correctly. + """ + if not properties: + properties = {} + + def parse_value(v): + if isinstance(v, bool): + return str(v) + + return f"{v}" + + args = [] + kwargs = {} + if el_text: + args.append(el_text) + + if properties: + kwargs = {k: parse_value(v) for k, v in properties.items()} + + # Let's make sure the target div to contain the element is empty. + container = web.page["#test-element-container"][0] + container.innerHTML = "" + assert container.innerHTML == "", container.innerHTML + + # Let's create the element + try: + klass = getattr(web, el_type) + el = klass(*args, **kwargs) + container.append(el) + except Exception as e: + msg = f"Failed to create element {el_type}: {e}" + raise AssertionError(msg) + + # Let's keep the tag in 2 variables, one for the selector and another to + # check the return tag from the selector + locator_type = el_tag = el_type[:-1] if el_type.endswith("_") else el_type + if additional_selector_rules: + locator_type += f"{additional_selector_rules}" + + el = container.find(locator_type)[0] + el.tagName == el_tag.upper() + if el_text: + assert ( + el.innerHTML == el_text + ), f"In {el.tagName}, expected {el_text} but got {el.innerHTML}" + assert el.textContent == el_text + + if properties: + for k, v in properties.items(): + assert v == getattr(el, k), f"{k} should be {v} but is {getattr(el, k)}" + return el + + def test_a(self): + a = self._create_el_and_basic_asserts("a", "click me") + assert a.textContent == "click me" + + def test_abbr(self): + abbr = self._create_el_and_basic_asserts("abbr", "some text") + assert abbr.textContent == "some text" + + def test_address(self): + address = self._create_el_and_basic_asserts("address", "some text") + assert address.textContent == "some text" + + def test_area(self): + properties = { + "shape": "poly", + "coords": "129,0,260,95,129,138", + "href": "https://developer.mozilla.org/docs/Web/HTTP", + "target": "_blank", + "alt": "HTTP", + } + # TODO: Check why click times out + self._create_el_and_basic_asserts("area", properties=properties) + + def test_article(self): + self._create_el_and_basic_asserts("article", "some text") + + def test_aside(self): + self._create_el_and_basic_asserts("aside", "some text") + + def test_audio(self): + self._create_el_and_basic_asserts( + "audio", + properties={ + "src": "http://localhost:8080/somefile.ogg", + "controls": True, + }, + ) + + def test_b(self): + self._create_el_and_basic_asserts("b", "some text") + + def test_blockquote(self): + self._create_el_and_basic_asserts("blockquote", "some text") + + def test_br(self): + self._create_el_and_basic_asserts("br") + + def test_element_button(self): + button = self._create_el_and_basic_asserts("button", "click me") + assert button.innerHTML == "click me" + + def test_element_button_attributes(self): + button = self._create_el_and_basic_asserts("button", "click me", None) + assert button.innerHTML == "click me" + + def test_canvas(self): + properties = { + "height": 100, + "width": 120, + } + # TODO: Check why click times out + self._create_el_and_basic_asserts( + "canvas", "alt text for canvas", properties=properties + ) + + def test_caption(self): + self._create_el_and_basic_asserts("caption", "some text") + + def test_cite(self): + self._create_el_and_basic_asserts("cite", "some text") + + def test_code(self): + self._create_el_and_basic_asserts("code", "import pyweb") + + def test_data(self): + self._create_el_and_basic_asserts( + "data", "some text", properties={"value": "123"} + ) + + def test_datalist(self): + self._create_el_and_basic_asserts("datalist", "some items") + + def test_dd(self): + self._create_el_and_basic_asserts("dd", "some text") + + def test_del_(self): + self._create_el_and_basic_asserts( + "del_", "some text", properties={"cite": "http://example.com/"} + ) + + def test_details(self): + self._create_el_and_basic_asserts( + "details", "some text", properties={"open": True} + ) + + def test_dialog(self): + self._create_el_and_basic_asserts( + "dialog", "some text", properties={"open": True} + ) + + def test_div(self): + div = self._create_el_and_basic_asserts("div", "click me") + assert div.innerHTML == "click me" + + def test_dl(self): + self._create_el_and_basic_asserts("dl", "some text") + + def test_dt(self): + self._create_el_and_basic_asserts("dt", "some text") + + def test_em(self): + self._create_el_and_basic_asserts("em", "some text") + + def test_embed(self): + # NOTE: Types actually matter and embed expects a string for height and width + # while other elements expect an int + + # TODO: It's important that we add typing soon to help with the user experience + properties = { + "src": "http://localhost:8080/somefile.ogg", + "type": "video/ogg", + "width": "250", + "height": "200", + } + self._create_el_and_basic_asserts("embed", properties=properties) + + def test_fieldset(self): + self._create_el_and_basic_asserts( + "fieldset", "some text", properties={"name": "some name"} + ) + + def test_figcaption(self): + self._create_el_and_basic_asserts("figcaption", "some text") + + def test_figure(self): + self._create_el_and_basic_asserts("figure", "some text") + + def test_footer(self): + self._create_el_and_basic_asserts("footer", "some text") + + def test_form(self): + properties = { + "action": "https://example.com/submit", + "method": "post", + "name": "some name", + "autocomplete": "on", + "rel": "external", + } + self._create_el_and_basic_asserts("form", "some text", properties=properties) + + def test_h1(self): + self._create_el_and_basic_asserts("h1", "some text") + + def test_h2(self): + self._create_el_and_basic_asserts("h2", "some text") + + def test_h3(self): + self._create_el_and_basic_asserts("h3", "some text") + + def test_h4(self): + self._create_el_and_basic_asserts("h4", "some text") + + def test_h5(self): + self._create_el_and_basic_asserts("h5", "some text") + + def test_h6(self): + self._create_el_and_basic_asserts("h6", "some text") + + def test_header(self): + self._create_el_and_basic_asserts("header", "some text") + + def test_hgroup(self): + self._create_el_and_basic_asserts("hgroup", "some text") + + def test_hr(self): + self._create_el_and_basic_asserts("hr") + + def test_i(self): + self._create_el_and_basic_asserts("i", "some text") + + def test_iframe(self): + # TODO: same comment about defining the right types + properties = { + "src": "http://localhost:8080/somefile.html", + "width": "250", + "height": "200", + } + self._create_el_and_basic_asserts("iframe", properties=properties) + + @upytest.skip( + "Flakey in worker.", + skip_when=RUNNING_IN_WORKER, + ) + async def test_img(self): + """ + This test, thanks to downloading an image from the internet, is flakey + when run in a worker. It's skipped when running in a worker. + """ + properties = { + "src": "https://picsum.photos/600/400", + "alt": "some image", + "width": 250, + "height": 200, + } + self._create_el_and_basic_asserts("img", properties=properties) + + def test_input(self): + # TODO: we need multiple input tests + properties = { + "type": "text", + "value": "some value", + "name": "some name", + "autofocus": True, + "pattern": "[A-Za-z]{3}", + "placeholder": "some placeholder", + "required": True, + "size": 20, + } + self._create_el_and_basic_asserts("input_", properties=properties) + + def test_ins(self): + self._create_el_and_basic_asserts( + "ins", "some text", properties={"cite": "http://example.com/"} + ) + + def test_kbd(self): + self._create_el_and_basic_asserts("kbd", "some text") + + def test_label(self): + self._create_el_and_basic_asserts("label", "some text") + + def test_legend(self): + self._create_el_and_basic_asserts("legend", "some text") + + def test_li(self): + self._create_el_and_basic_asserts("li", "some text") + + def test_link(self): + properties = { + "href": "http://localhost:8080/somefile.css", + "rel": "stylesheet", + "type": "text/css", + } + self._create_el_and_basic_asserts( + "link", + properties=properties, + additional_selector_rules="[href='http://localhost:8080/somefile.css']", + ) + + def test_main(self): + self._create_el_and_basic_asserts("main", "some text") + + def test_map(self): + self._create_el_and_basic_asserts( + "map_", "some text", properties={"name": "somemap"} + ) + + def test_mark(self): + self._create_el_and_basic_asserts("mark", "some text") + + def test_menu(self): + self._create_el_and_basic_asserts("menu", "some text") + + def test_meter(self): + properties = { + "value": 50, + "min": 0, + "max": 100, + "low": 30, + "high": 80, + "optimum": 50, + } + self._create_el_and_basic_asserts("meter", "some text", properties=properties) + + def test_nav(self): + self._create_el_and_basic_asserts("nav", "some text") + + def test_object(self): + properties = { + "data": "http://localhost:8080/somefile.swf", + "type": "application/x-shockwave-flash", + "width": "250", + "height": "200", + } + self._create_el_and_basic_asserts( + "object_", + properties=properties, + ) + + def test_ol(self): + self._create_el_and_basic_asserts("ol", "some text") + + def test_optgroup(self): + self._create_el_and_basic_asserts( + "optgroup", "some text", properties={"label": "some label"} + ) + + def test_option(self): + self._create_el_and_basic_asserts( + "option", "some text", properties={"value": "some value"} + ) + + def test_output(self): + self._create_el_and_basic_asserts("output", "some text") + + def test_p(self): + self._create_el_and_basic_asserts("p", "some text") + + def test_picture(self): + self._create_el_and_basic_asserts("picture", "some text") + + def test_pre(self): + self._create_el_and_basic_asserts("pre", "some text") + + def test_progress(self): + properties = { + "value": 50.0, + "max": 100.0, + } + self._create_el_and_basic_asserts( + "progress", "some text", properties=properties + ) + + def test_q(self): + self._create_el_and_basic_asserts( + "q", "some text", properties={"cite": "http://example.com/"} + ) + + def test_s(self): + self._create_el_and_basic_asserts("s", "some text") + + # def test_script(self): + # self._create_el_and_basic_asserts("script", "some text") + + def test_section(self): + self._create_el_and_basic_asserts("section", "some text") + + def test_select(self): + self._create_el_and_basic_asserts("select", "some text") + + def test_small(self): + self._create_el_and_basic_asserts("small", "some text") + + def test_source(self): + properties = { + "src": "http://localhost:8080/somefile.ogg", + "type": "audio/ogg", + } + self._create_el_and_basic_asserts( + "source", + properties=properties, + ) + + def test_span(self): + self._create_el_and_basic_asserts("span", "some text") + + def test_strong(self): + self._create_el_and_basic_asserts("strong", "some text") + + def test_style(self): + self._create_el_and_basic_asserts( + "style", + "body {background-color: red;}", + ) + + def test_sub(self): + self._create_el_and_basic_asserts("sub", "some text") + + def test_summary(self): + self._create_el_and_basic_asserts("summary", "some text") + + def test_sup(self): + self._create_el_and_basic_asserts("sup", "some text") + + def test_table(self): + self._create_el_and_basic_asserts("table", "some text") + + def test_tbody(self): + self._create_el_and_basic_asserts("tbody", "some text") + + def test_td(self): + self._create_el_and_basic_asserts("td", "some text") + + def test_template(self): + # We are not checking the content of template since it's sort of + # special element + self._create_el_and_basic_asserts("template") + + def test_textarea(self): + self._create_el_and_basic_asserts("textarea", "some text") + + def test_tfoot(self): + self._create_el_and_basic_asserts("tfoot", "some text") + + def test_th(self): + self._create_el_and_basic_asserts("th", "some text") + + def test_thead(self): + self._create_el_and_basic_asserts("thead", "some text") + + def test_time(self): + self._create_el_and_basic_asserts("time", "some text") + + def test_title(self): + self._create_el_and_basic_asserts("title", "some text") + + def test_tr(self): + self._create_el_and_basic_asserts("tr", "some text") + + def test_track(self): + properties = { + "src": "http://localhost:8080/somefile.vtt", + "kind": "subtitles", + "srclang": "en", + "label": "English", + } + self._create_el_and_basic_asserts( + "track", + properties=properties, + ) + + def test_u(self): + self._create_el_and_basic_asserts("u", "some text") + + def test_ul(self): + self._create_el_and_basic_asserts("ul", "some text") + + def test_var(self): + self._create_el_and_basic_asserts("var", "some text") + + def test_video(self): + properties = { + "src": "http://localhost:8080/somefile.ogg", + "controls": True, + "width": 250, + "height": 200, + } + self._create_el_and_basic_asserts("video", properties=properties) + + def test_append_py_element(self): + div_text_content = "Luke, I am your father" + p_text_content = "noooooooooo!" + # Let's create the element + el = web.div(div_text_content) + child = web.p(p_text_content) + el.append(child) + self.container.append(el) + # Check the expected content exists. + result = self.container.find("div") + assert len(result) == 1 + el = result[0] + tag = el.tagName + assert tag == "DIV", tag + assert el.textContent == f"{div_text_content}{p_text_content}" + assert len(el.children) == 1, "There should be only 1 child" + assert el.children[0].tagName == "P" + assert ( + el.children[0].parentNode.textContent + == f"{div_text_content}{p_text_content}" + ) + assert el.children[0].textContent == p_text_content + + def test_append_proxy_element(self): + div_text_content = "Luke, I am your father" + p_text_content = "noooooooooo!" + # Let's create the element + el = web.div(div_text_content) + child = document.createElement("P") + child.textContent = p_text_content + el.append(child) + self.container.append(el) + # Check the expected content exists. + result = self.container.find("div") + assert len(result) == 1 + el = result[0] + tag = el.tagName + assert tag == "DIV", tag + assert el.textContent == f"{div_text_content}{p_text_content}", el.textContent + assert len(el.children) == 1, "There should be only 1 child" + assert el.children[0].tagName == "P" + assert ( + el.children[0].parentNode.textContent + == f"{div_text_content}{p_text_content}" + ) + assert el.children[0].textContent == p_text_content + + def test_append_py_elementcollection(self): + div_text_content = "Luke, I am your father" + p_text_content = "noooooooooo!" + p2_text_content = "not me!" + # Let's create the elements + el = web.div(div_text_content) + child1 = web.p(p_text_content) + child2 = web.p(p2_text_content, id="child2") + collection = web.ElementCollection([child1, child2]) + el.append(collection) + self.container.append(el) + # Check the expected content exists. + result = self.container.find("div") + assert len(result) == 1 + el = result[0] + tag = el.tagName + assert tag == "DIV", tag + parent_full_content = f"{div_text_content}{p_text_content}{p2_text_content}" + assert el.textContent == parent_full_content + assert len(el.children) == 2, "There should be only 2 children" + assert el.children[0].tagName == "P" + assert el.children[0].parentNode.textContent == parent_full_content + assert el.children[0].textContent == p_text_content + assert el.children[1].tagName == "P" + assert el.children[1].id == "child2" + assert el.children[1].parentNode.textContent == parent_full_content + assert el.children[1].textContent == p2_text_content + + def test_append_js_element_nodelist(self): + div_text_content = "Luke, I am your father" + p_text_content = "noooooooooo!" + p2_text_content = "not me!" + # Let's create the elements + el = web.div(div_text_content) + child1 = web.p(p_text_content) + child2 = web.p(p2_text_content, id="child2") + self.container.append(child1) + self.container.append(child2) + nodes = self.container._dom_element.querySelectorAll("p") + el.append(nodes) + self.container.append(el) + # Check the expected content exists. + result = self.container.find("div") + assert len(result) == 1 + el = result[0] + tag = el.tagName + assert tag == "DIV", tag + parent_full_content = f"{div_text_content}{p_text_content}{p2_text_content}" + assert el.textContent == parent_full_content, el.innerHTML + assert len(el.children) == 2, "There should be only 2 children" + assert el.children[0].tagName == "P" + assert el.children[0].parentNode.textContent == parent_full_content + assert el.children[0].textContent == p_text_content + assert el.children[1].tagName == "P" + assert el.children[1].id == "child2" + assert el.children[1].parentNode.textContent == parent_full_content + assert el.children[1].textContent == p2_text_content diff --git a/core/tests/python/tests/test_websocket.py b/core/tests/python/tests/test_websocket.py new file mode 100644 index 00000000000..8561eab1b1a --- /dev/null +++ b/core/tests/python/tests/test_websocket.py @@ -0,0 +1,102 @@ +""" +Exercise the pyscript.Websocket class. +""" + +import asyncio +import upytest + +from pyscript import WebSocket + + +@upytest.skip("Websocket tests are disabled.") +async def test_websocket_with_attributes(): + """ + Event handlers assigned via object attributes. + + The Websocket class should be able to connect to a websocket server and + send and receive messages. + + Use of echo.websocket.org means: + + 1) When connecting it responds with a "Request served by" message. + 2) When sending a message it echos it back. + """ + connected_flag = False + closed_flag = False + messages = [] + ready_to_test = asyncio.Event() + + def on_open(event): + nonlocal connected_flag + connected_flag = True + ws.send("Hello, world!") # A message to echo. + + def on_message(event): + messages.append(event.data) + if len(messages) == 2: # We're done. + ws.close() + + def on_close(event): + nonlocal closed_flag + closed_flag = True + ready_to_test.set() # Finished! + + ws = WebSocket(url="wss://echo.websocket.org") + ws.onopen = on_open + ws.onmessage = on_message + ws.onclose = on_close + # Wait for everything to be finished. + await ready_to_test.wait() + assert connected_flag is True + assert len(messages) == 2 + assert "request served by" in messages[0].lower() + assert messages[1] == "Hello, world!" + assert closed_flag is True + + +@upytest.skip("Websocket tests are disabled.") +async def test_websocket_with_init(): + """ + Event handlers assigned via __init__ arguments. + + The Websocket class should be able to connect to a websocket server and + send and receive messages. + + Use of echo.websocket.org means: + + 1) When connecting it responds with a "Request served by" message. + 2) When sending a message it echos it back. + """ + connected_flag = False + closed_flag = False + messages = [] + ready_to_test = asyncio.Event() + + def on_open(event): + nonlocal connected_flag + connected_flag = True + ws.send("Hello, world!") # A message to echo. + + def on_message(event): + messages.append(event.data) + if len(messages) == 2: # We're done. + ws.close() + + def on_close(event): + nonlocal closed_flag + closed_flag = True + ready_to_test.set() # Finished! + + ws = WebSocket( + url="wss://echo.websocket.org", + onopen=on_open, + onmessage=on_message, + onclose=on_close, + ) + # Wait for everything to be finished. + await ready_to_test.wait() + assert connected_flag is True + assert len(messages) == 2 + assert "request served by" in messages[0].lower() + assert messages[1] == "Hello, world!" + assert closed_flag is True diff --git a/core/tests/python/tests/test_window.py b/core/tests/python/tests/test_window.py new file mode 100644 index 00000000000..6600c36fb31 --- /dev/null +++ b/core/tests/python/tests/test_window.py @@ -0,0 +1,25 @@ +""" +Ensure the pyscript.window object refers to the main thread's window object. +""" + +import upytest +from pyscript import RUNNING_IN_WORKER, window + + +@upytest.skip("Main thread only.", skip_when=RUNNING_IN_WORKER) +def test_window_in_main_thread(): + """ + The window object should refer to the main thread's window object. + """ + # The window will have a document. + assert window.document + + +@upytest.skip("Worker only.", skip_when=not RUNNING_IN_WORKER) +def test_window_in_worker(): + """ + The window object should refer to the worker's self object, even though + this code is running in a web worker. + """ + # The window will have a document. + assert window.document diff --git a/pyscript.core/tsconfig.json b/core/tsconfig.json similarity index 100% rename from pyscript.core/tsconfig.json rename to core/tsconfig.json diff --git a/core/types/3rd-party/codemirror.d.ts b/core/types/3rd-party/codemirror.d.ts new file mode 100644 index 00000000000..2a1a953a9a0 --- /dev/null +++ b/core/types/3rd-party/codemirror.d.ts @@ -0,0 +1 @@ +export * from "codemirror"; diff --git a/core/types/3rd-party/codemirror_commands.d.ts b/core/types/3rd-party/codemirror_commands.d.ts new file mode 100644 index 00000000000..1862cebc7bb --- /dev/null +++ b/core/types/3rd-party/codemirror_commands.d.ts @@ -0,0 +1 @@ +export * from "@codemirror/commands"; diff --git a/core/types/3rd-party/codemirror_lang-python.d.ts b/core/types/3rd-party/codemirror_lang-python.d.ts new file mode 100644 index 00000000000..76b718d3b66 --- /dev/null +++ b/core/types/3rd-party/codemirror_lang-python.d.ts @@ -0,0 +1 @@ +export * from "@codemirror/lang-python"; diff --git a/core/types/3rd-party/codemirror_language.d.ts b/core/types/3rd-party/codemirror_language.d.ts new file mode 100644 index 00000000000..632a9f72919 --- /dev/null +++ b/core/types/3rd-party/codemirror_language.d.ts @@ -0,0 +1 @@ +export * from "@codemirror/language"; diff --git a/core/types/3rd-party/codemirror_state.d.ts b/core/types/3rd-party/codemirror_state.d.ts new file mode 100644 index 00000000000..9dd5c97d8a1 --- /dev/null +++ b/core/types/3rd-party/codemirror_state.d.ts @@ -0,0 +1 @@ +export * from "@codemirror/state"; diff --git a/core/types/3rd-party/codemirror_view.d.ts b/core/types/3rd-party/codemirror_view.d.ts new file mode 100644 index 00000000000..3669d051e72 --- /dev/null +++ b/core/types/3rd-party/codemirror_view.d.ts @@ -0,0 +1 @@ +export * from "@codemirror/view"; diff --git a/pyscript.core/types/3rd-party/toml.d.ts b/core/types/3rd-party/toml.d.ts similarity index 100% rename from pyscript.core/types/3rd-party/toml.d.ts rename to core/types/3rd-party/toml.d.ts diff --git a/pyscript.core/types/3rd-party/xterm-readline.d.ts b/core/types/3rd-party/xterm-readline.d.ts similarity index 95% rename from pyscript.core/types/3rd-party/xterm-readline.d.ts rename to core/types/3rd-party/xterm-readline.d.ts index 99a16d83239..6bb8c3bfe4b 100644 --- a/pyscript.core/types/3rd-party/xterm-readline.d.ts +++ b/core/types/3rd-party/xterm-readline.d.ts @@ -1,6 +1,6 @@ -declare var b: any; -declare var I: boolean; -declare namespace r { +declare var v: any; +declare var k: boolean; +declare namespace i { export let __esModule: boolean; export { Readline }; } @@ -57,7 +57,7 @@ declare class Readline { highlighter: any; history: any; promptSize: any; - layout: p; + layout: c; buffer(): string; shouldHighlight(): boolean; clearScreen(): void; @@ -124,15 +124,15 @@ declare class Readline { readPaste(t: any): void; readKey(t: any): void; } -declare class p { +declare class c { constructor(t: any); promptSize: any; - cursor: c; - end: c; + cursor: u; + end: u; } -declare class c { +declare class u { constructor(t: any, e: any); row: any; col: any; } -export { b as Readline, I as __esModule, r as default }; +export { v as Readline, k as __esModule, i as default }; diff --git a/core/types/3rd-party/xterm.d.ts b/core/types/3rd-party/xterm.d.ts new file mode 100644 index 00000000000..697d9adc5f5 --- /dev/null +++ b/core/types/3rd-party/xterm.d.ts @@ -0,0 +1,4 @@ +declare var D: any; +declare var R: any; +declare var L: {}; +export { D as Terminal, R as __esModule, L as default }; diff --git a/pyscript.core/types/3rd-party/xterm_addon-fit.d.ts b/core/types/3rd-party/xterm_addon-fit.d.ts similarity index 100% rename from pyscript.core/types/3rd-party/xterm_addon-fit.d.ts rename to core/types/3rd-party/xterm_addon-fit.d.ts diff --git a/core/types/3rd-party/xterm_addon-web-links.d.ts b/core/types/3rd-party/xterm_addon-web-links.d.ts new file mode 100644 index 00000000000..5d1e051502b --- /dev/null +++ b/core/types/3rd-party/xterm_addon-web-links.d.ts @@ -0,0 +1,4 @@ +declare var r: any; +declare var n: any; +declare var t: {}; +export { r as WebLinksAddon, n as __esModule, t as default }; diff --git a/pyscript.core/types/all-done.d.ts b/core/types/all-done.d.ts similarity index 100% rename from pyscript.core/types/all-done.d.ts rename to core/types/all-done.d.ts diff --git a/core/types/config.d.ts b/core/types/config.d.ts new file mode 100644 index 00000000000..bb809895a68 --- /dev/null +++ b/core/types/config.d.ts @@ -0,0 +1,7 @@ +export function configDetails(config: string, type: string | null): { + json: boolean; + toml: boolean; + text: string; +}; +export const configs: Map; +export function relative_url(url: any, base?: string): string; diff --git a/core/types/core.d.ts b/core/types/core.d.ts new file mode 100644 index 00000000000..2f075d559fd --- /dev/null +++ b/core/types/core.d.ts @@ -0,0 +1,67 @@ +export function donkey(options: any): Promise<{ + process: (code: any) => Promise; + execute: (code: any) => Promise; + evaluate: (code: any) => Promise; + clear: () => Promise; + reset: () => Promise; + kill: () => void; +}>; +export function offline_interpreter(config: any): string; +import codemirror from "./plugins/codemirror.js"; +import { stdlib } from "./stdlib.js"; +import { optional } from "./stdlib.js"; +import { inputFailure } from "./hooks.js"; +import TYPES from "./types.js"; +import { relative_url } from "./config.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 {Promise} + */ +declare function exportedPyWorker(file: string, options?: { + config?: string | object; + async?: boolean; +}): Promise; +/** + * 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 {Promise} + */ +declare function exportedMPWorker(file: string, options?: { + config?: string | object; + async?: boolean; +}): Promise; +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: any; +export { codemirror, stdlib, optional, inputFailure, TYPES, relative_url, exportedPyWorker as PyWorker, exportedMPWorker as MPWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; diff --git a/pyscript.core/types/exceptions.d.ts b/core/types/exceptions.d.ts similarity index 82% rename from pyscript.core/types/exceptions.d.ts rename to core/types/exceptions.d.ts index f13f1fbfa77..fc2db6340b5 100644 --- a/pyscript.core/types/exceptions.d.ts +++ b/core/types/exceptions.d.ts @@ -53,19 +53,4 @@ export class InstallError extends UserError { /** * 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; -}; +export type ErrorCodes = "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"; diff --git a/pyscript.core/types/fetch.d.ts b/core/types/fetch.d.ts similarity index 86% rename from pyscript.core/types/fetch.d.ts rename to core/types/fetch.d.ts index 83b6bed2bd1..fc3849ddeee 100644 --- a/pyscript.core/types/fetch.d.ts +++ b/core/types/fetch.d.ts @@ -8,5 +8,4 @@ * @returns {Promise} */ export function robustFetch(url: string, options?: Request): Promise; -export { getText }; -import { getText } from "polyscript/exports"; +export function getText(response: Response): Promise; diff --git a/core/types/fs.d.ts b/core/types/fs.d.ts new file mode 100644 index 00000000000..3283c5d4009 --- /dev/null +++ b/core/types/fs.d.ts @@ -0,0 +1,8 @@ +export const NAMESPACE: "@pyscript.fs"; +export const ERROR: "storage permissions not granted"; +export const idb: any; +export function getFileSystemDirectoryHandle(options: { + id?: string; + mode?: "read" | "readwrite"; + hint?: "desktop" | "documents" | "downloads" | "music" | "pictures" | "videos"; +}): Promise; diff --git a/pyscript.core/types/hooks.d.ts b/core/types/hooks.d.ts similarity index 76% rename from pyscript.core/types/hooks.d.ts rename to core/types/hooks.d.ts index e79ff791852..cb52f57a64e 100644 --- a/pyscript.core/types/hooks.d.ts +++ b/core/types/hooks.d.ts @@ -1,7 +1,8 @@ export function main(name: any): any; export function worker(name: any): any; -export function codeFor(branch: any): {}; +export function codeFor(branch: any, type: any): {}; export function createFunction(self: any, name: any): any; +export const inputFailure: "\n import builtins\n def input(prompt=\"\"):\n raise Exception(\"\\n \".join([\n \"input() doesn't work when PyScript runs in the main thread.\",\n \"Consider using the worker attribute: https://pyscript.github.io/docs/2023.11.2/user-guide/workers/\"\n ]))\n\n builtins.input = input\n del builtins\n del input\n"; export namespace hooks { namespace main { let onWorker: Set; diff --git a/pyscript.core/types/plugins-helper.d.ts b/core/types/plugins-helper.d.ts similarity index 100% rename from pyscript.core/types/plugins-helper.d.ts rename to core/types/plugins-helper.d.ts diff --git a/pyscript.core/types/plugins.d.ts b/core/types/plugins.d.ts similarity index 63% rename from pyscript.core/types/plugins.d.ts rename to core/types/plugins.d.ts index d50636137e1..00dd48e665a 100644 --- a/pyscript.core/types/plugins.d.ts +++ b/core/types/plugins.d.ts @@ -1,7 +1,10 @@ declare const _default: { + codemirror: () => Promise; "deprecations-manager": () => Promise; + donkey: () => Promise; error: () => Promise; "py-editor": () => Promise; + "py-game": () => Promise; "py-terminal": () => Promise; }; export default _default; diff --git a/core/types/plugins/codemirror.d.ts b/core/types/plugins/codemirror.d.ts new file mode 100644 index 00000000000..93424d77d2c --- /dev/null +++ b/core/types/plugins/codemirror.d.ts @@ -0,0 +1,9 @@ +declare namespace _default { + const core: Promise; + const state: Promise; + const python: Promise; + const language: Promise; + const view: Promise; + const commands: Promise; +} +export default _default; diff --git a/pyscript.core/types/plugins/deprecations-manager.d.ts b/core/types/plugins/deprecations-manager.d.ts similarity index 100% rename from pyscript.core/types/plugins/deprecations-manager.d.ts rename to core/types/plugins/deprecations-manager.d.ts diff --git a/core/types/plugins/donkey.d.ts b/core/types/plugins/donkey.d.ts new file mode 100644 index 00000000000..f328f997dd4 --- /dev/null +++ b/core/types/plugins/donkey.d.ts @@ -0,0 +1,9 @@ +declare function _default(options?: {}): Promise<{ + process: (code: any) => Promise; + execute: (code: any) => Promise; + evaluate: (code: any) => Promise; + clear: () => Promise; + reset: () => Promise; + kill: () => void; +}>; +export default _default; diff --git a/pyscript.core/types/plugins/error.d.ts b/core/types/plugins/error.d.ts similarity index 81% rename from pyscript.core/types/plugins/error.d.ts rename to core/types/plugins/error.d.ts index bf9a6788ab5..40bdfd0dc2d 100644 --- a/pyscript.core/types/plugins/error.d.ts +++ b/core/types/plugins/error.d.ts @@ -1,3 +1,4 @@ +export function notOnDOM(): void; /** * Add a banner to the top of the page, notifying the user of an error * @param {string} message diff --git a/pyscript.core/types/plugins/py-editor.d.ts b/core/types/plugins/py-editor.d.ts similarity index 100% rename from pyscript.core/types/plugins/py-editor.d.ts rename to core/types/plugins/py-editor.d.ts diff --git a/core/types/plugins/py-game.d.ts b/core/types/plugins/py-game.d.ts new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/core/types/plugins/py-game.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/core/types/plugins/py-terminal.d.ts b/core/types/plugins/py-terminal.d.ts new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/core/types/plugins/py-terminal.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/core/types/plugins/py-terminal/mpy.d.ts b/core/types/plugins/py-terminal/mpy.d.ts new file mode 100644 index 00000000000..a45471b4e48 --- /dev/null +++ b/core/types/plugins/py-terminal/mpy.d.ts @@ -0,0 +1,2 @@ +declare function _default(element: any): Promise; +export default _default; diff --git a/core/types/plugins/py-terminal/py.d.ts b/core/types/plugins/py-terminal/py.d.ts new file mode 100644 index 00000000000..a45471b4e48 --- /dev/null +++ b/core/types/plugins/py-terminal/py.d.ts @@ -0,0 +1,2 @@ +declare function _default(element: any): Promise; +export default _default; diff --git a/core/types/stdlib.d.ts b/core/types/stdlib.d.ts new file mode 100644 index 00000000000..c42c11acfd6 --- /dev/null +++ b/core/types/stdlib.d.ts @@ -0,0 +1,2 @@ +export const stdlib: string; +export const optional: string; diff --git a/core/types/stdlib/pyscript.d.ts b/core/types/stdlib/pyscript.d.ts new file mode 100644 index 00000000000..8c6c476d5a8 --- /dev/null +++ b/core/types/stdlib/pyscript.d.ts @@ -0,0 +1,19 @@ +declare namespace _default { + let pyscript: { + "__init__.py": string; + "display.py": string; + "events.py": string; + "fetch.py": string; + "ffi.py": string; + "flatted.py": string; + "fs.py": string; + "magic_js.py": string; + "media.py": string; + "storage.py": string; + "util.py": string; + "web.py": string; + "websocket.py": string; + "workers.py": string; + }; +} +export default _default; diff --git a/core/types/sync.d.ts b/core/types/sync.d.ts new file mode 100644 index 00000000000..484122d3782 --- /dev/null +++ b/core/types/sync.d.ts @@ -0,0 +1,20 @@ +declare namespace _default { + function is_pyterminal(): boolean; + /** + * '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; + /** + * Ask a user action via dialog and returns the directory handler once granted. + * @param {string} uid + * @param {{id?:string, mode?:"read"|"readwrite", hint?:"desktop"|"documents"|"downloads"|"music"|"pictures"|"videos"}} options + * @returns {boolean} + */ + function storeFSHandler(uid: string, options?: { + id?: string; + mode?: "read" | "readwrite"; + hint?: "desktop" | "documents" | "downloads" | "music" | "pictures" | "videos"; + }): boolean; +} +export default _default; diff --git a/pyscript.core/types/types.d.ts b/core/types/types.d.ts similarity index 100% rename from pyscript.core/types/types.d.ts rename to core/types/types.d.ts diff --git a/core/types/zero-redirect.d.ts b/core/types/zero-redirect.d.ts new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/core/types/zero-redirect.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/README.md b/public/README.md new file mode 100644 index 00000000000..2a384d12071 --- /dev/null +++ b/public/README.md @@ -0,0 +1,7 @@ +# Public + +The `index.html` file found in this directory is used by the GitHub Actions +(defined in this repo's `.github/workflows/` directory) as a template for the +static page used to collate all the information relating to a release of +PyScript. Such static pages (and related release assets) eventually end up on +the https://pyscript.net/ domain. diff --git a/public/index.html b/public/index.html index 90f67f082d5..3ea49dd74e3 100644 --- a/public/index.html +++ b/public/index.html @@ -4,48 +4,151 @@ - - PyScript + PyScript Release: _VERSION_ + +
-

<py-script>

+ +

Files

- + + -

Example

-
+            

+ Example + + + + + +

+
 <!DOCTYPE html>
 <html lang="en">
     <head>
-    <meta charset="utf-8" />
-    <meta name="viewport" content="width=device-width,initial-scale=1" />
-    <title>PyScript Hello World</title>
-    <link rel="stylesheet" href="_PATH_core.css" />
-    <script type="module" src="_PATH_core.js"></script>
+        <meta charset="utf-8" />
+        <meta name="viewport" content="width=device-width,initial-scale=1" />
+        <title>PyScript _VERSION_</title>
+        <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()
-display(now.strftime("%m/%d/%Y, %H:%M:%S"))
-    </py-script>
+        <h1>Hello world!</h1>
+        <p>These are the Python interpreters in PyScript _VERSION_:</p>
+        <script type="py">
+            # Pyodide
+            from pyscript import display
+            import sys
+            display(sys.version)
+        </script>
+        <script type="mpy">
+            # MicroPython
+            from pyscript import display
+            import sys
+            display(sys.version)
+        </script>
     </body>
 </html>
diff --git a/pyproject.toml b/pyproject.toml index f56bd121eba..a3a7cbc434d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,9 @@ -[build-system] -requires = ["setuptools>=61.2"] -build-backend = "setuptools.build_meta" - -[project] -dynamic = ["version"] - [tool.codespell] ignore-words-list = "afterall" skip = "*.js,*.json" -[tool.setuptools] -include-package-data = false +[tool.ruff] +line-length = 114 +lint.select = ["C4", "C90", "E", "EM", "F", "PIE", "PYI", "PLC", "Q", "RET", "W"] +lint.ignore = ["E402", "E722", "E731", "E741", "F401", "F704", "F811", "F821"] +lint.mccabe.max-complexity = 27 diff --git a/pyscript.core/.eslintrc.cjs b/pyscript.core/.eslintrc.cjs deleted file mode 100644 index ecdde66299f..00000000000 --- a/pyscript.core/.eslintrc.cjs +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - }, - extends: "eslint:recommended", - overrides: [ - { - env: { - node: true, - }, - files: [".eslintrc.{js,cjs}"], - parserOptions: { - sourceType: "script", - }, - }, - ], - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - }, - ignorePatterns: ["3rd-party"], - rules: { - "no-implicit-globals": ["error"], - }, -}; diff --git a/pyscript.core/.npmignore b/pyscript.core/.npmignore deleted file mode 100644 index cd1f68af59c..00000000000 --- a/pyscript.core/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -.eslintrc.cjs -.pytest_cache/ -node_modules/ -rollup/ -test/ -tests/ -src/stdlib/_pyscript -src/stdlib/pyscript.py -package-lock.json -tsconfig.json diff --git a/pyscript.core/README.md b/pyscript.core/README.md deleted file mode 100644 index 75ef6af2a79..00000000000 --- a/pyscript.core/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# @pyscript/core - -We have moved and renamed previous _core_ module as [polyscript](https://github.com/pyscript/polyscript/#readme), which is the base module used in here to build up _PyScript Next_, now hosted in this folder. - -## Documentation - -Please read [core documentation](./docs/README.md) to know more about this project. - -## Development - -Clone this repository then run `npm install` within its folder. - -Use `npm run build` to create all artifacts and _dist_ files. - -Use `npm run server` to test locally, via the `http://localhost:8080/test/` url, smoke tests or to test manually anything you'd like to check. - -### Artifacts - -There are two main artifacts in this project: - -- **stdlib** and its content, where `src/stdlib/pyscript.js` exposes as object literal all the _Python_ content within the folder (recursively) -- **plugins** and its content, where `src/plugins.js` exposes all available _dynamic imports_, able to instrument the bundler to create files a part within the _dist/_ folder, so that by default _core_ remains as small as possible - -Accordingly, whenever a file contains this warning at its first line, please do not change such file directly before submitting a merge request, as that file will be overwritten at the next `npm run build` command, either here or in _CI_: - -```js -// ⚠️ This file is an artifact: DO NOT MODIFY -``` - -### Running tests - -Before running the tests, we need to create a tests environment first. To do so run the following command from the root folder of the project: - -``` -make setup -``` - -This will create a tests environment [in the root of the project, named `./env`]and install all the dependencies needed to run the tests. - -After the command has completed and the tests environment has been created, you can run the **integration tests** with -the following command: - -``` -make test-integration -``` - -## `pyscript` python package - -The `pyscript` package available in _Python_ lives in the folder `src/stdlib/pyscript/`. - -All _Python_ files will be embedded automatically whenever `npm run build` happens and reflected into the `src/stdlib/pyscript.js` file. - -It is _core_ responsibility to ensure those files will be available through the Filesystem in either the _main_ thread, or any _worker_. - -## JS plugins - -While community or third party plugins don't need to be part of this repository and can be added just importing `@pyscript/core` as module, there are a few plugins that we would like to make available by default and these are considered _core plugins_. - -To add a _core plugin_ to this project you can define your plugin entry-point and name in the `src/plugins` folder (see the `error.js` example) and create, if necessary, a folder with the same name where extra files or dependencies can be added. - -The _build_ command will bring plugins by name as artifact so that the bundler can create ad-hoc files within the `dist/` folder. diff --git a/pyscript.core/docs/README.md b/pyscript.core/docs/README.md deleted file mode 100644 index ae3bcde0e26..00000000000 --- a/pyscript.core/docs/README.md +++ /dev/null @@ -1,271 +0,0 @@ -# PyScript Next - -A summary of @pyscript/core features - -### Getting started - -Differently from [pyscript classic](https://github.com/pyscript/pyscript), where "*classic*" is the disambiguation name we use to describe the two versions of the project, `@pyscript/core` is an *ECMAScript Module* with the follow benefits: - - * it doesn't block the page like a regular script, without a `deferred` attribute, would - * it allows modularity in the future - * it bootstraps itself once but it allows exports via the module - -Accordingly, this is the bare minimum required output to bootstrap *PyScript Next* in your page via a CDN: - -```html - - - - - - - -``` - -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/package.json b/pyscript.core/package.json deleted file mode 100644 index 031defba77a..00000000000 --- a/pyscript.core/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "@pyscript/core", - "version": "0.3.18", - "type": "module", - "description": "PyScript", - "module": "./index.js", - "unpkg": "./index.js", - "jsdelivr": "./jsdelivr.js", - "browser": "./index.js", - "main": "./index.js", - "exports": { - ".": { - "types": "./types/core.d.ts", - "import": "./src/core.js" - }, - "./css": { - "import": "./dist/core.css" - }, - "./package.json": "./package.json" - }, - "scripts": { - "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", - "clean:3rd-party": "rm src/3rd-party/*.js && rm src/3rd-party/*.css", - "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 cat $js | brotli > ._; echo -e \"\\033[2m$js:\\033[0m $(du -h --apparent-size ._ | sed -e 's/[[:space:]]*._//')\"; rm ._; done", - "ts": "rm -rf types && tsc -p .", - "zip": "zip -r dist.zip ./dist" - }, - "keywords": [ - "pyscript", - "core" - ], - "author": "Anaconda Inc.", - "license": "APACHE-2.0", - "dependencies": { - "@ungap/with-resolvers": "^0.1.0", - "basic-devtools": "^0.1.6", - "polyscript": "^0.6.13", - "sticky-module": "^0.1.1", - "to-json-callback": "^0.1.1", - "type-checked-collections": "^0.1.7" - }, - "devDependencies": { - "@codemirror/commands": "^6.3.3", - "@codemirror/lang-python": "^6.1.3", - "@codemirror/language": "^6.10.0", - "@codemirror/state": "^6.4.0", - "@codemirror/view": "^6.23.0", - "@playwright/test": "^1.41.1", - "@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", - "@xterm/addon-fit": "^0.9.0-beta.1", - "chokidar": "^3.5.3", - "codemirror": "^6.0.1", - "eslint": "^8.56.0", - "rollup": "^4.9.6", - "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-string": "^3.0.0", - "static-handler": "^0.4.3", - "typescript": "^5.3.3", - "xterm": "^5.3.0", - "xterm-readline": "^1.1.1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/pyscript/pyscript.git" - }, - "bugs": { - "url": "https://github.com/pyscript/pyscript/issues" - }, - "homepage": "https://github.com/pyscript/pyscript#readme" -} diff --git a/pyscript.core/rollup/stdlib.cjs b/pyscript.core/rollup/stdlib.cjs deleted file mode 100644 index 0c23583ec92..00000000000 --- a/pyscript.core/rollup/stdlib.cjs +++ /dev/null @@ -1,29 +0,0 @@ -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/plugins/py-editor.js b/pyscript.core/src/plugins/py-editor.js deleted file mode 100644 index a5595d36bfb..00000000000 --- a/pyscript.core/src/plugins/py-editor.js +++ /dev/null @@ -1,229 +0,0 @@ -// PyScript py-editor plugin -import { Hook, XWorker, dedent } from "polyscript/exports"; -import { TYPES } from "../core.js"; - -const RUN_BUTTON = ``; - -let id = 0; -const getID = (type) => `${type}-editor-${id++}`; - -const envs = new Map(); - -const hooks = { - worker: { - // works on both Pyodide and MicroPython - onReady: ({ runAsync, io }, { sync }) => { - io.stdout = (line) => sync.write(line); - io.stderr = (line) => sync.writeErr(line); - sync.revoke(); - sync.runAsync = runAsync; - }, - }, -}; - -async function execute({ currentTarget }) { - const { env, pySrc, outDiv } = this; - - currentTarget.disabled = true; - outDiv.innerHTML = ""; - - if (!envs.has(env)) { - const srcLink = URL.createObjectURL(new Blob([""])); - const xworker = XWorker.call(new Hook(null, hooks), srcLink, { - type: this.interpreter, - }); - - const { sync } = xworker; - const { promise, resolve } = Promise.withResolvers(); - envs.set(env, promise); - sync.revoke = () => { - URL.revokeObjectURL(srcLink); - resolve(xworker); - }; - } - - // wait for the env then set the target div - // before executing the current code - envs.get(env).then((xworker) => { - xworker.onerror = ({ error }) => { - outDiv.innerHTML += `${ - error.message || error - }\n`; - console.error(error); - }; - - const enable = () => { - currentTarget.disabled = false; - }; - const { sync } = xworker; - sync.write = (str) => { - outDiv.innerText += `${str}\n`; - }; - sync.writeErr = (str) => { - outDiv.innerHTML += `${str}\n`; - }; - sync.runAsync(pySrc).then(enable, enable); - }); -} - -const makeRunButton = (listener, type) => { - const runButton = document.createElement("button"); - runButton.className = `absolute ${type}-editor-run-button`; - runButton.innerHTML = RUN_BUTTON; - runButton.setAttribute("aria-label", "Python Script Run Button"); - runButton.addEventListener("click", listener); - return runButton; -}; - -const makeEditorDiv = (listener, type) => { - const editorDiv = document.createElement("div"); - editorDiv.className = `${type}-editor-input`; - editorDiv.setAttribute("aria-label", "Python Script Area"); - - const runButton = makeRunButton(listener, type); - const editorShadowContainer = document.createElement("div"); - - // avoid outer elements intercepting key events (reveal as example) - editorShadowContainer.addEventListener("keydown", (event) => { - event.stopPropagation(); - }); - - editorDiv.append(runButton, editorShadowContainer); - - return editorDiv; -}; - -const makeOutDiv = (type) => { - const outDiv = document.createElement("div"); - outDiv.className = `${type}-editor-output`; - outDiv.id = `${getID(type)}-output`; - return outDiv; -}; - -const makeBoxDiv = (listener, type) => { - const boxDiv = document.createElement("div"); - boxDiv.className = `${type}-editor-box`; - - const editorDiv = makeEditorDiv(listener, type); - const outDiv = makeOutDiv(type); - boxDiv.append(editorDiv, outDiv); - - return [boxDiv, outDiv]; -}; - -const init = async (script, type, interpreter) => { - const [ - { basicSetup, EditorView }, - { Compartment }, - { python }, - { indentUnit }, - { keymap }, - { defaultKeymap }, - ] = await Promise.all([ - // TODO: find a way to actually produce these bundles locally - import(/* webpackIgnore: true */ "../3rd-party/codemirror.js"), - import(/* webpackIgnore: true */ "../3rd-party/codemirror_state.js"), - import( - /* webpackIgnore: true */ "../3rd-party/codemirror_lang-python.js" - ), - import(/* webpackIgnore: true */ "../3rd-party/codemirror_language.js"), - import(/* webpackIgnore: true */ "../3rd-party/codemirror_view.js"), - import(/* webpackIgnore: true */ "../3rd-party/codemirror_commands.js"), - ]); - - const selector = script.getAttribute("target"); - - let target; - if (selector) { - target = - document.getElementById(selector) || - document.querySelector(selector); - if (!target) throw new Error(`Unknown target ${selector}`); - } else { - target = document.createElement(`${type}-editor`); - target.style.display = "block"; - script.after(target); - } - - if (!target.id) target.id = getID(type); - if (!target.hasAttribute("exec-id")) target.setAttribute("exec-id", 0); - if (!target.hasAttribute("root")) target.setAttribute("root", target.id); - - const env = `${interpreter}-${script.getAttribute("env") || getID(type)}`; - const context = { - interpreter, - env, - get pySrc() { - return editor.state.doc.toString(); - }, - get outDiv() { - return outDiv; - }, - }; - - // @see https://github.com/JeffersGlass/mkdocs-pyscript/blob/main/mkdocs_pyscript/js/makeblocks.js - const listener = execute.bind(context); - const [boxDiv, outDiv] = makeBoxDiv(listener, type); - boxDiv.dataset.env = script.hasAttribute("env") ? env : interpreter; - - const inputChild = boxDiv.querySelector(`.${type}-editor-input > div`); - const parent = inputChild.attachShadow({ mode: "open" }); - // avoid inheriting styles from the outer component - parent.innerHTML = ``; - - target.appendChild(boxDiv); - - const doc = dedent(script.textContent).trim(); - - // preserve user indentation, if any - const indentation = /^(\s+)/m.test(doc) ? RegExp.$1 : " "; - - const editor = new EditorView({ - extensions: [ - indentUnit.of(indentation), - new Compartment().of(python()), - keymap.of([ - ...defaultKeymap, - { key: "Ctrl-Enter", run: listener, preventDefault: true }, - { key: "Cmd-Enter", run: listener, preventDefault: true }, - { key: "Shift-Enter", run: listener, preventDefault: true }, - ]), - basicSetup, - ], - parent, - doc, - }); - - editor.focus(); -}; - -// avoid too greedy MutationObserver operations at distance -let timeout = 0; - -// reset interval value then check for new scripts -const resetTimeout = () => { - timeout = 0; - pyEditor(); -}; - -// triggered both ASAP on the living DOM and via MutationObserver later -const pyEditor = async () => { - if (timeout) return; - timeout = setTimeout(resetTimeout, 250); - for (const [type, interpreter] of TYPES) { - const selector = `script[type="${type}-editor"]`; - for (const script of document.querySelectorAll(selector)) { - // avoid any further bootstrap - script.type += "-active"; - await init(script, type, interpreter); - } - } -}; - -new MutationObserver(pyEditor).observe(document, { - childList: true, - subtree: true, -}); - -// try to check the current document ASAP -export default pyEditor(); diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js deleted file mode 100644 index edf9db3cd27..00000000000 --- a/pyscript.core/src/plugins/py-terminal.js +++ /dev/null @@ -1,187 +0,0 @@ -// PyScript py-terminal plugin -import { TYPES, hooks } from "../core.js"; -import { notify } from "./error.js"; -import { defineProperty } from "polyscript/exports"; - -const SELECTOR = [...TYPES.keys()] - .map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`) - .join(","); - -// show the error on main and -// stops the module from keep executing -const notifyAndThrow = (message) => { - notify(message); - throw new Error(message); -}; - -const pyTerminal = async () => { - const terminals = document.querySelectorAll(SELECTOR); - - // no results will look further for runtime nodes - if (!terminals.length) return; - - // if we arrived this far, let's drop the MutationObserver - // as we only support one terminal per page (right now). - mo.disconnect(); - - // we currently support only one terminal as in "classic" - if (terminals.length > 1) notifyAndThrow("You can use at most 1 terminal."); - - const [element] = terminals; - // hopefully to be removed in the near future! - if (element.matches('script[type="mpy"],mpy-script')) - notifyAndThrow("Unsupported terminal."); - - // import styles lazily - document.head.append( - Object.assign(document.createElement("link"), { - rel: "stylesheet", - href: new URL("./xterm.css", import.meta.url), - }), - ); - - // lazy load these only when a valid terminal is found - const [{ Terminal }, { Readline }, { FitAddon }] = await Promise.all([ - import(/* webpackIgnore: true */ "../3rd-party/xterm.js"), - import(/* webpackIgnore: true */ "../3rd-party/xterm-readline.js"), - import(/* webpackIgnore: true */ "../3rd-party/xterm_addon-fit.js"), - ]); - - const readline = new Readline(); - - // common main thread initialization for both worker - // or main case, bootstrapping the terminal on its target - const init = (options) => { - let target = element; - const selector = element.getAttribute("target"); - if (selector) { - target = - document.getElementById(selector) || - document.querySelector(selector); - if (!target) throw new Error(`Unknown target ${selector}`); - } else { - target = document.createElement("py-terminal"); - target.style.display = "block"; - element.after(target); - } - const terminal = new Terminal({ - theme: { - background: "#191A19", - foreground: "#F5F2E7", - }, - ...options, - }); - const fitAddon = new FitAddon(); - terminal.loadAddon(fitAddon); - terminal.loadAddon(readline); - terminal.open(target); - fitAddon.fit(); - terminal.focus(); - defineProperty(element, "terminal", { value: terminal }); - return terminal; - }; - - // branch logic for the worker - if (element.hasAttribute("worker")) { - // when the remote thread onReady triggers: - // setup the interpreter stdout and stderr - const workerReady = ({ interpreter, io, run }, { sync }) => { - // in workers it's always safe to grab the polyscript currentScript - run( - "from polyscript.currentScript import terminal as __terminal__", - ); - sync.pyterminal_drop_hooks(); - - // This part is inevitably duplicated as external scope - // can't be reached by workers out of the box. - // The detail is that here we use sync though, not readline. - const decoder = new TextDecoder(); - let data = ""; - const generic = { - isatty: true, - write(buffer) { - data = decoder.decode(buffer); - sync.pyterminal_write(data); - return buffer.length; - }, - }; - interpreter.setStdout(generic); - interpreter.setStderr(generic); - interpreter.setStdin({ - isatty: true, - stdin: () => sync.pyterminal_read(data), - }); - - io.stderr = (error) => { - sync.pyterminal_write(`${error.message || error}\n`); - }; - }; - - // add a hook on the main thread to setup all sync helpers - // also bootstrapping the XTerm target on main - hooks.main.onWorker.add(function worker(_, xworker) { - hooks.main.onWorker.delete(worker); - init({ - disableStdin: false, - cursorBlink: true, - cursorStyle: "block", - }); - xworker.sync.pyterminal_read = readline.read.bind(readline); - xworker.sync.pyterminal_write = readline.write.bind(readline); - // allow a worker to drop main thread hooks ASAP - xworker.sync.pyterminal_drop_hooks = () => { - hooks.worker.onReady.delete(workerReady); - }; - }); - - // setup remote thread JS/Python code for whenever the - // worker is ready to become a terminal - hooks.worker.onReady.add(workerReady); - } else { - // in the main case, just bootstrap XTerm without - // allowing any input as that's not possible / awkward - hooks.main.onReady.add(function main({ interpreter, io, run }) { - console.warn("py-terminal is read only on main thread"); - hooks.main.onReady.delete(main); - - // on main, it's easy to trash and clean the current terminal - globalThis.__py_terminal__ = init({ - disableStdin: true, - cursorBlink: false, - cursorStyle: "underline", - }); - run("from js import __py_terminal__ as __terminal__"); - delete globalThis.__py_terminal__; - - // This part is inevitably duplicated as external scope - // can't be reached by workers out of the box. - // The detail is that here we use readline here, not sync. - const decoder = new TextDecoder(); - let data = ""; - const generic = { - isatty: true, - write(buffer) { - data = decoder.decode(buffer); - readline.write(data); - return buffer.length; - }, - }; - interpreter.setStdout(generic); - interpreter.setStderr(generic); - interpreter.setStdin({ - isatty: true, - stdin: () => readline.read(data), - }); - - io.stderr = (error) => { - readline.write(`${error.message || error}\n`); - }; - }); - } -}; - -const mo = new MutationObserver(pyTerminal); -mo.observe(document, { childList: true, subtree: true }); - -// try to check the current document ASAP -export default pyTerminal(); diff --git a/pyscript.core/src/stdlib/pyscript/event_handling.py b/pyscript.core/src/stdlib/pyscript/event_handling.py deleted file mode 100644 index 3fac89ea522..00000000000 --- a/pyscript.core/src/stdlib/pyscript/event_handling.py +++ /dev/null @@ -1,45 +0,0 @@ -import inspect - -from pyodide.ffi.wrappers import add_event_listener -from pyscript.magic_js import document - - -def when(event_type=None, selector=None): - """ - Decorates a function and passes py-* events to the decorated function - The events might or not be an argument of the decorated function - """ - - def decorator(func): - if isinstance(selector, str): - elements = document.querySelectorAll(selector) - else: - # TODO: This is a hack that will be removed when pyscript becomes a package - # and we can better manage the imports without circular dependencies - from pyweb import pydom - - if isinstance(selector, pydom.Element): - elements = [selector._js] - elif isinstance(selector, pydom.ElementCollection): - elements = [el._js for el in selector] - else: - raise ValueError( - f"Invalid selector: {selector}. Selector must" - " be a string, a pydom.Element or a pydom.ElementCollection." - ) - - sig = inspect.signature(func) - # Function doesn't receive events - if not sig.parameters: - - def wrapper(*args, **kwargs): - func() - - for el in elements: - add_event_listener(el, event_type, wrapper) - else: - for el in elements: - add_event_listener(el, event_type, func) - return func - - return decorator diff --git a/pyscript.core/src/stdlib/pyscript/util.py b/pyscript.core/src/stdlib/pyscript/util.py deleted file mode 100644 index 8676f052fb6..00000000000 --- a/pyscript.core/src/stdlib/pyscript/util.py +++ /dev/null @@ -1,21 +0,0 @@ -class NotSupported: - """ - Small helper that raises exceptions if you try to get/set any attribute on - it. - """ - - def __init__(self, name, error): - object.__setattr__(self, "name", name) - object.__setattr__(self, "error", error) - - def __repr__(self): - return f"" - - def __getattr__(self, attr): - raise AttributeError(self.error) - - def __setattr__(self, attr, value): - raise AttributeError(self.error) - - def __call__(self, *args): - raise TypeError(self.error) diff --git a/pyscript.core/src/stdlib/pyweb/pydom.py b/pyscript.core/src/stdlib/pyweb/pydom.py deleted file mode 100644 index 340186fdc5e..00000000000 --- a/pyscript.core/src/stdlib/pyweb/pydom.py +++ /dev/null @@ -1,433 +0,0 @@ -import sys -import warnings -from functools import cached_property -from typing import Any - -from pyodide.ffi import JsProxy -from pyscript import display, document, window - -alert = window.alert - - -class BaseElement: - def __init__(self, js_element): - self._js = js_element - self._parent = None - self.style = StyleProxy(self) - self._proxies = {} - - def __eq__(self, obj): - """Check if the element is the same as the other element by comparing - the underlying JS element""" - return isinstance(obj, BaseElement) and obj._js == self._js - - @property - def parent(self): - if self._parent: - return self._parent - - if self._js.parentElement: - self._parent = self.__class__(self._js.parentElement) - - return self._parent - - @property - def __class(self): - return self.__class__ if self.__class__ != PyDom else Element - - def create(self, type_, is_child=True, classes=None, html=None, label=None): - js_el = document.createElement(type_) - element = self.__class(js_el) - - if classes: - for class_ in classes: - element.add_class(class_) - - if html is not None: - element.html = html - - if label is not None: - element.label = label - - if is_child: - self.append(element) - - return element - - def find(self, selector): - """Return an ElementCollection representing all the child elements that - match the specified selector. - - Args: - selector (str): A string containing a selector expression - - Returns: - ElementCollection: A collection of elements matching the selector - """ - elements = self._js.querySelectorAll(selector) - if not elements: - return None - return ElementCollection([Element(el) for el in elements]) - - -class Element(BaseElement): - @property - def children(self): - return [self.__class__(el) for el in self._js.children] - - def append(self, child): - # TODO: this is Pyodide specific for now!!!!!! - # if we get passed a JSProxy Element directly we just map it to the - # higher level Python element - if isinstance(child, JsProxy): - return self.append(Element(child)) - - elif isinstance(child, Element): - self._js.appendChild(child._js) - - return child - - elif isinstance(child, ElementCollection): - for el in child: - self.append(el) - - # -------- Pythonic Interface to Element -------- # - @property - def html(self): - return self._js.innerHTML - - @html.setter - def html(self, value): - self._js.innerHTML = value - - @property - def content(self): - # TODO: This breaks with with standard template elements. Define how to best - # handle this specifica use case. Just not support for now? - if self._js.tagName == "TEMPLATE": - warnings.warn( - "Content attribute not supported for template elements.", stacklevel=2 - ) - return None - return self._js.innerHTML - - @content.setter - def content(self, value): - # TODO: (same comment as above) - if self._js.tagName == "TEMPLATE": - warnings.warn( - "Content attribute not supported for template elements.", stacklevel=2 - ) - return - - display(value, target=self.id) - - @property - def id(self): - return self._js.id - - @id.setter - def id(self, value): - self._js.id = value - - @property - def options(self): - if "options" in self._proxies: - return self._proxies["options"] - - if not self._js.tagName.lower() in {"select", "datalist", "optgroup"}: - raise AttributeError( - f"Element {self._js.tagName} has no options attribute." - ) - self._proxies["options"] = OptionsProxy(self) - return self._proxies["options"] - - @property - def value(self): - return self._js.value - - @value.setter - def value(self, value): - # in order to avoid confusion to the user, we don't allow setting the - # value of elements that don't have a value attribute - if not hasattr(self._js, "value"): - raise AttributeError( - f"Element {self._js.tagName} has no value attribute. If you want to " - "force a value attribute, set it directly using the `_js.value = ` " - "javascript API attribute instead." - ) - self._js.value = value - - @property - def selected(self): - return self._js.selected - - @selected.setter - def selected(self, value): - # in order to avoid confusion to the user, we don't allow setting the - # value of elements that don't have a value attribute - if not hasattr(self._js, "selected"): - raise AttributeError( - f"Element {self._js.tagName} has no value attribute. If you want to " - "force a value attribute, set it directly using the `_js.value = ` " - "javascript API attribute instead." - ) - self._js.selected = value - - def clone(self, new_id=None): - clone = Element(self._js.cloneNode(True)) - clone.id = new_id - - return clone - - def remove_class(self, classname): - classList = self._js.classList - if isinstance(classname, list): - classList.remove(*classname) - else: - classList.remove(classname) - return self - - def add_class(self, classname): - classList = self._js.classList - if isinstance(classname, list): - classList.add(*classname) - else: - self._js.classList.add(classname) - return self - - @property - def classes(self): - classes = self._js.classList.values() - return [x for x in classes] - - def show_me(self): - self._js.scrollIntoView() - - -class OptionsProxy: - """This class represents the options of a select element. It - allows to access to add and remove options by using the `add` and `remove` methods. - """ - - def __init__(self, element: Element) -> None: - self._element = element - if self._element._js.tagName.lower() != "select": - raise AttributeError( - f"Element {self._element._js.tagName} has no options attribute." - ) - - def add( - self, - value: Any = None, - html: str = None, - text: str = None, - before: Element | int = None, - **kws, - ) -> None: - """Add a new option to the select element""" - # create the option element and set the attributes - option = document.createElement("option") - if value is not None: - kws["value"] = value - if html is not None: - option.innerHTML = html - if text is not None: - kws["text"] = text - - for key, value in kws.items(): - option.setAttribute(key, value) - - if before: - if isinstance(before, Element): - before = before._js - - self._element._js.add(option, before) - - def remove(self, item: int) -> None: - """Remove the option at the specified index""" - self._element._js.remove(item) - - def clear(self) -> None: - """Remove all the options""" - for i in range(len(self)): - self.remove(0) - - @property - def options(self): - """Return the list of options""" - return [Element(opt) for opt in self._element._js.options] - - @property - def selected(self): - """Return the selected option""" - return self.options[self._element._js.selectedIndex] - - def __iter__(self): - yield from self.options - - def __len__(self): - return len(self.options) - - def __repr__(self): - return f"{self.__class__.__name__} (length: {len(self)}) {self.options}" - - def __getitem__(self, key): - return self.options[key] - - -class StyleProxy(dict): - def __init__(self, element: Element) -> None: - self._element = element - - @cached_property - def _style(self): - return self._element._js.style - - def __getitem__(self, key): - return self._style.getPropertyValue(key) - - def __setitem__(self, key, value): - self._style.setProperty(key, value) - - def remove(self, key): - self._style.removeProperty(key) - - def set(self, **kws): - for k, v in kws.items(): - self._element._js.style.setProperty(k, v) - - # CSS Properties - # Reference: https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts#L3799C1-L5005C2 - # Following prperties automatically generated from the above reference using - # tools/codegen_css_proxy.py - @property - def visible(self): - return self._element._js.style.visibility - - @visible.setter - def visible(self, value): - self._element._js.style.visibility = value - - -class StyleCollection: - def __init__(self, collection: "ElementCollection") -> None: - self._collection = collection - - def __get__(self, obj, objtype=None): - return obj._get_attribute("style") - - def __getitem__(self, key): - return self._collection._get_attribute("style")[key] - - def __setitem__(self, key, value): - for element in self._collection._elements: - element.style[key] = value - - def remove(self, key): - for element in self._collection._elements: - element.style.remove(key) - - -class ElementCollection: - def __init__(self, elements: [Element]) -> None: - self._elements = elements - self.style = StyleCollection(self) - - def __getitem__(self, key): - # If it's an integer we use it to access the elements in the collection - if isinstance(key, int): - return self._elements[key] - # If it's a slice we use it to support slice operations over the elements - # in the collection - elif isinstance(key, slice): - return ElementCollection(self._elements[key]) - - # If it's anything else (basically a string) we use it as a selector - # TODO: Write tests! - elements = self._element.querySelectorAll(key) - return ElementCollection([Element(el) for el in elements]) - - def __len__(self): - return len(self._elements) - - def __eq__(self, obj): - """Check if the element is the same as the other element by comparing - the underlying JS element""" - return isinstance(obj, ElementCollection) and obj._elements == self._elements - - def _get_attribute(self, attr, index=None): - if index is None: - return [getattr(el, attr) for el in self._elements] - - # As JQuery, when getting an attr, only return it for the first element - return getattr(self._elements[index], attr) - - def _set_attribute(self, attr, value): - for el in self._elements: - setattr(el, attr, value) - - @property - def html(self): - return self._get_attribute("html") - - @html.setter - def html(self, value): - self._set_attribute("html", value) - - @property - def value(self): - return self._get_attribute("value") - - @value.setter - def value(self, value): - self._set_attribute("value", value) - - @property - def children(self): - return self._elements - - def __iter__(self): - yield from self._elements - - def __repr__(self): - return f"{self.__class__.__name__} (length: {len(self._elements)}) {self._elements}" - - -class DomScope: - def __getattr__(self, __name: str) -> Any: - element = document[f"#{__name}"] - if element: - return element[0] - - -class PyDom(BaseElement): - # Add objects we want to expose to the DOM namespace since this class instance is being - # remapped as "the module" itself - BaseElement = BaseElement - Element = Element - ElementCollection = ElementCollection - - def __init__(self): - super().__init__(document) - self.ids = DomScope() - self.body = Element(document.body) - self.head = Element(document.head) - - def create(self, type_, classes=None, html=None): - return super().create(type_, is_child=False, classes=classes, html=html) - - def __getitem__(self, key): - if isinstance(key, int): - indices = range(*key.indices(len(self.list))) - return [self.list[i] for i in indices] - - elements = self._js.querySelectorAll(key) - if not elements: - return None - return ElementCollection([Element(el) for el in elements]) - - -dom = PyDom() - -sys.modules[__name__] = dom diff --git a/pyscript.core/src/sync.js b/pyscript.core/src/sync.js deleted file mode 100644 index 55519452873..00000000000 --- a/pyscript.core/src/sync.js +++ /dev/null @@ -1,9 +0,0 @@ -export 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. - */ - sleep(seconds) { - return new Promise(($) => setTimeout($, seconds * 1000)); - }, -}; diff --git a/pyscript.core/test/async.html b/pyscript.core/test/async.html deleted file mode 100644 index 0e9801d1108..00000000000 --- a/pyscript.core/test/async.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - import asyncio - print('foo') - await asyncio.sleep(1) - print('bar') - - - diff --git a/pyscript.core/test/error.js b/pyscript.core/test/error.js deleted file mode 100644 index 46a99a9dcac..00000000000 --- a/pyscript.core/test/error.js +++ /dev/null @@ -1,39 +0,0 @@ -// 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/mpy.spec.js b/pyscript.core/test/mpy.spec.js deleted file mode 100644 index 7e89c0f76e9..00000000000 --- a/pyscript.core/test/mpy.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -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')); -}); - -test('MicroPython + Pyodide js_modules', 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/js_modules.html'); - await page.waitForSelector('html.done'); - await expect(logs.length).toBe(6); - await expect(logs[0]).toBe(logs[1]); - await expect(logs[1]).toBe(logs[2]); - await expect(logs[3]).toBe(logs[4]); - await expect(logs[4]).toBe(logs[5]); -}); - -test('MicroPython + configURL', 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/config-url.html'); - await page.waitForSelector('html.main.worker'); -}); - -test('Pyodide + terminal on Main', async ({ page }) => { - await page.goto('http://localhost:8080/test/py-terminal-main.html'); - await page.waitForSelector('html.ok'); -}); - - -test('Pyodide + terminal on Worker', async ({ page }) => { - await page.goto('http://localhost:8080/test/py-terminal-worker.html'); - await page.waitForSelector('html.ok'); -}); diff --git a/pyscript.core/test/py-terminal.html b/pyscript.core/test/py-terminal.html deleted file mode 100644 index ebf7f04de3a..00000000000 --- a/pyscript.core/test/py-terminal.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - PyTerminal - - - - - - - - # works on both worker and main scripts - print("__terminal__", __terminal__) - - 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 deleted file mode 100644 index ff64738171a..00000000000 --- a/pyscript.core/test/pydom.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - PyScript Next Plugin - - - - - - - - - - -
- - diff --git a/pyscript.core/test/pydom.py b/pyscript.core/test/pydom.py deleted file mode 100644 index e251b8b42f1..00000000000 --- a/pyscript.core/test/pydom.py +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 63c88ee4ae7..00000000000 --- a/pyscript.core/test/pyscript_dom/index.html +++ /dev/null @@ -1,128 +0,0 @@ - - - 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 deleted file mode 100644 index 128abcccb73..00000000000 --- a/pyscript.core/test/pyscript_dom/run_tests.py +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 6bcee173597..00000000000 --- a/pyscript.core/test/pyscript_dom/tests.toml +++ /dev/null @@ -1,8 +0,0 @@ -packages = [ - "pytest" -] - -[[fetch]] -from = "tests/" -files = ["__init__.py", "conftest.py", "test_dom.py"] -to_folder = "tests" diff --git a/pyscript.core/test/pyscript_dom/tests/conftest.py b/pyscript.core/test/pyscript_dom/tests/conftest.py deleted file mode 100644 index 4ba26c057db..00000000000 --- a/pyscript.core/test/pyscript_dom/tests/conftest.py +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 3172e1d9763..00000000000 --- a/pyscript.core/test/pyscript_dom/tests/test_dom.py +++ /dev/null @@ -1,435 +0,0 @@ -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" - - def test_element_without_collection(self): - result = pydom[f"#tests-terminal"] - with pytest.raises(AttributeError): - result.value = "some value" - - -class TestSelect: - def test_select_options_iter(self): - select = pydom[f"#test_select_element_w_options"][0] - - for i, option in enumerate(select.options, 1): - assert option.value == f"{i}" - assert option.html == f"Option {i}" - - def test_select_options_len(self): - select = pydom[f"#test_select_element_w_options"][0] - assert len(select.options) == 2 - - def test_select_options_clear(self): - select = pydom[f"#test_select_element_to_clear"][0] - assert len(select.options) == 3 - - select.options.clear() - - assert len(select.options) == 0 - - def test_select_element_add(self): - # GIVEN the existing select element with no options - select = pydom[f"#test_select_element"][0] - - # EXPECT the select element to have no options - assert len(select.options) == 0 - - # WHEN we add an option - select.options.add(value="1", html="Option 1") - - # EXPECT the select element to have 1 option matching the attributes - # we passed in - assert len(select.options) == 1 - assert select.options[0].value == "1" - assert select.options[0].html == "Option 1" - - # WHEN we add another option (blank this time) - select.options.add() - - # EXPECT the select element to have 2 options - assert len(select.options) == 2 - - # EXPECT the last option to have an empty value and html - assert select.options[1].value == "" - assert select.options[1].html == "" - - # WHEN we add another option (this time adding it in between the other 2 - # options by using an integer index) - select.options.add(value="2", html="Option 2", before=1) - - # EXPECT the select element to have 3 options - assert len(select.options) == 3 - - # EXPECT the middle option to have the value and html we passed in - assert select.options[0].value == "1" - assert select.options[0].html == "Option 1" - assert select.options[1].value == "2" - assert select.options[1].html == "Option 2" - assert select.options[2].value == "" - assert select.options[2].html == "" - - # WHEN we add another option (this time adding it in between the other 2 - # options but using the option itself) - select.options.add( - value="3", html="Option 3", before=select.options[2], selected=True - ) - - # EXPECT the select element to have 3 options - assert len(select.options) == 4 - - # EXPECT the middle option to have the value and html we passed in - assert select.options[0].value == "1" - assert select.options[0].html == "Option 1" - assert select.options[0].selected == select.options[0]._js.selected == False - assert select.options[1].value == "2" - assert select.options[1].html == "Option 2" - assert select.options[2].value == "3" - assert select.options[2].html == "Option 3" - assert select.options[2].selected == select.options[2]._js.selected == True - assert select.options[3].value == "" - assert select.options[3].html == "" - - # WHEN we add another option (this time adding it in between the other 2 - # options but using the JS element of the option itself) - select.options.add(value="2a", html="Option 2a", before=select.options[2]._js) - - # EXPECT the select element to have 3 options - assert len(select.options) == 5 - - # EXPECT the middle option to have the value and html we passed in - assert select.options[0].value == "1" - assert select.options[0].html == "Option 1" - assert select.options[1].value == "2" - assert select.options[1].html == "Option 2" - assert select.options[2].value == "2a" - assert select.options[2].html == "Option 2a" - assert select.options[3].value == "3" - assert select.options[3].html == "Option 3" - assert select.options[4].value == "" - assert select.options[4].html == "" - - def test_select_options_remove(self): - # GIVEN the existing select element with 3 options - select = pydom[f"#test_select_element_to_remove"][0] - - # EXPECT the select element to have 3 options - assert len(select.options) == 4 - # EXPECT the options to have the values originally set - assert select.options[0].value == "1" - assert select.options[1].value == "2" - assert select.options[2].value == "3" - assert select.options[3].value == "4" - - # WHEN we remove the second option (index starts at 0) - select.options.remove(1) - - # EXPECT the select element to have 2 options - assert len(select.options) == 3 - # EXPECT the options to have the values originally set but the second - assert select.options[0].value == "1" - assert select.options[1].value == "3" - assert select.options[2].value == "4" - - def test_select_get_selected_option(self): - # GIVEN the existing select element with one selected option - select = pydom[f"#test_select_element_w_options"][0] - - # WHEN we get the selected option - selected_option = select.options.selected - - # EXPECT the selected option to be correct - assert selected_option.value == "2" - assert selected_option.html == "Option 2" - assert selected_option.selected == selected_option._js.selected == True diff --git a/pyscript.core/tests/integration/__init__.py b/pyscript.core/tests/integration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pyscript.core/tests/integration/conftest.py b/pyscript.core/tests/integration/conftest.py deleted file mode 100644 index fe26c72a17c..00000000000 --- a/pyscript.core/tests/integration/conftest.py +++ /dev/null @@ -1,183 +0,0 @@ -import shutil -import threading -from http.server import HTTPServer as SuperHTTPServer -from http.server import SimpleHTTPRequestHandler - -import pytest - -from .support import Logger - - -def pytest_cmdline_main(config): - """ - If we pass --clear-http-cache, we don't enter the main pytest logic, but - use our custom main instead - """ - - def mymain(config, session): - print() - print("-" * 20, "SmartRouter HTTP cache", "-" * 20) - # unfortunately pytest-cache doesn't offer a public API to selectively - # clear the cache, so we need to peek its internal. The good news is - # that pytest-cache is very old, stable and robust, so it's likely - # that this won't break anytime soon. - cache = config.cache - base = cache._cachedir.joinpath(cache._CACHE_PREFIX_VALUES, "pyscript") - if not base.exists(): - print("No cache found, nothing to do") - return 0 - # - print("Requests found in the cache:") - for f in base.rglob("*"): - if f.is_file(): - # requests are saved in dirs named pyscript/http:/foo/bar, let's turn - # them into a proper url - url = str(f.relative_to(base)) - url = url.replace(":/", "://") - print(" ", url) - shutil.rmtree(base) - print("Cache cleared") - return 0 - - if config.option.clear_http_cache: - from _pytest.main import wrap_session - - return wrap_session(config, mymain) - return None - - -def pytest_configure(config): - """ - THIS IS A WORKAROUND FOR A pytest QUIRK! - - At the moment of writing this conftest defines two new options, --dev and - --no-fake-server, but because of how pytest works, they are available only - if this is the "root conftest" for the test session. - - This means that if you are in the pyscript.core directory: - - $ py.test # does NOT work - $ py.test tests/integration/ # works - - This happens because there is also test py-unit directory, so in the first - case the "root conftest" would be tests/conftest.py (which doesn't exist) - instead of this. - - There are various workarounds, but for now we can just detect it and - inform the user. - - Related StackOverflow answer: https://stackoverflow.com/a/51733980 - """ - if not hasattr(config.option, "dev"): - msg = """ - Running a bare "pytest" command from the pyscript.core directory - is not supported. Please use one of the following commands: - - pytest tests/integration - - pytest tests/* - - cd tests/integration; pytest - """ - pytest.fail(msg) - else: - if config.option.dev: - config.option.headed = True - config.option.no_fake_server = True - - -@pytest.fixture(scope="session") -def logger(): - return Logger() - - -def pytest_addoption(parser): - parser.addoption( - "--no-fake-server", - action="store_true", - help="Use a real HTTP server instead of http://fakeserver", - ) - parser.addoption( - "--dev", - action="store_true", - help="Automatically open a devtools panel. Implies --headed and --no-fake-server", - ) - parser.addoption( - "--clear-http-cache", - action="store_true", - help="Clear the cache of HTTP requests for SmartRouter", - ) - - -@pytest.fixture(scope="session") -def browser_type_launch_args(request): - """ - Override the browser_type_launch_args defined by pytest-playwright to - support --devtools. - - NOTE: this has been tested with pytest-playwright==0.3.0. It might break - with newer versions of it. - """ - # this calls the "original" fixture defined by pytest_playwright.py - launch_options = request.getfixturevalue("browser_type_launch_args") - if request.config.option.dev: - launch_options["devtools"] = True - return launch_options - - -class DevServer(SuperHTTPServer): - """ - Class for wrapper to run SimpleHTTPServer on Thread. - Ctrl +Only Thread remains dead when terminated with C. - Keyboard Interrupt passes. - """ - - def __init__(self, base_url, *args, **kwargs): - self.base_url = base_url - super().__init__(*args, **kwargs) - - def run(self): - try: - self.serve_forever() - except KeyboardInterrupt: - pass - finally: - self.server_close() - - -@pytest.fixture(scope="session") -def dev_server(logger): - class MyHTTPRequestHandler(SimpleHTTPRequestHandler): - enable_cors_headers = True - - @classmethod - def my_headers(cls): - if cls.enable_cors_headers: - return { - "Cross-Origin-Embedder-Policy": "require-corp", - "Cross-Origin-Opener-Policy": "same-origin", - } - return {} - - def end_headers(self): - self.send_my_headers() - SimpleHTTPRequestHandler.end_headers(self) - - def send_my_headers(self): - for k, v in self.my_headers().items(): - self.send_header(k, v) - - def log_message(self, fmt, *args): - logger.log("http_server", fmt % args, color="blue") - - host, port = "localhost", 8080 - base_url = f"http://{host}:{port}" - - # serve_Run forever under thread - server = DevServer(base_url, (host, port), MyHTTPRequestHandler) - - thread = threading.Thread(None, server.run) - thread.start() - - yield server # Transition to test here - - # End thread - server.shutdown() - thread.join() diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py deleted file mode 100644 index 4cc40db72ff..00000000000 --- a/pyscript.core/tests/integration/support.py +++ /dev/null @@ -1,1043 +0,0 @@ -import dataclasses -import functools -import math -import os -import pdb -import re -import sys -import time -import traceback -import urllib -from dataclasses import dataclass - -import py -import pytest -import toml -from playwright.sync_api import Error as PlaywrightError - -ROOT = py.path.local(__file__).dirpath("..", "..", "..") -BUILD = ROOT.join("pyscript.core").join("dist") - - -def params_with_marks(params): - """ - Small helper to automatically apply to each param a pytest.mark with the - same name of the param itself. E.g.: - - params_with_marks(['aaa', 'bbb']) - - is equivalent to: - - [pytest.param('aaa', marks=pytest.mark.aaa), - pytest.param('bbb', marks=pytest.mark.bbb)] - - This makes it possible to use 'pytest -m aaa' to run ONLY the tests which - uses the param 'aaa'. - """ - return [pytest.param(name, marks=getattr(pytest.mark, name)) for name in params] - - -def with_execution_thread(*values): - """ - Class decorator to override config.execution_thread. - - By default, we run each test twice: - - execution_thread = 'main' - - execution_thread = 'worker' - - If you want to execute certain tests with only one specific values of - execution_thread, you can use this class decorator. For example: - - @with_execution_thread('main') - class TestOnlyMainThread: - ... - - @with_execution_thread('worker') - class TestOnlyWorker: - ... - - If you use @with_execution_thread(None), the logic to inject the - execution_thread config is disabled. - """ - - if values == (None,): - - @pytest.fixture - def execution_thread(self, request): - return None - - else: - for value in values: - assert value in ("main", "worker") - - @pytest.fixture(params=params_with_marks(values)) - def execution_thread(self, request): - return request.param - - def with_execution_thread_decorator(cls): - cls.execution_thread = execution_thread - return cls - - return with_execution_thread_decorator - - -def skip_worker(reason): - """ - Decorator to skip a test if self.execution_thread == 'worker' - """ - if callable(reason): - # this happens if you use @skip_worker instead of @skip_worker("bla bla bla") - raise Exception( - "You need to specify a reason for skipping, " - "please use: @skip_worker('...')" - ) - - def decorator(fn): - @functools.wraps(fn) - def decorated(self, *args): - if self.execution_thread == "worker": - pytest.skip(reason) - return fn(self, *args) - - return decorated - - return decorator - - -def only_main(fn): - """ - Decorator to mark a test which make sense only in the main thread - """ - - @functools.wraps(fn) - def decorated(self, *args): - if self.execution_thread == "worker": - return - return fn(self, *args) - - return decorated - - -def only_worker(fn): - """ - Decorator to mark a test which make sense only in the worker thread - """ - - @functools.wraps(fn) - def decorated(self, *args): - if self.execution_thread != "worker": - return - return fn(self, *args) - - return decorated - - -def filter_inner_text(text, exclude=None): - return "\n".join(filter_page_content(text.splitlines(), exclude=exclude)) - - -def filter_page_content(lines, exclude=None): - """Remove lines that are not relevant for the test. By default, ignores: - ('', 'execution_thread = "main"', 'execution_thread = "worker"') - - Args: - lines (list): list of strings - exclude (list): list of strings to exclude - - Returns: - list: list of strings - """ - if exclude is None: - exclude = {"", 'execution_thread = "main"', 'execution_thread = "worker"'} - - return [line for line in lines if line not in exclude] - - -@pytest.mark.usefixtures("init") -@with_execution_thread("main", "worker") -class PyScriptTest: - """ - Base class to write PyScript integration tests, based on playwright. - - It provides a simple API to generate HTML files and load them in - playwright. - - It also provides a Pythonic API on top of playwright for the most - common tasks; in particular: - - - self.console collects all the JS console.* messages. Look at the doc - of ConsoleMessageCollection for more details. - - - self.check_js_errors() checks that no JS errors have been thrown - - - after each test, self.check_js_errors() is automatically run to ensure - that no JS error passes uncaught. - - - self.wait_for_console waits until the specified message appears in the - console - - - self.wait_for_pyscript waits until all the PyScript tags have been - evaluated - - - self.pyscript_run is the main entry point for pyscript tests: it - creates an HTML page to run the specified snippet. - """ - - DEFAULT_TIMEOUT = 30 * 1000 - - @pytest.fixture() - def init(self, request, tmpdir, logger, page, execution_thread): - """ - Fixture to automatically initialize all the tests in this class and its - subclasses. - - The magic is done by the decorator @pytest.mark.usefixtures("init"), - which tells pytest to automatically use this fixture for all the test - method of this class. - - Using the standard pytest behavior, we can request more fixtures: - tmpdir, and page; 'page' is a fixture provided by pytest-playwright. - - Then, we save these fixtures on the self and proceed with more - initialization. The end result is that the requested fixtures are - automatically made available as self.xxx in all methods. - """ - self.testname = request.function.__name__.replace("test_", "") - self.tmpdir = tmpdir - # create a symlink to BUILD inside tmpdir - tmpdir.join("build").mksymlinkto(BUILD) - self.tmpdir.chdir() - self.tmpdir.join("favicon.ico").write("") - self.logger = logger - self.execution_thread = execution_thread - self.dev_server = None - - if request.config.option.no_fake_server: - # use a real HTTP server. Note that as soon as we request the - # fixture, the server automatically starts in its own thread. - self.dev_server = request.getfixturevalue("dev_server") - self.http_server_addr = self.dev_server.base_url - self.router = None - else: - # use the internal playwright routing - self.http_server_addr = "https://fake_server" - self.router = SmartRouter( - "fake_server", - cache=request.config.cache, - logger=logger, - usepdb=request.config.option.usepdb, - ) - self.router.install(page) - # - self.init_page(page) - # - # this extra print is useful when using pytest -s, else we start printing - # in the middle of the line - print() - # - # if you use pytest --headed you can see the browser page while - # playwright executes the tests, but the page is closed very quickly - # as soon as the test finishes. To avoid that, we automatically start - # a pdb so that we can wait as long as we want. - yield - if request.config.option.headed: - pdb.Pdb.intro = ( - "\n" - "This (Pdb) was started automatically because you passed --headed:\n" - "the execution of the test pauses here to give you the time to inspect\n" - "the browser. When you are done, type one of the following commands:\n" - " (Pdb) continue\n" - " (Pdb) cont\n" - " (Pdb) c\n" - ) - pdb.set_trace() - - def init_page(self, page): - self.page = page - page.set_default_timeout(self.DEFAULT_TIMEOUT) - self.console = ConsoleMessageCollection(self.logger) - self._js_errors = [] - self._py_errors = [] - page.on("console", self._on_console) - page.on("pageerror", self._on_pageerror) - - @property - def headers(self): - if self.dev_server is None: - return self.router.headers - return self.dev_server.RequestHandlerClass.my_headers() - - def disable_cors_headers(self): - if self.dev_server is None: - self.router.enable_cors_headers = False - else: - self.dev_server.RequestHandlerClass.enable_cors_headers = False - - def run_js(self, code): - """ - allows top level await to be present in the `code` parameter - """ - self.page.evaluate( - """(async () => { - try {%s} - catch(e) { - console.error(e); - } - })();""" - % code - ) - - def teardown_method(self): - # we call check_js_errors on teardown: this means that if there are still - # non-cleared errors, the test will fail. If you expect errors in your - # page and they should not cause the test to fail, you should call - # self.check_js_errors() in the test itself. - self.check_js_errors() - self.check_py_errors() - - def _on_console(self, msg): - if msg.type == "error" and "Traceback (most recent call last)" in msg.text: - # this is a Python traceback, let's record it as a py_error - self._py_errors.append(msg.text) - self.console.add_message(msg.type, msg.text) - - def _on_pageerror(self, error): - # apparently, playwright Error.stack contains all the info that we - # want: exception name, message and stacktrace. The docs say that - # error.stack is optional, so fallback to the standard repr if it's - # unavailable. - error_msg = error.stack or str(error) - self.console.add_message("js_error", error_msg) - self._js_errors.append(error_msg) - - def _check_page_errors(self, kind, expected_messages): - """ - Check whether the page raised any 'JS' or 'Python' error. - - expected_messages is a list of strings of errors that you expect they - were raised in the page. They are checked using a simple 'in' check, - equivalent to this: - if expected_message in actual_error_message: - ... - - If an error was expected but not found, it raises PageErrorsDidNotRaise. - - If there are MORE errors other than the expected ones, it raises PageErrors. - - Upon return, all the errors are cleared, so a subsequent call to - check_{js,py}_errors will not raise, unless NEW errors have been reported - in the meantime. - """ - assert kind in ("JS", "Python") - if kind == "JS": - actual_errors = self._js_errors[:] - else: - actual_errors = self._py_errors[:] - expected_messages = list(expected_messages) - - for i, msg in enumerate(expected_messages): - for j, error in enumerate(actual_errors): - if msg is not None and error is not None and msg in error: - # we matched one expected message with an error, remove both - expected_messages[i] = None - actual_errors[j] = None - - # if everything is find, now expected_messages and actual_errors contains - # only Nones. If they contain non-None elements, it means that we - # either have messages which are expected-but-not-found or - # found-but-not-expected. - not_found = [msg for msg in expected_messages if msg is not None] - unexpected = [err for err in actual_errors if err is not None] - - if kind == "JS": - self.clear_js_errors() - else: - self.clear_py_errors() - - if not_found: - # expected-but-not-found - raise PageErrorsDidNotRaise(kind, not_found, unexpected) - if unexpected: - # found-but-not-expected - raise PageErrors(kind, unexpected) - - def check_js_errors(self, *expected_messages): - """ - Check whether JS errors were reported. - - See the docstring for _check_page_errors for more details. - """ - self._check_page_errors("JS", expected_messages) - - def check_py_errors(self, *expected_messages): - """ - Check whether Python errors were reported. - - See the docstring for _check_page_errors for more details. - """ - self._check_page_errors("Python", expected_messages) - - def clear_js_errors(self): - """ - Clear all JS errors. - """ - self._js_errors = [] - - def clear_py_errors(self): - self._py_errors = [] - - def writefile(self, filename, content): - """ - Very thin helper to write a file in the tmpdir - """ - f = self.tmpdir.join(filename) - f.dirpath().ensure(dir=True) - f.write(content) - - def goto(self, path): - self.logger.reset() - self.logger.log("page.goto", path, color="yellow") - url = f"{self.http_server_addr}/{path}" - self.page.goto(url, timeout=0) - - def wait_for_console( - self, - text, - *, - match_substring=False, - timeout=None, - check_js_errors=True, - ): - """ - Wait until the given message appear in the console. If the message was - already printed in the console, return immediately. - - By default "text" must be the *exact* string as printed by a single - call to e.g. console.log. If match_substring is True, it is enough - that the console contains the given text anywhere. - - timeout is expressed in milliseconds. If it's None, it will use - the same default as playwright, which is 30 seconds. - - If check_js_errors is True (the default), it also checks that no JS - errors were raised during the waiting. - - Return the elapsed time in ms. - """ - if match_substring: - - def find_text(): - return text in self.console.all.text - - else: - - def find_text(): - return text in self.console.all.lines - - if timeout is None: - timeout = self.DEFAULT_TIMEOUT - # NOTE: we cannot use playwright's own page.expect_console_message(), - # because if you call it AFTER the text has already been emitted, it - # waits forever. Instead, we have to use our own custom logic. - try: - t0 = time.time() - while True: - elapsed_ms = (time.time() - t0) * 1000 - if elapsed_ms > timeout: - raise TimeoutError(f"{elapsed_ms:.2f} ms") - # - if find_text(): - # found it! - return elapsed_ms - # - self.page.wait_for_timeout(50) - finally: - # raise JsError if there were any javascript exception. Note that - # this might happen also in case of a TimeoutError. In that case, - # the JsError will shadow the TimeoutError but this is correct, - # because it's very likely that the console message never appeared - # precisely because of the exception in JS. - if check_js_errors: - self.check_js_errors() - - def wait_for_pyscript(self, *, timeout=None, check_js_errors=True): - """ - Wait until pyscript has been fully loaded. - - Timeout is expressed in milliseconds. If it's None, it will use - playwright's own default value, which is 30 seconds). - - If check_js_errors is True (the default), it also checks that no JS - errors were raised during the waiting. - """ - scripts = ( - self.page.locator("script[type=py]").all() - + self.page.locator("py-script").all() - ) - n_scripts = len(scripts) - - # this is printed by core.js:onAfterRun - elapsed_ms = self.wait_for_console( - "---py:all-done---", - timeout=timeout, - check_js_errors=check_js_errors, - ) - self.logger.log( - "wait_for_pyscript", f"Waited for {elapsed_ms/1000:.2f} s", color="yellow" - ) - self.page.wait_for_selector("html.all-done") - - SCRIPT_TAG_REGEX = re.compile('( - - {extra_head} - - - {snippet} - - - """ - return doc - - def pyscript_run( - self, - snippet, - *, - extra_head="", - wait_for_pyscript=True, - timeout=None, - check_js_errors=True, - ): - """ - Main entry point for pyscript tests. - - snippet contains a fragment of HTML which will be put inside a full - HTML document. In particular, the automatically contains the - correct - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - assert len(self.console.all.messages) == 6 - assert self.console.all.lines == [ - "my log 1", - "my debug", - "my info", - "my error", - "my warning", - "my log 2", - ] - - # fmt: off - assert self.console.all.text == textwrap.dedent(""" - my log 1 - my debug - my info - my error - my warning - my log 2 - """).strip() - # fmt: on - - assert self.console.log.lines == ["my log 1", "my log 2"] - assert self.console.debug.lines == ["my debug"] - - def test_check_js_errors_simple(self): - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrors) as exc: - self.check_js_errors() - # check that the exception message contains the error message and the - # stack trace - msg = str(exc.value) - expected = textwrap.dedent( - f""" - JS errors found: 1 - Error: this is an error - at {self.http_server_addr}/mytest.html:.* - """ - ).strip() - assert re.search(expected, msg) - # - # after a call to check_js_errors, the errors are cleared - self.check_js_errors() - # - # JS exceptions are also available in self.console.js_error - assert self.console.js_error.lines[0].startswith("Error: this is an error") - - def test_check_js_errors_expected(self): - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - self.check_js_errors("this is an error") - - def test_check_js_errors_expected_but_didnt_raise(self): - doc = """ - - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrorsDidNotRaise) as exc: - self.check_js_errors( - "this is an error 1", - "this is an error 2", - "this is an error 3", - "this is an error 4", - ) - # - msg = str(exc.value) - expected = textwrap.dedent( - """ - The following JS errors were expected but could not be found: - - this is an error 1 - - this is an error 3 - """ - ).strip() - assert re.search(expected, msg) - - def test_check_js_errors_multiple(self): - doc = """ - - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrors) as exc: - self.check_js_errors() - # - msg = str(exc.value) - expected = textwrap.dedent( - """ - JS errors found: 2 - Error: error 1 - at https://fake_server/mytest.html:.* - Error: error 2 - at https://fake_server/mytest.html:.* - """ - ).strip() - assert re.search(expected, msg) - # - # check that errors are cleared - self.check_js_errors() - - def test_check_js_errors_some_expected_but_others_not(self): - doc = """ - - - - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrors) as exc: - self.check_js_errors("expected 1", "expected 3") - # - msg = str(exc.value) - expected = textwrap.dedent( - """ - JS errors found: 2 - Error: NOT expected 2 - at https://fake_server/mytest.html:.* - Error: NOT expected 4 - at https://fake_server/mytest.html:.* - """ - ).strip() - assert re.search(expected, msg) - - def test_check_js_errors_expected_not_found_but_other_errors(self): - doc = """ - - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrorsDidNotRaise) as exc: - self.check_js_errors("this is not going to be found") - # - msg = str(exc.value) - expected = textwrap.dedent( - """ - The following JS errors were expected but could not be found: - - this is not going to be found - --- - The following JS errors were raised but not expected: - Error: error 1 - at https://fake_server/mytest.html:.* - Error: error 2 - at https://fake_server/mytest.html:.* - """ - ).strip() - assert re.search(expected, msg) - - def test_clear_js_errors(self): - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - self.clear_js_errors() - # self.check_js_errors does not raise, because the errors have been - # cleared - self.check_js_errors() - - def test_wait_for_console_simple(self): - """ - Test that self.wait_for_console actually waits. - If it's buggy, the test will try to read self.console.log BEFORE the - log has been written and it will fail. - """ - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - # we use a timeout of 200ms to give plenty of time to the page to - # actually run the setTimeout callback - self.wait_for_console("Page loaded!", timeout=200) - assert self.console.log.lines[-1] == "Page loaded!" - - def test_wait_for_console_timeout(self): - doc = """ - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(TimeoutError): - self.wait_for_console("This text will never be printed", timeout=200) - - def test_wait_for_console_dont_wait_if_already_emitted(self): - """ - If the text is already on the console, wait_for_console() should return - immediately without waiting. - """ - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - self.wait_for_console("Page loaded!", timeout=200) - assert self.console.log.lines[-2] == "Hello world" - assert self.console.log.lines[-1] == "Page loaded!" - # the following call should return immediately without waiting - self.wait_for_console("Hello world", timeout=1) - - def test_wait_for_console_exception_1(self): - """ - Test that if a JS exception is raised while waiting for the console, we - report the exception and not the timeout. - - There are two main cases: - 1. there is an exception and the console message does not appear - 2. there is an exception but the console message appears anyway - - This test checks for case 1. Case 2 is tested by - test_wait_for_console_exception_2 - """ - # case 1: there is an exception and the console message does not appear - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - # "Page loaded!" will never appear, of course. - self.goto("mytest.html") - with pytest.raises(PageErrors) as exc: - self.wait_for_console("Page loaded!", timeout=200) - assert "this is an error" in str(exc.value) - assert isinstance(exc.value.__context__, TimeoutError) - # - # if we use check_js_errors=False, the error are ignored, but we get the - # Timeout anyway - self.goto("mytest.html") - with pytest.raises(TimeoutError): - self.wait_for_console("Page loaded!", timeout=200, check_js_errors=False) - # we still got a PageErrors, so we need to manually clear it, else the - # test fails at teardown - self.clear_js_errors() - - def test_wait_for_console_exception_2(self): - """ - See the description in test_wait_for_console_exception_1. - """ - # case 2: there is an exception, but the console message appears - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(PageErrors) as exc: - self.wait_for_console("Page loaded!", timeout=200) - assert "this is an error" in str(exc.value) - # - # with check_js_errors=False, the Error is ignored and the - # wait_for_console succeeds - self.goto("mytest.html") - self.wait_for_console("Page loaded!", timeout=200, check_js_errors=False) - # clear the errors, else the test fails at teardown - self.clear_js_errors() - - def test_wait_for_console_match_substring(self): - doc = """ - - - - - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - with pytest.raises(TimeoutError): - self.wait_for_console("Bar", timeout=200) - # - self.wait_for_console("Bar", timeout=200, match_substring=True) - assert self.console.log.lines[-1] == "Foo Bar Baz" - - def test_iter_locator(self): - doc = """ - - -
foo
-
bar
-
baz
- - - """ - self.writefile("mytest.html", doc) - self.goto("mytest.html") - divs = self.page.locator("div") - assert divs.count() == 3 - texts = [el.inner_text() for el in self.iter_locator(divs)] - assert texts == ["foo", "bar", "baz"] - - def test_smartrouter_cache(self): - if self.router is None: - pytest.skip("Cannot test SmartRouter with --dev") - - # this is not an image but who cares, I just want the browser to make - # an HTTP request - URL = "https://raw.githubusercontent.com/pyscript/pyscript/main/README.md" - doc = f""" - - - - - - """ - self.writefile("mytest.html", doc) - # - self.router.clear_cache(URL) - self.goto("mytest.html") - assert self.router.requests == [ - (200, "fake_server", "https://fake_server/mytest.html"), - (200, "NETWORK", URL), - ] - # - # let's visit the page again, now it should be cached - self.goto("mytest.html") - assert self.router.requests == [ - # 1st visit - (200, "fake_server", "https://fake_server/mytest.html"), - (200, "NETWORK", URL), - # 2nd visit - (200, "fake_server", "https://fake_server/mytest.html"), - (200, "CACHED", URL), - ] - - def test_404(self): - """ - Test that we capture a 404 in loading a page that does not exist. - """ - self.goto("this_url_does_not_exist.html") - assert [ - "Failed to load resource: the server responded with a status of 404 (Not Found)" - ] == self.console.all.lines diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py deleted file mode 100644 index 5ac71f2a171..00000000000 --- a/pyscript.core/tests/integration/test_01_basic.py +++ /dev/null @@ -1,404 +0,0 @@ -import re - -import pytest - -from .support import PyScriptTest, only_main, skip_worker - - -class TestBasic(PyScriptTest): - 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 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") - 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 == "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, " - "the server must use https and also serve with the following headers: " - '{"Cross-Origin-Embedder-Policy":"require-corp",' - '"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(".py-error") - assert expected_alert_banner_msg in alert_banner.inner_text() - - def test_print(self): - self.pyscript_run( - """ - - """ - ) - assert self.console.log.lines[-1] == "hello pyscript" - - @only_main - def test_input_exception(self): - self.pyscript_run( - """ - - """ - ) - self.check_py_errors( - "Exception: input() doesn't work when PyScript runs in the main thread." - ) - - @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 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) - 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( - """ - - - """ - ) - - self.page.locator("button").click() - self.wait_for_console( - "Exception: this is an error inside handler", match_substring=True - ) - - self.check_py_errors("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 script py tags are executed in the same order they are - defined - """ - self.pyscript_run( - """ - - - - - """ - ) - assert self.console.log.lines[-4:] == [ - "one", - "two", - "three", - "four", - ] - - def test_escaping_of_angle_brackets(self): - """ - Check that script tags escape angle brackets - """ - self.pyscript_run( - """ - - - import js - js.console.log("C", 1<2, 1>2) - js.console.log("D
") -
- """ - ) - # 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( - """ - - packages = ["asciitree"] - - - """ - ) - - assert self.console.log.lines[-3:] == [ - "Loading asciitree", # printed by pyodide - "Loaded asciitree", # printed by pyodide - "hello asciitree", # printed by us - ] - - @pytest.mark.skip("NEXT: No banner") - def test_non_existent_package(self): - self.pyscript_run( - """ - - packages = ["i-dont-exist"] - - - """, - wait_for_pyscript=False, - ) - - expected_alert_banner_msg = ( - "(PY1001): Unable to install package(s) 'i-dont-exist'. " - "Unable to find package in PyPI. Please make sure you have " - "entered a correct package name." - ) - - alert_banner = self.page.wait_for_selector(".alert-banner") - assert expected_alert_banner_msg in alert_banner.inner_text() - self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") - - @pytest.mark.skip("NEXT: No banner") - def test_no_python_wheel(self): - self.pyscript_run( - """ - - packages = ["opsdroid"] - - - """, - wait_for_pyscript=False, - ) - - expected_alert_banner_msg = ( - "(PY1001): Unable to install package(s) 'opsdroid'. " - "Reason: Can't find a pure Python 3 Wheel for package(s) 'opsdroid'" - ) - - alert_banner = self.page.wait_for_selector(".alert-banner") - 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("py-script") - - 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.error.lines) - assert self.assert_banner_message(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)") - - assert ( - re.match(r"\d{4}\.\d{2}\.\d+(\.[a-zA-Z0-9]+)?", self.console.log.lines[-1]) - 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 ( - re.match(r"\d{4}\.\d{2}\.\d+(\.[a-zA-Z0-9]+)?", self.console.log.lines[-2]) - is not None - ) - assert ( - re.match( - r"version_info\(year=\d{4}, month=\d{2}, " - r"minor=\d+, releaselevel='([a-zA-Z0-9]+)?'\)", - self.console.log.lines[-1], - ) - is not None - ) - - @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.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( - """ - - - """ - ) - btn = self.page.wait_for_selector("button") - btn.click() - self.wait_for_console("hello world!") - assert self.console.log.lines[-1] == "hello world!" - assert self.console.error.lines == [] - - def test_py_all_done_event(self): - self.pyscript_run( - """ - - - """ - ) - 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 deleted file mode 100644 index 1ea603305ed..00000000000 --- a/pyscript.core/tests/integration/test_02_display.py +++ /dev/null @@ -1,526 +0,0 @@ -################################################################################ - -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/pyscript.core/tests/integration/test_assets/line_plot.png b/pyscript.core/tests/integration/test_assets/line_plot.png deleted file mode 100644 index 6909b373ac7..00000000000 Binary files a/pyscript.core/tests/integration/test_assets/line_plot.png and /dev/null differ diff --git a/pyscript.core/tests/integration/test_assets/tripcolor.png b/pyscript.core/tests/integration/test_assets/tripcolor.png deleted file mode 100644 index 898786a26e6..00000000000 Binary files a/pyscript.core/tests/integration/test_assets/tripcolor.png and /dev/null differ diff --git a/pyscript.core/tests/integration/test_async.py b/pyscript.core/tests/integration/test_async.py deleted file mode 100644 index 8c265a591d8..00000000000 --- a/pyscript.core/tests/integration/test_async.py +++ /dev/null @@ -1,205 +0,0 @@ -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): - self.pyscript_run(self.coroutine_script.format(func="ensure_future")) - self.wait_for_console("third") - assert self.console.log.lines[-3:] == ["first", "second", "third"] - - def test_asyncio_create_task(self): - self.pyscript_run(self.coroutine_script.format(func="create_task")) - self.wait_for_console("third") - assert self.console.log.lines[-3:] == ["first", "second", "third"] - - 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") - assert self.console.log.lines == [ - "A 0", - "B 0", - "A 1", - "B 1", - "A 2", - "B 2", - "b func done", - ] - - @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 filter_inner_text(inner_text) - - def test_async_display_untargeted(self): - self.pyscript_run( - """ - - """ - ) - self.wait_for_console("DONE") - 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 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 - executed. That's why the console.log() inside mytask1 and mytask2 are - executed after e.g. js.console.log("6"). - """ - src = """ - - - - - - - - """ - self.pyscript_run(src, wait_for_pyscript=False) - self.wait_for_console("DONE") - lines = self.console.log.lines[-11:] - assert lines == ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "DONE"] diff --git a/pyscript.core/tests/integration/test_importmap.py b/pyscript.core/tests/integration/test_importmap.py deleted file mode 100644 index 17ba21aaeb4..00000000000 --- a/pyscript.core/tests/integration/test_importmap.py +++ /dev/null @@ -1,66 +0,0 @@ -import pytest - -from .support import PyScriptTest - - -@pytest.mark.xfail(reason="See PR #938") -class TestImportmap(PyScriptTest): - def test_importmap(self): - src = """ - export function say_hello(who) { - console.log("hello from", who); - } - """ - self.writefile("mymod.js", src) - # - self.pyscript_run( - """ - - - - - - """ - ) - assert self.console.log.lines == [ - "hello from JS", - "hello from Python", - ] - - def test_invalid_json(self): - self.pyscript_run( - """ - - - - """, - wait_for_pyscript=False, - ) - # this error is raised by the browser itself, when *it* tries to parse - # the import map - self.check_js_errors("Failed to parse import map") - - self.wait_for_pyscript() - assert self.console.log.lines == [ - "hello world", - ] - # this warning is shown by pyscript, when *we* try to parse the import - # map - banner = self.page.locator(".py-warning") - assert "Failed to parse import map" in banner.inner_text() diff --git a/pyscript.core/tests/integration/test_interpreter.py b/pyscript.core/tests/integration/test_interpreter.py deleted file mode 100644 index d7147208c64..00000000000 --- a/pyscript.core/tests/integration/test_interpreter.py +++ /dev/null @@ -1,98 +0,0 @@ -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""" - - def test_interpreter_python_access(self): - self.pyscript_run( - """ - - """ - ) - - self.run_js( - """ - const x = await pyscript.interpreter.globals.get('x'); - const py_func = await pyscript.interpreter.globals.get('py_func'); - const py_func_res = await py_func(); - console.log(`x is ${x}`); - console.log(`py_func() returns ${py_func_res}`); - """ - ) - assert self.console.log.lines[-2:] == [ - "x is 1", - "py_func() returns 2", - ] - - def test_interpreter_script_execution(self): - """Test running Python code from js via pyscript.interpreter""" - self.pyscript_run("") - - self.run_js( - """ - const interface = pyscript.interpreter._remote.interface; - await interface.runPython('print("Interpreter Ran This")'); - """ - ) - - expected_message = "Interpreter Ran This" - assert self.console.log.lines[-1] == expected_message - - py_terminal = self.page.wait_for_selector("py-terminal") - assert py_terminal.text_content() == expected_message - - def test_backward_compatibility_runtime_script_execution(self): - """Test running Python code from js via pyscript.runtime""" - self.pyscript_run("") - - self.run_js( - """ - const interface = pyscript.runtime._remote.interpreter; - await interface.runPython('print("Interpreter Ran This")'); - """ - ) - - expected_message = "Interpreter Ran This" - assert self.console.log.lines[-1] == expected_message - - py_terminal = self.page.wait_for_selector("py-terminal") - assert py_terminal.text_content() == expected_message - - def test_backward_compatibility_runtime_python_access(self): - """Test accessing Python objects from JS via pyscript.runtime""" - self.pyscript_run( - """ - - """ - ) - - self.run_js( - """ - const x = await pyscript.interpreter.globals.get('x'); - const py_func = await pyscript.interpreter.globals.get('py_func'); - const py_func_res = await py_func(); - console.log(`x is ${x}`); - console.log(`py_func() returns ${py_func_res}`); - """ - ) - - assert self.console.log.lines[-2:] == [ - "x is 1", - "py_func() returns 2", - ] diff --git a/pyscript.core/tests/integration/test_plugins.py b/pyscript.core/tests/integration/test_plugins.py deleted file mode 100644 index 8ee707389b6..00000000000 --- a/pyscript.core/tests/integration/test_plugins.py +++ /dev/null @@ -1,419 +0,0 @@ -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 -from js import console - -plugin = Plugin('py-upper') - -console.log("py_upper Plugin loaded") - -@plugin.register_custom_element('py-up') -class Upper: - def __init__(self, element): - self.element = element - - def connect(self): - console.log("Upper plugin connected") - return self.element.originalInnerHTML.upper() -""" - -# Source of a plugin hooks into the PyScript App lifecycle events -HOOKS_PLUGIN_CODE = """ -from pyscript import Plugin -from js import console - -class TestLogger(Plugin): - def configure(self, config): - console.log('configure called') - - def beforeLaunch(self, config): - console.log('beforeLaunch called') - - def afterSetup(self, config): - console.log('afterSetup called') - - def afterStartup(self, config): - console.log('afterStartup called') - - def beforePyScriptExec(self, interpreter, src, pyScriptTag): - console.log(f'beforePyScriptExec called') - console.log(f'before_src:{src}') - - def afterPyScriptExec(self, interpreter, src, pyScriptTag, result): - console.log(f'afterPyScriptExec called') - console.log(f'after_src:{src}') - - def onUserError(self, config): - console.log('onUserError called') - - -plugin = TestLogger() -""" - -# Source of script that defines a plugin with only beforePyScriptExec and -# afterPyScriptExec methods -PYSCRIPT_HOOKS_PLUGIN_CODE = """ -from pyscript import Plugin -from js import console - -class ExecTestLogger(Plugin): - - async def beforePyScriptExec(self, interpreter, src, pyScriptTag): - console.log(f'beforePyScriptExec called') - console.log(f'before_src:{src}') - - async def afterPyScriptExec(self, interpreter, src, pyScriptTag, result): - console.log(f'afterPyScriptExec called') - console.log(f'after_src:{src}') - console.log(f'result:{result}') - - -plugin = ExecTestLogger() -""" - -# Source of script that defines a plugin with only beforePyScriptExec and -# afterPyScriptExec methods -PYREPL_HOOKS_PLUGIN_CODE = """ -from pyscript import Plugin -from js import console - -console.warn("This is in pyrepl hooks file") - -class PyReplTestLogger(Plugin): - - def beforePyReplExec(self, interpreter, src, outEl, pyReplTag): - console.log(f'beforePyReplExec called') - console.log(f'before_src:{src}') - - def afterPyReplExec(self, interpreter, src, outEl, pyReplTag, result): - console.log(f'afterPyReplExec called') - console.log(f'after_src:{src}') - console.log(f'result:{result}') - - -plugin = PyReplTestLogger() -""" - -# Source of a script that doesn't call define a `plugin` attribute -NO_PLUGIN_CODE = """ -from pyscript import Plugin -from js import console - -class TestLogger(Plugin): - pass -""" - -# Source code of a simple plugin that creates a Custom Element for testing purposes -CODE_CE_PLUGIN_BAD_RETURNS = """ -from pyscript import Plugin -from js import console - -plugin = Plugin('py-broken') - -@plugin.register_custom_element('py-up') -class Upper: - def __init__(self, element): - self.element = element - - def connect(self): - # Just returning something... anything other than a string should be ignore - return Plugin -""" -HTML_TEMPLATE_WITH_TAG = """ - - plugins = [ - "./{plugin_name}.py" - ] - - - <{tagname}> - {html} - -""" -HTML_TEMPLATE_NO_TAG = """ - - plugins = [ - "./{plugin_name}.py" - ] - -""" - - -def prepare_test( - plugin_name, code, tagname="", html="", template=HTML_TEMPLATE_WITH_TAG -): - """ - Prepares the test by writing a new plugin file named `plugin_name`.py, with `code` as its - content and run `pyscript_run` on `template` formatted with the above inputs to create the - page HTML code. - - For example: - - >> @prepare_test('py-upper', CE_PLUGIN_CODE, tagname='py-up', html="Hello World") - >> def my_foo(...): - >> ... - - will: - - * write a new `py-upper.py` file to the FS - * the contents of `py-upper.py` is equal to CE_PLUGIN_CODE - * call self.pyscript_run with the following string: - ''' - - plugins = [ - "./py-upper.py" - ] - - - - {html} - - ''' - * call `my_foo` just like a normal decorator would - - """ - - def dec(f): - def _inner(self, *args, **kws): - self.writefile(f"{plugin_name}.py", code) - page_html = template.format( - plugin_name=plugin_name, tagname=tagname, html=html - ) - self.pyscript_run(page_html) - return f(self, *args, **kws) - - return _inner - - return dec - - -class TestPlugin(PyScriptTest): - @skip_worker("FIXME: relative paths") - @prepare_test("py-upper", CE_PLUGIN_CODE, tagname="py-up", html="Hello World") - def test_py_plugin_inline(self): - """Test that a regular plugin that returns new HTML content from connected works""" - # GIVEN a plugin that returns the all caps version of the tag innerHTML and logs text - # during it's execution/hooks - - # EXPECT the plugin logs to be present in the console logs - log_lines = self.console.log.lines - for log_line in ["py_upper Plugin loaded", "Upper plugin connected"]: - assert log_line in log_lines - - # EXPECT the inner text of the Plugin CustomElement to be all caps - rendered_text = self.page.locator("py-up").inner_text() - assert rendered_text == "HELLO WORLD" - - @skip_worker("FIXME: relative paths") - @prepare_test("hooks_logger", HOOKS_PLUGIN_CODE, template=HTML_TEMPLATE_NO_TAG) - def test_execution_hooks(self): - """Test that a Plugin that hooks into the PyScript App events, gets called - for each one of them""" - # GIVEN a plugin that logs specific strings for each app execution event - hooks_available = ["afterSetup", "afterStartup"] - hooks_unavailable = [ - "configure", - "beforeLaunch", - "beforePyScriptExec", - "afterPyScriptExec", - "beforePyReplExec", - "afterPyReplExec", - ] - - # EXPECT it to log the correct logs for the events it intercepts - log_lines = self.console.log.lines - num_calls = { - method: log_lines.count(f"{method} called") for method in hooks_available - } - expected_calls = {method: 1 for method in hooks_available} - assert num_calls == expected_calls - - # EXPECT it to NOT be called (hence not log anything) the events that happen - # before it's ready, hence is not called - unavailable_called = { - method: f"{method} called" in log_lines for method in hooks_unavailable - } - assert unavailable_called == {method: False for method in hooks_unavailable} - - # TODO: It'd be actually better to check that the events get called in order - - @skip_worker("FIXME: relative paths") - @prepare_test( - "exec_test_logger", - PYSCRIPT_HOOKS_PLUGIN_CODE, - 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("script") is not None - - log_lines: list[str] = self.console.log.lines - - assert "beforePyScriptExec called" in log_lines - assert "afterPyScriptExec called" in log_lines - - # These could be made better with a utility function that found log lines - # that match a filter function, or start with something - assert "before_src:x=2; x" in log_lines - assert "after_src:x=2; x" in log_lines - assert "result:2" in log_lines - - @skip_worker("FIXME: relative paths") - @prepare_test( - "pyrepl_test_logger", - PYREPL_HOOKS_PLUGIN_CODE, - template=HTML_TEMPLATE_NO_TAG + "\nx=2; x", - ) - def test_pyrepl_exec_hooks(self): - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - # allow afterPyReplExec to also finish before the test finishes - self.wait_for_console("result:2") - - log_lines: list[str] = self.console.log.lines - - assert "beforePyReplExec called" in log_lines - assert "afterPyReplExec called" in log_lines - - # These could be made better with a utility function that found log lines - # that match a filter function, or start with something - assert "before_src:x=2; x" in log_lines - assert "after_src:x=2; x" in log_lines - assert "result:2" in log_lines - - @skip_worker("FIXME: relative paths") - @prepare_test("no_plugin", NO_PLUGIN_CODE) - def test_no_plugin_attribute_error(self): - """ - Test a plugin that do not add the `plugin` attribute to its module - """ - # GIVEN a Plugin NO `plugin` attribute in it's module - error_msg = ( - "[pyscript/main] Cannot find plugin on Python module no_plugin! Python plugins " - 'modules must contain a "plugin" attribute. For more information check the ' - "plugins documentation." - ) - # EXPECT an error for the missing attribute - assert error_msg in self.console.error.lines - - @skip_worker("FIXME: relative paths") - def test_fetch_python_plugin(self): - """ - Test that we can fetch a plugin from a remote URL. Note we need to use - the 'raw' URL for the plugin, otherwise the request will be rejected - by cors policy. - """ - self.pyscript_run( - """ - - plugins = [ - "https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/python/hello-world.py" - ] - - - - """ - ) - - hello_element = self.page.locator("py-hello-world") - assert hello_element.inner_html() == '
Hello World!
' - - def test_fetch_js_plugin(self): - self.pyscript_run( - """ - - plugins = [ - "https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world.js" - ] - - """ - ) - - hello_element = self.page.locator("py-hello-world") - assert hello_element.inner_html() == "

Hello, world!

" - - def test_fetch_js_plugin_bare(self): - self.pyscript_run( - """ - - plugins = [ - "https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world-base.js" - ] - - """ - ) - - hello_element = self.page.locator("py-hello-world") - assert hello_element.inner_html() == "

Hello, world!

" - - def test_fetch_plugin_no_file_extension(self): - self.pyscript_run( - """ - - plugins = [ - "https://non-existent.blah/hello-world" - ] - - """, - wait_for_pyscript=False, - ) - - expected_msg = ( - "(PY2000): Unable to load plugin from " - "'https://non-existent.blah/hello-world'. Plugins " - "need to contain a file extension and be either a " - "python or javascript file." - ) - - assert self.assert_banner_message(expected_msg) - - def test_fetch_js_plugin_non_existent(self): - self.pyscript_run( - """ - - plugins = [ - "http://non-existent.example.com/hello-world.js" - ] - - """, - wait_for_pyscript=False, - ) - - expected_msg = ( - "(PY0001): Fetching from URL " - "http://non-existent.example.com/hello-world.js failed " - "with error 'Failed to fetch'. Are your filename and " - "path correct?" - ) - - assert self.assert_banner_message(expected_msg) - - def test_fetch_js_no_export(self): - self.pyscript_run( - """ - - plugins = [ - "https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world-no-export.js" - ] - - """, - wait_for_pyscript=False, - ) - - expected_message = ( - "(PY2001): Unable to load plugin from " - "'https://raw.githubusercontent.com/FabioRosado/pyscript-plugins" - "/main/js/hello-world-no-export.js'. " - "Plugins need to contain a default export." - ) - - assert self.assert_banner_message(expected_message) diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py deleted file mode 100644 index 089d35a3205..00000000000 --- a/pyscript.core/tests/integration/test_py_config.py +++ /dev/null @@ -1,215 +0,0 @@ -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 - - def test_ambiguous_py_config(self): - self.pyscript_run( - """ - name = "first" - - - """, - wait_for_pyscript=False, - ) - banner = self.page.wait_for_selector(".py-error") - expected = "(PY0409): Ambiguous py-config VS config attribute" - assert banner.text_content() == expected - - def test_multiple_attributes_py_config(self): - self.pyscript_run( - """ - - - """, - wait_for_pyscript=False, - ) - banner = self.page.wait_for_selector(".py-error") - expected = "(PY0409): Unable to use different configs on main" - assert banner.text_content() == expected - - def test_multiple_py_config(self): - self.pyscript_run( - """ - - name = "foobar" - - - - name = "this is ignored" - - - - """, - wait_for_pyscript=False, - ) - banner = self.page.wait_for_selector(".py-error") - expected = "(PY0409): Too many py-config" - 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/pyscript.core/tests/integration/test_py_repl.py b/pyscript.core/tests/integration/test_py_repl.py deleted file mode 100644 index c9687dc9030..00000000000 --- a/pyscript.core/tests/integration/test_py_repl.py +++ /dev/null @@ -1,663 +0,0 @@ -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): - """ - Clear the editor and write new code in it. - WARNING: this assumes that the textbox has already the focus - """ - # clear the editor, write new code - if "macOS" in platform.platform(): - self.page.keyboard.press("Meta+A") - else: - self.page.keyboard.press("Control+A") - - self.page.keyboard.press("Backspace") - self.page.keyboard.type(newcode) - - def test_repl_loads(self): - self.pyscript_run( - """ - - """ - ) - py_repl = self.page.query_selector("py-repl .py-repl-box") - assert py_repl - - def test_execute_preloaded_source(self): - """ - Unfortunately it tests two things at once, but it's impossible to write a - smaller test. I think this is the most basic test that we can write. - - We test that: - 1. the source code that we put in the tag is loaded inside the editor - 2. clicking the button executes it - """ - self.pyscript_run( - """ - - print('hello from py-repl') - - """ - ) - py_repl = self.page.locator("py-repl") - src = py_repl.locator("div.cm-content").inner_text() - assert "print('hello from py-repl')" in src - py_repl.locator("button").click() - self.page.wait_for_selector("py-terminal") - assert self.console.log.lines[-1] == "hello from py-repl" - - def test_execute_code_typed_by_the_user(self): - self.pyscript_run( - """ - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.type('print("hello")') - py_repl.locator("button").click() - self.page.wait_for_selector("py-terminal") - assert self.console.log.lines[-1] == "hello" - - def test_execute_on_shift_enter(self): - self.pyscript_run( - """ - - print("hello world") - - """ - ) - self.page.wait_for_selector("py-repl .py-repl-run-button") - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("py-terminal") - - assert self.console.log.lines[-1] == "hello world" - - # Shift-enter should not add a newline to the editor - assert self.page.locator(".cm-line").count() == 1 - - @skip_worker("FIXME: display()") - def test_display(self): - self.pyscript_run( - """ - - display('hello world') - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "hello world" - - @skip_worker("TIMEOUT") - def test_show_last_expression(self): - """ - Test that we display() the value of the last expression, as you would - expect by a REPL - """ - self.pyscript_run( - """ - - 42 - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "42" - - @skip_worker("TIMEOUT") - def test_show_last_expression_with_output(self): - """ - Test that we display() the value of the last expression, as you would - expect by a REPL - """ - self.pyscript_run( - """ -
- - 42 - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - out_div = py_repl.locator("div.py-repl-output") - assert out_div.all_inner_texts()[0] == "" - - out_div = self.page.wait_for_selector("#repl-target") - assert out_div.inner_text() == "42" - - @skip_worker("FIXME: display()") - def test_run_clears_previous_output(self): - """ - Check that we clear the previous output of the cell before executing it - again - """ - self.pyscript_run( - """ - - display('hello world') - - """ - ) - py_repl = self.page.locator("py-repl") - self.page.keyboard.press("Shift+Enter") - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "hello world" - # clear the editor, write new code, execute - self._replace(py_repl, "display('another output')") - self.page.keyboard.press("Shift+Enter") - # test runner can be too fast, the line below should wait for output to change - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "another output" - - def test_python_exception(self): - """ - See also test01_basic::test_python_exception, since it's very similar - """ - self.pyscript_run( - """ - - raise Exception('this is an error') - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - self.page.wait_for_selector(".py-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 - err_pre = py_repl.locator("div.py-repl-output > pre.py-error") - tb_lines = err_pre.inner_text().splitlines() - assert tb_lines[0] == "Traceback (most recent call last):" - assert tb_lines[-1] == "Exception: this is an error" - # - self.check_py_errors("this is an error") - - @skip_worker("FIXME: display()") - def test_multiple_repls(self): - """ - Multiple repls showing in the correct order in the page - """ - self.pyscript_run( - """ - display("first") - display("second") - """ - ) - first_py_repl = self.page.get_by_text("first") - first_py_repl.click() - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-0-repl-output") - assert self.page.inner_text("#py-internal-0-repl-output") == "first" - - second_py_repl = self.page.get_by_text("second") - second_py_repl.click() - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-1-repl-output") - assert self.page.inner_text("#py-internal-1-repl-output") == "second" - - @skip_worker("FIXME: display()") - def test_python_exception_after_previous_output(self): - self.pyscript_run( - """ - - display('hello world') - - """ - ) - py_repl = self.page.locator("py-repl") - self.page.keyboard.press("Shift+Enter") - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "hello world" - # - # clear the editor, write new code, execute - self._replace(py_repl, "0/0") - self.page.keyboard.press("Shift+Enter") - # test runner can be too fast, the line below should wait for output to change - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert "hello world" not in out_div.inner_text() - assert "ZeroDivisionError" in out_div.inner_text() - # - self.check_py_errors("ZeroDivisionError") - - @skip_worker("FIXME: js.document") - def test_hide_previous_error_after_successful_run(self): - """ - this tests the fact that a new error div should be created once there's an - error but also that it should disappear automatically once the error - is fixed - """ - self.pyscript_run( - """ - - raise Exception('this is an error') - - """ - ) - py_repl = self.page.locator("py-repl") - self.page.keyboard.press("Shift+Enter") - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert "this is an error" in out_div.inner_text() - # - self._replace(py_repl, "display('hello')") - self.page.keyboard.press("Shift+Enter") - # test runner can be too fast, the line below should wait for output to change - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "hello" - # - self.check_py_errors("this is an error") - - def test_output_attribute_does_not_exist(self): - """ - If we try to use an attribute which doesn't exist, we display an error - instead - """ - self.pyscript_run( - """ - - print('I will not be executed') - - """ - ) - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - banner = self.page.wait_for_selector(".py-warning") - - banner_content = banner.inner_text() - expected = ( - 'output = "I-dont-exist" does not match the id of any element on the page.' - ) - assert banner_content == expected - - @skip_worker("TIMEOUT") - def test_auto_generate(self): - self.pyscript_run( - """ - - - """ - ) - py_repls = self.page.locator("py-repl") - outputs = py_repls.locator("div.py-repl-output") - assert py_repls.count() == 1 - assert outputs.count() == 1 - # - # evaluate the py-repl, and wait for the newly generated one - self.page.keyboard.type("'hello'") - self.page.keyboard.press("Shift+Enter") - self.page.locator('py-repl[exec-id="1"]').wait_for() - assert py_repls.count() == 2 - assert outputs.count() == 2 - # - # now we type something else: the new py-repl should have the focus - self.page.keyboard.type("'world'") - self.page.keyboard.press("Shift+Enter") - self.page.locator('py-repl[exec-id="2"]').wait_for() - assert py_repls.count() == 3 - assert outputs.count() == 3 - # - # check that the code and the outputs are in order - out_texts = [el.inner_text() for el in self.iter_locator(outputs)] - assert out_texts == ["hello", "world", ""] - - @skip_worker("FIXME: display()") - def test_multiple_repls_mixed_display_order(self): - """ - Displaying several outputs that don't obey the order in which the original - repl displays were created using the auto_generate attr - """ - self.pyscript_run( - """ - display("root first") - display("root second") - """ - ) - - second_py_repl = self.page.get_by_text("root second") - second_py_repl.click() - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-1-repl-output") - self.page.keyboard.type("display('second children')") - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-1-1-repl-output") - - first_py_repl = self.page.get_by_text("root first") - first_py_repl.click() - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-0-repl-output") - self.page.keyboard.type("display('first children')") - self.page.keyboard.press("Shift+Enter") - self.page.wait_for_selector("#py-internal-0-1-repl-output") - - assert self.page.inner_text("#py-internal-1-1-repl-output") == "second children" - assert self.page.inner_text("#py-internal-0-1-repl-output") == "first children" - - @skip_worker("FIXME: display()") - def test_repl_output_attribute(self): - # Test that output attribute sends stdout to the element - # with the given ID, but not display() - self.pyscript_run( - """ -
- - print('print from py-repl') - display('display from py-repl') - - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - target = self.page.wait_for_selector("#repl-target") - assert "print from py-repl" in target.inner_text() - - out_div = self.page.wait_for_selector("#py-internal-0-repl-output") - assert out_div.inner_text() == "display from py-repl" - - self.assert_no_banners() - - @skip_worker("FIXME: js.document") - def test_repl_output_display_async(self): - # py-repls running async code are not expected to - # send display to element element - self.pyscript_run( - """ -
- - - - asyncio.ensure_future(print_it()); - asyncio.ensure_future(display_it()); - asyncio.ensure_future(done()); - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - self.wait_for_console("DONE") - - assert self.page.locator("#repl-target").text_content() == "" - self.assert_no_banners() - - @skip_worker("FIXME: js.document") - def test_repl_stdio_dynamic_tags(self): - self.pyscript_run( - """ -
-
- - import js - - print("first.") - - # Using string, since no clean way to write to the - # code contents of the CodeMirror in a PyRepl - newTag = 'print("second.")' - js.document.body.innerHTML += newTag - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - assert self.page.wait_for_selector("#first").inner_text() == "first.\n" - - second_repl = self.page.locator("py-repl#second-repl") - second_repl.locator("button").click() - assert self.page.wait_for_selector("#second").inner_text() == "second.\n" - - def test_repl_output_id_errors(self): - self.pyscript_run( - """ - - print("bad.") - print("bad.") - - - - print("bad.") - - """ - ) - py_repls = self.page.query_selector_all("py-repl") - for repl in py_repls: - repl.query_selector_all("button")[0].click() - - banner = self.page.wait_for_selector(".py-warning") - - banner_content = banner.inner_text() - expected = ( - 'output = "not-on-page" does not match the id of any element on the page.' - ) - - assert banner_content == expected - - def test_repl_stderr_id_errors(self): - self.pyscript_run( - """ - - import sys - print("bad.", file=sys.stderr) - print("bad.", file=sys.stderr) - - - - print("bad.", file=sys.stderr) - - """ - ) - py_repls = self.page.query_selector_all("py-repl") - for repl in py_repls: - repl.query_selector_all("button")[0].click() - - banner = self.page.wait_for_selector(".py-warning") - - banner_content = banner.inner_text() - expected = ( - 'stderr = "not-on-page" does not match the id of any element on the page.' - ) - - assert banner_content == expected - - def test_repl_output_stderr(self): - # Test that stderr works, and routes to the same location as stdout - # Also, repls with the stderr attribute route to an additional location - self.pyscript_run( - """ -
-
- - import sys - print("one.", file=sys.stderr) - print("two.") - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - assert self.page.wait_for_selector("#stdout-div").inner_text() == "one.\ntwo.\n" - assert self.page.wait_for_selector("#stderr-div").inner_text() == "one.\n" - self.assert_no_banners() - - @skip_worker("TIMEOUT") - def test_repl_output_attribute_change(self): - # If the user changes the 'output' attribute of a tag mid-execution, - # Output should no longer go to the selected div and a warning should appear - self.pyscript_run( - """ -
-
- - - print("one.") - - # Change the 'output' attribute of this tag - import js - this_tag = js.document.getElementById("repl-tag") - - this_tag.setAttribute("output", "second") - print("two.") - - this_tag.setAttribute("output", "third") - print("three.") - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - assert self.page.wait_for_selector("#first").inner_text() == "one.\n" - assert self.page.wait_for_selector("#second").inner_text() == "two.\n" - - expected_alert_banner_msg = ( - 'output = "third" does not match the id of any element on the page.' - ) - - alert_banner = self.page.wait_for_selector(".alert-banner") - assert expected_alert_banner_msg in alert_banner.inner_text() - - @skip_worker("TIMEOUT") - def test_repl_output_element_id_change(self): - # If the user changes the ID of the targeted DOM element mid-execution, - # Output should no longer go to the selected element and a warning should appear - self.pyscript_run( - """ -
-
- - - print("one.") - - # Change the ID of the targeted DIV to something else - import js - target_tag = js.document.getElementById("first") - - # should fail and show banner - target_tag.setAttribute("id", "second") - print("two.") - - # But changing both the 'output' attribute and the id of the target - # should work - target_tag.setAttribute("id", "third") - js.document.getElementById("pyscript-tag").setAttribute("output", "third") - print("three.") - - """ - ) - - py_repl = self.page.locator("py-repl") - py_repl.locator("button").click() - - # Note the ID of the div has changed by the time of this assert - assert self.page.wait_for_selector("#third").inner_text() == "one.\nthree.\n" - - expected_alert_banner_msg = ( - 'output = "first" does not match the id of any element on the page.' - ) - alert_banner = self.page.wait_for_selector(".alert-banner") - assert expected_alert_banner_msg in alert_banner.inner_text() - - def test_repl_load_content_from_src(self): - self.writefile("loadReplSrc1.py", "print('1')") - self.pyscript_run( - """ - -
- """ - ) - successMsg = "[py-repl] loading code from ./loadReplSrc1.py to repl...success" - assert self.console.info.lines[-1] == successMsg - - py_repl = self.page.locator("py-repl") - code = py_repl.locator("div.cm-content").inner_text() - assert "print('1')" in code - - @skip_worker("TIMEOUT") - def test_repl_src_change(self): - self.writefile("loadReplSrc2.py", "2") - self.writefile("loadReplSrc3.py", "print('3')") - self.pyscript_run( - """ - -
- - - import js - target_tag = js.document.getElementById("py-repl2") - target_tag.setAttribute("src", "./loadReplSrc3.py") - -
- """ - ) - - successMsg1 = "[py-repl] loading code from ./loadReplSrc2.py to repl...success" - assert self.console.info.lines[-1] == successMsg1 - - py_repl3 = self.page.locator("py-repl#py-repl3") - py_repl3.locator("button").click() - py_repl2 = self.page.locator("py-repl#py-repl2") - py_repl2.locator("button").click() - self.page.wait_for_selector("py-terminal") - assert self.console.log.lines[-1] == "3" - - successMsg2 = "[py-repl] loading code from ./loadReplSrc3.py to repl...success" - assert self.console.info.lines[-1] == successMsg2 - - def test_repl_src_path_that_do_not_exist(self): - self.pyscript_run( - """ - -
- """ - ) - errorMsg = ( - "(PY0404): Fetching from URL ./loadReplSrc4.py " - "failed with error 404 (Not Found). " - "Are your filename and path correct?" - ) - assert self.console.error.lines[-1] == errorMsg diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py deleted file mode 100644 index 8e5e3395860..00000000000 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ /dev/null @@ -1,187 +0,0 @@ -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 sequences. 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/pyscript.core/tests/integration/test_script_type.py b/pyscript.core/tests/integration/test_script_type.py deleted file mode 100644 index b52b9e49b6b..00000000000 --- a/pyscript.core/tests/integration/test_script_type.py +++ /dev/null @@ -1,124 +0,0 @@ -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): - def test_display_line_break(self): - self.pyscript_run( - r""" - - """ - ) - text_content = self.page.locator("script-py").text_content() - assert "hello\nworld" == text_content - - def test_amp(self): - self.pyscript_run( - r""" - - """ - ) - text_content = self.page.locator("script-py").text_content() - assert "a & b" == text_content - - def test_quot(self): - self.pyscript_run( - r""" - - """ - ) - text_content = self.page.locator("script-py").text_content() - assert "a " b" == text_content - - def test_lt_gt(self): - self.pyscript_run( - r""" - - """ - ) - text_content = self.page.locator("script-py").text_content() - assert "< < > >" == text_content - - def test_dynamically_add_script_type_py_tag(self): - self.pyscript_run( - """ - - """ - ) - # please note the test here was on timeout - # incapable of finding a - - """ - ) - self.page.locator("text=foo_button").click() - self.wait_for_console("clicked foo_id") - self.assert_no_banners() - - 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 - """ - self.pyscript_run( - """ - - - """ - ) - self.page.locator("text=foo_button").click() - self.wait_for_console("The button was clicked") - self.assert_no_banners() - - def test_multiple_when_decorators_with_event(self): - self.pyscript_run( - """ - - - - """ - ) - self.page.locator("text=foo_button").click() - self.wait_for_console("foo_click! id=foo_id") - self.page.locator("text=bar_button").click() - self.wait_for_console("bar_click! id=bar_id") - self.assert_no_banners() - - 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("got event: click") - self.assert_no_banners() - - 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("got event: click") - self.assert_no_banners() - - def test_when_decorator_multiple_elements(self): - """The @when decorator's selector should successfully select multiple - DOM elements - """ - self.pyscript_run( - """ - - - - """ - ) - self.page.locator("text=button1").click() - self.page.locator("text=button2").click() - self.wait_for_console("button2 was clicked") - assert "button1 was clicked" in self.console.log.lines - assert "button2 was clicked" in self.console.log.lines - self.assert_no_banners() - - def test_when_decorator_duplicate_selectors(self): - """ """ - self.pyscript_run( - """ - - - """ - ) - self.page.locator("text=foo_button").click() - self.wait_for_console("click 1 on foo_id") - self.wait_for_console("click 2 on foo_id") - self.assert_no_banners() - - @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() - msg = "Failed to execute 'querySelectorAll' on 'Document': '#.bad' is not a valid selector." - error = self.page.wait_for_selector(".py-error") - banner_text = error.inner_text() - - if msg not in banner_text: - raise AssertionError( - f"Expected message '{msg}' does not " - f"match banner text '{banner_text}'" - ) - - assert msg in self.console.error.lines[-1] - self.check_py_errors(msg) diff --git a/pyscript.core/types/3rd-party/xterm.d.ts b/pyscript.core/types/3rd-party/xterm.d.ts deleted file mode 100644 index 636fd9ee850..00000000000 --- a/pyscript.core/types/3rd-party/xterm.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -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/config.d.ts b/pyscript.core/types/config.d.ts deleted file mode 100644 index d9c40f26237..00000000000 --- a/pyscript.core/types/config.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export default configs; -declare const configs: Map; diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts deleted file mode 100644 index 371bfc43bbe..00000000000 --- a/pyscript.core/types/core.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -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}} - */ -declare function exportedPyWorker(file: string, options?: { - config?: string | object; - async?: boolean; -}): Worker & { - sync: ProxyHandler; -}; -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/plugins/py-terminal.d.ts b/pyscript.core/types/plugins/py-terminal.d.ts deleted file mode 100644 index 35a35db464a..00000000000 --- a/pyscript.core/types/plugins/py-terminal.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const _default: Promise; -export default _default; diff --git a/pyscript.core/types/stdlib.d.ts b/pyscript.core/types/stdlib.d.ts deleted file mode 100644 index ae80ecad1b2..00000000000 --- a/pyscript.core/types/stdlib.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index fa33defe76c..00000000000 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 3dd526500ca..00000000000 --- a/pyscript.core/types/sync.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -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.sw/.npmignore b/pyscript.sw/.npmignore deleted file mode 100644 index 51e603f73aa..00000000000 --- a/pyscript.sw/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -rollup/ -src/ -test/ -package-lock.json diff --git a/pyscript.sw/LICENSE b/pyscript.sw/LICENSE deleted file mode 100644 index f1ed3ff0b45..00000000000 --- a/pyscript.sw/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright (c) 2022-present, PyScript Development Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/pyscript.sw/README.md b/pyscript.sw/README.md deleted file mode 100644 index cca1f3711e1..00000000000 --- a/pyscript.sw/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# @pyscript/sw - -**[PyScript](https://github.com/pyscript/pyscript) Service Worker** - ---- - -## Documentation - -This module provides a single, standalone, *script* able to bootstrap a Service Worker which can drive a whole site via Python code. - -Please note the file *must* be available locally and it *must not* be loaded as a module, as a Service Worker is *not a module*. - -### Example - -This is the bare minimal example of an `index.html` file at the root of the site. - -```html - - -``` - - * **src** is where the PyScript Service Worker is located. - * **handler** is where Python code is located. This *must* provide a `handle_request` method that will be invoked per each browsing *fetch* operation. Such method should return a `[body, status, headers]` tuple where *body* is the content of the page, *status* is its *HTTP* status and *headers* contain the `content-type` or any other useful header. - * **config** is an *optional* attribute that indicates packages to load, files to fetch, and all other usual [py-config goodness](https://pyscript.github.io/docs/latest/reference/elements/py-config.html). - * **scope** (advanced use-case) is an *optional* attribute that indicates [where the Service Worker operates](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope). By default it operates from the same folder, and any subfolder, the `pyscript.sw.js` is. - -#### How to update `handle_request` - -Because the Service Worker, once activated, will persist over any further session, it is pretty hard to change its operating handler. - -To do so, there are two options: - - * unregister the Service Worker, clear all browsing data per that domain and hard-refresh the browser - * change and save your `handler.py` file and, once saved, reach the `/pyscript.sw/update_handler` via browser, or run the following code in console: - -```js -fetch('/pyscript.sw/update_handler') - .then(b => b.text()) - .then(console.log, console.error); -``` - -This operation will be intercepted behind the scene and the new file will be parsed. - -The result should be an `OK` response, with status `200`, or an error message with status `500` handled by the `console.error` or visible within the page once reached. diff --git a/pyscript.sw/package-lock.json b/pyscript.sw/package-lock.json deleted file mode 100644 index 557b1ab6dd5..00000000000 --- a/pyscript.sw/package-lock.json +++ /dev/null @@ -1,467 +0,0 @@ -{ - "name": "@pyscript/sw", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@pyscript/sw", - "version": "0.0.1", - "license": "APACHE-2.0", - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.3", - "basic-toml": "^0.3.1", - "rollup": "^3.27.0", - "static-handler": "^0.4.2" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/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/@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==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "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==", - "dev": true, - "dependencies": { - "serialize-javascript": "^6.0.1", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.x || ^3.x" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "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==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "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==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/basic-toml": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/basic-toml/-/basic-toml-0.3.1.tgz", - "integrity": "sha512-O1ywy7Win4Tw215aY/cHyzZXCYlhyzEUbVR+hqkmosBA6Z7ejBcZb3fwDtsirAsd+KADY9A/D3qkbAQ4CqkaHg==", - "dev": true - }, - "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/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "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/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/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "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/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.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/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "3.27.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.1.tgz", - "integrity": "sha512-tXNDFwOkN6C2w5Blj1g6ForKeFw6c1mDu5jxoeDO3/pmYjgt+8yvIFjKzH5FQUq70OKZBkOt0zzv0THXL7vwzQ==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/smob": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.0.tgz", - "integrity": "sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==", - "dev": true - }, - "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.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "mime-types": "^2.1.35" - }, - "bin": { - "static-handler": "static-handler.cjs" - }, - "engines": { - "node": ">=16" - } - }, - "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/terser": { - "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - } - } -} diff --git a/pyscript.sw/package.json b/pyscript.sw/package.json deleted file mode 100644 index a7e83103706..00000000000 --- a/pyscript.sw/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@pyscript/sw", - "version": "0.0.1", - "description": "PyScript Service Worker", - "main": "pyscript.sw.js", - "scripts": { - "server": "npx static-handler .", - "build": "rollup --config rollup/sw.config.mjs" - }, - "keywords": [], - "author": "Anaconda Inc.", - "license": "APACHE-2.0", - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.3", - "basic-toml": "^0.3.1", - "rollup": "^3.27.0", - "static-handler": "^0.4.2" - } -} diff --git a/pyscript.sw/pyscript.sw.js b/pyscript.sw/pyscript.sw.js deleted file mode 100644 index 07078f23761..00000000000 --- a/pyscript.sw/pyscript.sw.js +++ /dev/null @@ -1,3 +0,0 @@ -!function(){"use strict";(({document:e,navigator:{serviceWorker:t}})=>{if(e){const{href:s}=location,{controller:n}=t,{currentScript:a}=e,{src:r,attributes:{config:i,handler:o,scope:c}}=a;n&&n.postMessage({config:i?.value?new URL(i.value,s).href:"",handler:new URL(o.value,s).href}),t.addEventListener("message",(({data:e})=>{"reload"===e&&location.reload()})),t.register(r,{scope:c?.value||"."}).then((e=>{e.addEventListener("updatefound",(()=>location.reload())),e.active&&!n&&location.reload()}))}else{const e="https://cdn.jsdelivr.net/pyodide/v0.23.4/full";importScripts(`${e}/pyodide.js`);const t=async e=>(await Promise.resolve().then((function(){return r}))).parse(e),s=loadPyodide({indexURL:e});addEventListener("install",(()=>skipWaiting())),addEventListener("activate",(e=>e.waitUntil(clients.claim())));let n,a,i=!1,o=new Promise((e=>{addEventListener("message",(async({data:{config:r,handler:o}})=>{if(r){const e=await s,n=[fetch(r),e.loadPackage("micropip")];n[0]=r.endsWith(".json")?n[0].then((e=>e.json())):n[0].then((e=>e.text())).then(t);const[{packages:a}]=await Promise.all(n),i=await e.pyimport("micropip");await i.install(a)}a=o;const l=await c();i=!0;(await clients.get(n)).postMessage("reload"),e(l)}),{once:!0})}));const c=()=>new Promise((async(e,t)=>{const n=await s,r=await fetch(a).then((e=>e.text())),i=n.globals.get("dict")();await n.runPythonAsync(r,{globals:i}).catch(t),e(i.get("handle_request")),i.destroy()}));addEventListener("fetch",(e=>{if(n||(n=e.clientId),i)if("/pyscript.sw/update_handler"===new URL(e.request.url).pathname){const t=c();e.respondWith(t.then((()=>(o=t,new Response("OK",{headers:{"content-type":"text/plain"},status:200}))),(e=>new Response(e.message,{headers:{"content-type":"text/plain"},status:500}))))}else e.respondWith(o.then((async t=>{const[s,n,a]=await t(e.request);return new Response(s,{headers:a,status:n})})))}))}})(self); -/*! (c) Andrea Giammarchi - ISC */ -const{isArray:e}=Array,{parse:t}=JSON,s=(e,{s:t})=>e.replace(/"s(\d+)"/g,((e,s)=>t[s])),n=(e,s)=>t(e.replace(/(\S+?)\s*=/g,'"$1":'),((e,t)=>"string"==typeof t?s[t[0]][t.slice(1)]:t)),a=(t,n,a,r)=>{for(let i=0,{length:o}=t,c=o-1;i{const[t,r]=((e,t,s)=>[e.replace(/(["'])(?:(?=(\\?))\2.)*?\1/g,(e=>`"s${t.push(e.slice(1,-1))-1}"`)).replace(/\d{2,}([:-]\d{2}){2}([ T:-][\dZ:-]+)?/g,(e=>`"d${s.push(new Date(e))-1}"`)).replace(/,\s*[\r\n]+/g,", ").replace(/\[\s*[\r\n]+/g,"[").replace(/[\r\n]+\s*]/g,"]"),{s:t,d:s}])(e,[],[]),i={};let o=i;for(let e of t.split(/[\r\n]+/))if((e=e.trim())&&!e.startsWith("#"))if(/^(\[+)(.*?)\]+/.test(e))o=a(RegExp.$2.trim().split("."),r,i,"["!==RegExp.$1);else if(/^(\S+?)\s*=([^#]+)/.test(e)){const{$1:e,$2:t}=RegExp;o[s(e,r)]=n(t.trim(),r)}return i}})}(); diff --git a/pyscript.sw/rollup/sw.config.mjs b/pyscript.sw/rollup/sw.config.mjs deleted file mode 100644 index 9c3b73f5a7e..00000000000 --- a/pyscript.sw/rollup/sw.config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -// This file generates /core.js minified version of the module, which is -// the default exported as npm entry. - -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import terser from "@rollup/plugin-terser"; - -export default { - input: "./src/sw.js", - plugins: process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()], - output: { - esModule: false, - inlineDynamicImports: true, - file: "./pyscript.sw.js", - format: "iife", - }, -}; diff --git a/pyscript.sw/src/sw.js b/pyscript.sw/src/sw.js deleted file mode 100644 index ac21f60643d..00000000000 --- a/pyscript.sw/src/sw.js +++ /dev/null @@ -1,154 +0,0 @@ -// NOTE: this file must be a single JS file so that we can distribute it -// as standalone "one-shop" entry for the Service Worker, i.e.: -// - -// prevent global scope pollution with local references -// this callback works in both the main page and in the SW -(({ document, navigator: { serviceWorker } }) => { - // here we are on the main page - if (document) { - const { href } = location; - const { controller } = serviceWorker; - - const { currentScript } = document; - const { - src, - attributes: { config, handler, scope }, - } = currentScript; - - // send files to fetch and handle to the Service Worker - // after resolving the path through current page location - // (not the service worker one as these likely have different relative folders) - if (controller) { - controller.postMessage({ - config: config?.value ? new URL(config.value, href).href : "", - // handler is mandatory (or it means there's nothing to run as Python) - handler: new URL(handler.value, href).href, - }); - } - - // do reload automatically once everything has been bootstrapped - serviceWorker.addEventListener("message", ({ data }) => { - if (data === "reload") location.reload(); - }); - - // register the Service Worker with an optional scope ... - serviceWorker - .register(src, { scope: scope?.value || "." }) - .then((registration) => { - // ... once registered, let the SW automatically handle the page reload - registration.addEventListener("updatefound", () => - location.reload(), - ); - if (registration.active && !controller) location.reload(); - }); - } - // here we are on the Service Worker - else { - const indexURL = "https://cdn.jsdelivr.net/pyodide/v0.23.4/full"; - - // because of this issue https://github.com/w3c/ServiceWorker/issues/1356 - // the pyodide must be loaded sync ASAP or `importScripts` will fail - importScripts(`${indexURL}/pyodide.js`); - - // ⚠️ WARNING: this will be inlined by rollup - can't be used AS IS - const parse = async (text) => (await import('basic-toml')).parse(text); - - // this is still not blocking so no problems should happen ... we can bring anything - // directly from the CDN at this point, as pyodide is flagged as secure script here - const interpreter = loadPyodide({ indexURL }); - - // skip waiting on installation and ensure activation - // this will trigger the automatic reload on the main page - // once the Service Worker is ready to operate - addEventListener("install", () => skipWaiting()); - addEventListener("activate", (e) => e.waitUntil(clients.claim())); - - let // used to postMessage a reload when everything is ready - clientId, - // keeps the handler path known for future updates - handlerPath, - // let fetch operations through until there is a handler - handleReady = false, - // wait for the postMessage to communicate where is the python file - // and where is the config, if any - handleRequest = new Promise(resolve => { - addEventListener( - "message", - async ({ data: { config, handler } }) => { - if (config) { - const pyodide = await interpreter; - const deps = [ - fetch(config), - pyodide.loadPackage("micropip"), - ]; - - // assign the right body retriever accordingly - // with the config extension - deps[0] = config.endsWith(".json") ? - deps[0].then((b) => b.json()) : - deps[0].then((b) => b.text()).then(parse); - - const [{ packages }] = await Promise.all(deps); - const micropip = await pyodide.pyimport("micropip"); - await micropip.install(packages); - } - handlerPath = handler; - const result = await getHandler(); - handleReady = true; - const client = await clients.get(clientId); - client.postMessage("reload"); - resolve(result); - }, - { once: true }, - ); - }); - - // used to update the handler when '/pyscript.sw/update_handler' - // path is reached and the service worker is already initialized - const getHandler = () => new Promise(async (resolve, reject) => { - const pyodide = await interpreter; - const code = await fetch(handlerPath).then(b => b.text()); - const globals = pyodide.globals.get("dict")(); - await pyodide.runPythonAsync(code, { globals }).catch(reject); - resolve(globals.get("handle_request")); - globals.destroy(); - }); - - addEventListener("fetch", (event) => { - if (!clientId) clientId = event.clientId; - if (!handleReady) return; - // this switch is to allow possible future operations too - switch (new URL(event.request.url).pathname) { - // reserved: this is our namespace to operate internally - case '/pyscript.sw/update_handler': - const newHandler = getHandler(); - event.respondWith(newHandler.then( - () => { - // only if successful the handleRequest is re-assigned - handleRequest = newHandler; - return new Response('OK', { - headers: {'content-type': 'text/plain'}, - status: 200 - }); - }, - error => new Response(error.message, { - headers: {'content-type': 'text/plain'}, - status: 500 - }) - )); - break; - default: - event.respondWith( - handleRequest.then(async (handler) => { - const [text, status, headers] = await handler( - event.request, - ); - return new Response(text, { headers, status }); - }), - ); - break; - } - }); - } -})(self); diff --git a/pyscript.sw/test/index.html b/pyscript.sw/test/index.html deleted file mode 100644 index 48b17461b4b..00000000000 --- a/pyscript.sw/test/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - Loading PyScript Service Worker - - diff --git a/pyscript.sw/test/test.py b/pyscript.sw/test/test.py deleted file mode 100644 index ccde1f71e94..00000000000 --- a/pyscript.sw/test/test.py +++ /dev/null @@ -1,59 +0,0 @@ -import random - -from fastapi import FastAPI -from fastapi.responses import HTMLResponse -from httpx import AsyncClient - -app = FastAPI() - -base = "/test" - - -def generate_html_response(): - html_content = """ - - - - PyScript Service Worker - - -

PyScript from a service worker 🦄

-

FastAPI demo

-
    -
  • Test some random json
  • -
  • Test some random emoji
  • -
- - - """ - - return HTMLResponse(content=html_content, status_code=200) - - -@app.get(base + "/", response_class=HTMLResponse) -async def root(): - return generate_html_response() - - -# used to test errors forwarded as 500 -# shenanigans(1, 2, 3) - - -@app.get(base + "/json") -async def json(): - # used to test that file changes actually happen when - # '/pyscript.sw/update_handler' is reached - # print(base + "/json") - return {"message": random.choice(["Hello World", "Bonjour le monde", "Hola Mundo"])} - - -@app.get(base + "/emoji") -async def emoji(): - return {"emoji": random.choice(["👋", "👋🏻", "👋🏼", "👋🏽", "👋🏾", "👋🏿"])} - - -async def handle_request(request): - async with AsyncClient(app=app, base_url="http://testserver") as client: - response = await client.get(request.url) - - return response.text, response.status_code, response.headers.items() diff --git a/pyscript.sw/test/test.toml b/pyscript.sw/test/test.toml deleted file mode 100644 index b94942cf52f..00000000000 --- a/pyscript.sw/test/test.toml +++ /dev/null @@ -1 +0,0 @@ -packages = ["ssl", "httpx", "fastapi"] diff --git a/requirements.txt b/requirements.txt index 16c84899dcc..c76bb6c4259 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,4 @@ -black==23.11.0 -isort==5.12.0 -pytest==7.1.2 -pre-commit==3.5.0 -playwright==1.33.0 -pytest-playwright==0.3.3 -pytest-xdist==3.3.0 -pexpect==4.9.0 -pyodide_py==0.24.1 -micropip==0.5.0 -toml==0.10.2 -numpy==1.26.2 -pillow==10.1.0 +black==24.10.0 +pre-commit==3.7.1 +python-minifier==2.11.0 +setuptools==72.1.0