diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..2231ae1755 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: julialang diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 92cdf08c5d..cbc026e816 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,9 +9,10 @@ assignees: '' Thank you for reporting an issue about Pluto! Let's get it fixed! -# To report an issue, you need two things: +# To report an issue, you need three things: 1. 📹 A video recording demonstrating the problem. (You can drag a video file into this box) 2. 📝 A short Pluto notebook file. (Upload the notebook file to https://gist.github.com/ and include the link.) +3. 🤕 Try to clearly explain what the problem is, it might not be obvious to others! Instead of saying: "This does not work.", try to say: "I expected ..., but instead I am seeing ..." 🙋 But my issue is really simple, I don't want to make a screen recording / notebook! diff --git a/.github/workflows/Bundle.yml b/.github/workflows/Bundle.yml index ef89e2bd0e..ff2c46bcec 100644 --- a/.github/workflows/Bundle.yml +++ b/.github/workflows/Bundle.yml @@ -5,45 +5,74 @@ on: branches: - main workflow_dispatch: + pull_request: + paths-ignore: + - "**.md" + - "**.jl" + branches-ignore: + - release + +concurrency: + group: bundle-${{ github.ref }} + cancel-in-progress: false jobs: trigger: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # We use that PAT token instead of GITHUB_TOKEN because we are triggering another github action on the 'release' event. # Triggering a workflow from a workflow is only allowed if the relaying event is signed with a PAT. # See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token with: token: ${{ secrets.PAT_TOKEN }} + if: github.event_name != 'pull_request' + - uses: fregante/setup-git-user@v1 - + if: github.event_name != 'pull_request' + # Ignore the build changes from previous run. # This "just" hard resets to the latest commit on main. # The previous bundle commit will still exist, but will be "dangling", unless we made a tag for it. # Github will eventually clean dangling commits, which is fine because again, the ones with a tag will stay around. - name: Make Sure Release Is Reset To Main + if: github.event_name != 'pull_request' run: | git checkout -b release git reset --hard $GITHUB_SHA + # if this is a PR. then just checkout without fanciness + - uses: actions/checkout@v3 + if: github.event_name == 'pull_request' + # Do the actual bundling - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: 17.x cache: "npm" cache-dependency-path: frontend-bundler/package-lock.json + - run: npm install working-directory: frontend-bundler - - name: The Actual Build + + - name: The Actual Build (try 3 times) working-directory: frontend-bundler - run: npm run build + run: | + (npm run build) || (npm run build) || (npm run build) + + - name: Check for corrupt files + working-directory: frontend-dist + run: | + if [[ $(find . -empty) ]]; then + exit 1 + fi # Push the rebuild frontend-dist to the release branch. # Needs to be `add --force` because frontend-dist is normally gitignored. # Also needs `push --force` because we reset to main (which doesn't contain the previous frontend-dist) - name: Force push frontend-dist changes + if: github.event_name != 'pull_request' run: | git add frontend-dist --force - git commit -m "$GITHUB_WORKFLOW" + git commit -m "$GITHUB_WORKFLOW" -m "Built from hash $GITHUB_SHA" git push origin release --force diff --git a/.github/workflows/FrontendTest.yml b/.github/workflows/FrontendTest.yml index 6f72114274..99db72eeee 100644 --- a/.github/workflows/FrontendTest.yml +++ b/.github/workflows/FrontendTest.yml @@ -19,23 +19,24 @@ on: jobs: frontend-test: runs-on: "ubuntu-latest" + timeout-minutes: 30 steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Makes thes `julia` command available - uses: julia-actions/setup-julia@v1 with: - version: "1.5" + version: "1.6" # our lowest supported version - name: Install Pluto.jl packages run: | julia --project=$GITHUB_WORKSPACE -e "using Pkg; Pkg.instantiate()" - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: - node-version: "12.x" + node-version: "18.x" - name: Install Chrome dependencies run: | @@ -62,24 +63,27 @@ jobs: - name: Run tests working-directory: ./test/frontend run: | - julia -e "import Pkg; Pkg.add(path=\"$GITHUB_WORKSPACE\"); Pkg.instantiate(); import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false)" & # Run Pluto.jl server in the background + julia --project=$GITHUB_WORKSPACE -e 'import Pluto + # Run Pluto.jl server in the background + options = Pluto.Configuration.from_flat_kwargs(; + port=parse(Int, ENV["PLUTO_PORT"]), + require_secret_for_access=false, + workspace_use_distributed_stdlib=false, + ) + 🍭 = Pluto.ServerSession(; options) + server = Pluto.run!(🍭) - # Wait for Pluto to initialize - TIMES_TRIED=0 - until [ $TIMES_TRIED -eq 60 ] || $(curl --output /dev/null --silent --fail "http://localhost:$PLUTO_PORT/"); do - printf '.' - TIMES_TRIED=$((TIMES_TRIED+1)) - sleep 1 - done + run(`npm run test`) + + close(server)' - npm run test env: PLUTO_PORT: 1235 PLUTO_TEST_OFFLINE: ${{ github.ref_name == 'release' }} PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" PUPPETEER_EXECUTABLE_PATH: "/usr/bin/google-chrome-stable" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: test-screenshot-artifacts diff --git a/.github/workflows/IntegrationTest.yml b/.github/workflows/IntegrationTest.yml new file mode 100644 index 0000000000..69e7d8b5a5 --- /dev/null +++ b/.github/workflows/IntegrationTest.yml @@ -0,0 +1,69 @@ +name: Test dependent packages + +# based on https://github.com/SciML/SciMLBase.jl/blob/master/.github/workflows/Downstream.yml, thanks! + +# this is the same as Test.yml +on: + workflow_dispatch: + push: + paths-ignore: + - 'frontend/**' + - 'frontend-bundler/**' + - 'frontend-dist/**' + - 'test/frontend/**' + - '**.md' + branches: + - main + pull_request: + paths-ignore: + - 'frontend/**' + - 'frontend-bundler/**' + - 'frontend-dist/**' + - 'test/frontend/**' + - '**.md' + branches-ignore: + - release + + +jobs: + test: + name: ${{ matrix.package.repo }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + julia-version: [1] + os: [ubuntu-latest] + package: + - { user: JuliaPluto, repo: PlutoSliderServer.jl } + + steps: + - uses: actions/checkout@v3 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.julia-version }} + arch: x64 + - uses: julia-actions/julia-buildpkg@v1 + - name: Clone Downstream + uses: actions/checkout@v3 + with: + repository: ${{ matrix.package.user }}/${{ matrix.package.repo }} + path: downstream + - name: Load this and run the downstream tests + shell: julia --project=downstream {0} + run: | + using Pkg + try + # force it to use this PR's version of the package + Pkg.develop(PackageSpec(path=".")) # resolver may fail with main deps + Pkg.update() + Pkg.test() # resolver may fail with test time deps + catch err + err isa Pkg.Resolve.ResolverError || rethrow() + # If we can't resolve that means this is incompatible by SemVer and this is fine + # It means we marked this as a breaking change, so we don't need to worry about + # Mistakenly introducing a breaking change, as we have intentionally made one + + @info "Not compatible with this release. No problem." exception=err + exit(0) # Exit immediately, as a success + end diff --git a/.github/workflows/LaunchTest.yml b/.github/workflows/LaunchTest.yml index c7538be8b2..7bac5abb94 100644 --- a/.github/workflows/LaunchTest.yml +++ b/.github/workflows/LaunchTest.yml @@ -13,12 +13,12 @@ jobs: strategy: matrix: # We test quite a lot of versions because we do some OS and version specific things unfortunately - julia-version: ["1.0", "1.5", "1.7"] + julia-version: ["1.6", "1.7"] os: [windows-latest, ubuntu-latest] steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Makes thes `julia` command available - uses: julia-actions/setup-julia@v1 diff --git a/.github/workflows/ReleaseTriggers.yml b/.github/workflows/ReleaseTriggers.yml index b149a530bd..cad0e668c3 100644 --- a/.github/workflows/ReleaseTriggers.yml +++ b/.github/workflows/ReleaseTriggers.yml @@ -14,7 +14,7 @@ jobs: matrix: repository: ['fonsp/pluto-on-binder', 'JuliaPluto/sample-notebook-previews'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: | curl \ -X POST \ diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index ae92fce49f..d0c5b86382 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -23,17 +23,11 @@ jobs: # See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token token: ${{ secrets.PAT_TOKEN }} changelog: | - ## {{ package }} {{ version }} - - > Try this release in your browser! _(Available 30 minutes after the release)_ + > **Try this release in your browser!** _(Available 30 minutes after the release)_ > > Binder logo - - **Generate your own binder links using [pluto-on-binder.glitch.me](https://pluto-on-binder.glitch.me/)!** - - {% if previous_release %} - [Diff since {{ previous_release }}]({{ compare_url }}) - {% endif %} + > + > Generate your own binder links using [pluto-on-binder.glitch.me](https://pluto-on-binder.glitch.me/)! {% if custom %} {{ custom }} @@ -52,3 +46,19 @@ jobs: - {{ issue.title }} (#{{ issue.number }}) {% endfor %} {% endif %} + + # New features + *(TODO)* + + # Performance improvements + *(TODO)* + + # Fixes + *(TODO)* + + # Internal changes + *(TODO)* + + {% if previous_release %} + [Diff since {{ previous_release }}]({{ compare_url }}) + {% endif %} diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index eaa6a1ff72..359a6a6149 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -9,12 +9,16 @@ on: - "frontend/**" - "frontend-bundler/**" - "frontend-dist/**" + - "test/frontend/**" - "**.md" branches: - main pull_request: paths-ignore: - "frontend/**" + - "frontend-bundler/**" + - "frontend-dist/**" + - "test/frontend/**" - "**.md" branches-ignore: - release @@ -23,24 +27,27 @@ on: jobs: test: runs-on: ${{ matrix.os }} - timeout-minutes: 40 - # Uncomment if you want to see all results for all OSses. Otherwise, the first failed test cancels all others - # continue-on-error: true + timeout-minutes: 50 + strategy: + # Without setting this, a failing test cancels all others + fail-fast: false matrix: # We test quite a lot of versions because we do some OS and version specific things unfortunately - julia-version: ["1.5", "1.6", "1.7"] #, "nightly"] + julia-version: ["1.6", "1.8", "1.10", "nightly"] # "~1.11.0-0"] os: [ubuntu-latest, macOS-latest, windows-latest] steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - # Makes thes `julia` command available + # Makes the `julia` command available - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.julia-version }} + - uses: julia-actions/cache@v1 # 🚗 - uses: julia-actions/julia-runtest@v1 - continue-on-error: ${{ matrix.julia-version == 'nightly' }} + with: + coverage: false diff --git a/.github/workflows/TestBundledExport.yml b/.github/workflows/TestBundledExport.yml new file mode 100644 index 0000000000..6cc8a31339 --- /dev/null +++ b/.github/workflows/TestBundledExport.yml @@ -0,0 +1,31 @@ +name: Test bundled HTML export + +on: + push: + branches: + - release + +jobs: + frontend-test: + runs-on: "ubuntu-latest" + + steps: + - uses: actions/checkout@v3 + + - uses: julia-actions/setup-julia@v1 + with: + version: "1.8" + + - name: Generate exports and check for warnings + run: | + julia --project=$GITHUB_WORKSPACE -e ' + import Pkg + Pkg.activate(".") + Pkg.instantiate() + import Pluto + using Test + + @test_logs Pluto.generate_html() + @test_logs Pluto.generate_index_html() + ' + diff --git a/.github/workflows/TypeScriptCheck.yml b/.github/workflows/TypeScriptCheck.yml new file mode 100644 index 0000000000..bf8b115bc2 --- /dev/null +++ b/.github/workflows/TypeScriptCheck.yml @@ -0,0 +1,35 @@ +name: Run TypeScript checks + +on: + push: + paths: + - "**.js" + - "**.ts" + branches: + - main + - release + pull_request: + paths: + - "**.js" + - "**.ts" + branches-ignore: + - release + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: "18.x" + + - run: npm install typescript@5.0.4 -g + + - run: npm install + working-directory: frontend + + - name: Run TypeScript checks on frontend/ + run: tsc --noEmit --strictNullChecks false diff --git a/.gitignore b/.gitignore index 41be10eda5..a2b07a1d8d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,8 @@ node_modules .parcel-cache frontend/dist .net -net \ No newline at end of file +net +frontend/package-lock.json + +# PProf +profile.pb.gz diff --git a/.vscode/settings.json b/.vscode/settings.json index 800e828e01..3c537d6a8f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,21 +4,18 @@ "prettier.semi": false, "prettier.quoteProps": "consistent", "prettier.singleQuote": false, - "julia.format.calls": false, - "julia.format.comments": false, - "julia.format.curly": false, - "julia.format.docs": false, - "julia.format.indents": false, - "julia.format.iterOps": false, - "julia.format.ops": false, - "julia.format.tuples": false, - "julia.format.kwarg": "off", "editor.formatOnSave": false, "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }, "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true } } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..1ef57e407d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +fons@plutojl.org. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Project.toml b/Project.toml index 099f5c55c9..5c2ed3a340 100644 --- a/Project.toml +++ b/Project.toml @@ -2,39 +2,77 @@ name = "Pluto" uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" license = "MIT" authors = ["Fons van der Plas "] -version = "0.17.5" +version = "0.19.36" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Configurations = "5218b696-f38b-4ac9-8b61-a12ec717816d" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +ExpressionExplorer = "21656369-7473-754a-2065-74616d696c43" FileWatching = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" FuzzyCompletions = "fb4132e2-a121-4a70-b8a1-d5b831dcdcc2" HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +LoggingExtras = "e6f89c97-d47a-5376-807f-9c37f3926c36" +MIMEs = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +Malt = "36869731-bdee-424d-aa32-cab38c994e3b" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" MsgPack = "99f44e22-a591-53d1-9472-aa23ef4bd671" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +PrecompileSignatures = "91cefc8d-f054-46dc-8f8c-26e11d7c5411" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" +RegistryInstances = "2792f1a3-b283-48e8-9a74-f99dce5104f3" +RelocatableFolders = "05181044-ff0b-4ac5-8273-598c1e38db00" +Scratch = "6c6a2e73-6563-6170-7368-637461726353" Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] +Base64 = "1" Configurations = "0.15, 0.16, 0.17" -FuzzyCompletions = "0.3,0.4" -HTTP = "^0.9.1" +Dates = "1" +Downloads = "1" +ExpressionExplorer = "0.5, 0.6, 1" +FileWatching = "1" +FuzzyCompletions = "0.3, 0.4, 0.5" +HTTP = "^1.5.2" +HypertextLiteral = "0.7, 0.8, 0.9" +InteractiveUtils = "1" +Logging = "1" +LoggingExtras = "0.4, 1" +MIMEs = "0.1" +Malt = "1.1" +Markdown = "1" MsgPack = "1.1" +Pkg = "1" +PrecompileSignatures = "3" +PrecompileTools = "1" +REPL = "1" +RegistryInstances = "0.1" +RelocatableFolders = "0.1, 0.2, 0.3, 1" +Scratch = "1.1" +Sockets = "1" +TOML = "1" Tables = "1" -julia = "^1.5" +URIs = "1.3" +UUIDs = "1" +julia = "^1.6" [extras] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Memoize = "c03570c3-d221-55d1-a50c-7939bbd78826" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" [targets] -test = ["Test", "Random", "DataFrames", "OffsetArrays"] +test = ["DataFrames", "OffsetArrays", "Random", "Sockets", "Test", "TimerOutputs", "Memoize"] diff --git a/README.md b/README.md index 80577ea210..b76d99f931 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,12 @@

🌐 Pluto – one year later (25 min) at Juliacon 2021 🌐


+

🪐 Pluto – reactive and reproducible (25 min) at JupyterCon 2023 🪐

+ +
+ + +

Pluto.jl

@@ -69,9 +75,9 @@ Lastly, here's _**one more feature**_: Pluto notebooks have a `@bind` macro to c
-You don't need to know HTML to use it! The [PlutoUI package](https://github.com/fonsp/PlutoUI.jl) contains basic inputs like sliders and buttons. Pluto's interactivity is very easy to use, you will learn more from the sample notebooks inside Pluto! +You don't need to know HTML to use it! The [PlutoUI package](https://github.com/fonsp/PlutoUI.jl) contains basic inputs like sliders and buttons. Pluto's interactivity is very easy to use, you will learn more from the featured notebooks inside Pluto! -But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a `new CustomEvent("input")`, making it compatible with the [`viewof` operator of observablehq](https://observablehq.com/@observablehq/a-brief-introduction-to-viewof). Have a look at the JavaScript sample notebook inside Pluto! +But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a `new CustomEvent("input")`, making it compatible with the [`viewof` operator of observablehq](https://observablehq.com/@observablehq/a-brief-introduction-to-viewof). Have a look at the JavaScript featured notebook inside Pluto!
@@ -96,7 +102,7 @@ _([video](https://www.youtube.com/watch?v=rpB6zQNsbQU)) Grant Sanderson ([3Blue1 For one tasty notebook 🥞 you will need: -- [**Julia** v1.5 or above](https://julialang.org/downloads/#current_stable_release) +- [**Julia** v1.6 or above](https://julialang.org/downloads/#current_stable_release) - **Linux**, **MacOS** or **Windows**, _Linux and MacOS will work best_ - Mozilla **Firefox** or Google **Chrome** @@ -109,11 +115,10 @@ and add the Pluto package: ```julia julia> ] -(v1.7) pkg> add Pluto +(v1.10) pkg> add Pluto ``` -_Tip for new Julia users: To return to the `julia>` prompt from the Pkg REPL, -either press backspace when the input line is empty or press Ctrl+C._ +_Press `Ctrl+C` to return to the `julia>` prompt._ ### Usage @@ -147,9 +152,7 @@ Follow [these instructions](https://github.com/fonsp/Pluto.jl/blob/main/CONTRIBU ## License -Pluto.jl is open source! Specifically, it is [MIT Licensed](https://github.com/fonsp/Pluto.jl/blob/main/LICENSE). The included sample notebooks have a more permissive license: the [Unlicense](https://github.com/fonsp/Pluto.jl/blob/main/sample/LICENSE). This means that you can use sample notebook code however you like - you do not need to credit us! - -Pluto.jl is built by gluing together open source software: +Pluto.jl is open source! Specifically, it is [MIT Licensed](https://github.com/fonsp/Pluto.jl/blob/main/LICENSE). Pluto.jl is built by gluing together open source software: - `Julia` - [license](https://github.com/JuliaLang/julia/blob/master/LICENSE.md) - `CodeMirror` - [license](https://github.com/codemirror/codemirror.next/blob/master/LICENSE-MIT) @@ -161,7 +164,13 @@ Pluto.jl is built by gluing together open source software: - `developit/htm` - [license](https://github.com/developit/htm/blob/master/LICENSE) - `MathJax` - [license](https://github.com/mathjax/MathJax-src/blob/master/LICENSE) -Your notebook files are _yours_, you do not need to credit us. Have fun! +If you want to reference Pluto.jl in scientific writing, you can use our DOI: [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4792401.svg)](https://doi.org/10.5281/zenodo.4792401) + +### Featured notebooks + +Unless otherwise specified, the included featured notebooks have a more permissive license: the [Unlicense](https://github.com/fonsp/Pluto.jl/blob/main/sample/LICENSE). This means that you can use them however you like - you do not need to credit us! + +Your notebook files are _yours_, you also do not need to credit us. Have fun! ## From the authors @@ -169,9 +178,9 @@ The Pluto project is an ambition to [_rethink what a programming environment sho ### You can chat with us -- contact me (fonsi) **[via email](mailto:fons@plutojl.org)** or on my video chat room (wait a minute for me to join) - talk with fellow Pluto users in the **[Zulip chat room](https://gist.github.com/fonsp/db7d00fd3fe5bc0b379b4af9ec6674b6)** (_search for the `pluto.jl` stream_) - use Pluto's **[built-in feedback system:](https://github.com/fonsp/Pluto.jl/issues/182#issue-637726414)** +- contact fons **[via email](mailto:fons@plutojl.org)** feedback screencap @@ -185,7 +194,7 @@ Development of Pluto.jl is partially sponsored by |----|----| | MIT logo | The free online course _[Introduction to Computational Thinking](https://computationalthinking.mit.edu)_ at **MIT** uses Pluto notebooks to teach scientific computing in a new way. Homeworks react to the student in realtime, with _live answer checks and visualizations_ while you solve problems. | | QuEra logo | **QuEra Computing** uses a Pluto notebook as an online dashboard to control their _quantum computer_! | -| Julia Computing logo | [JuliaHub](https://juliahub.com) by **Julia Computing** enables the creation and editing of Pluto notebooks *on the cloud*! | +| JuliaHub logo | [**JuliaHub**](https://juliahub.com) enables the creation and editing of Pluto notebooks *on the cloud*! | | NumFOCUS logo | The mission of **NumFOCUS** is to promote open practices in research, data, and scientific computing by serving as a fiscal sponsor for open source projects and organizing community-driven educational programs. | _Created by [**Fons van der Plas**](https://github.com/fonsp) and [**Mikołaj Bochenski**](https://github.com/malyvsen). Inspired by [Observable](https://observablehq.com/)._ diff --git a/frontend-bundler/.parcelrc b/frontend-bundler/.parcelrc index eb1a80ec89..47170b8e3b 100644 --- a/frontend-bundler/.parcelrc +++ b/frontend-bundler/.parcelrc @@ -3,5 +3,9 @@ "resolvers": [ "parcel-resolver-like-a-browser", "..." + ], + "reporters": [ + "...", + "parcel-reporter-bundle-manifest" ] } diff --git a/frontend-bundler/add_sri.js b/frontend-bundler/add_sri.js new file mode 100644 index 0000000000..1cbb85baff --- /dev/null +++ b/frontend-bundler/add_sri.js @@ -0,0 +1,37 @@ +// Go through all the CSS/JS imports in an HTML file, and add SRI attributes. More info here: +// https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#examples + +// I really really tried to do this using a parcel plugin but it's "not possible". So right now this is just a separate script that you run with the html filenames as arguments. + +let path = require("path") +let fs = require("fs/promises") +let posthtml = require("posthtml") +let posthtmlSri = require("posthtml-sri") +let posthtmlCrossorigin = require("@plutojl/posthtml-crossorigin") + +let f = async () => { + // Read file given as command line arugment + for (let i = 2; i < process.argv.length; i++) { + let file = process.argv[i] + let contents = await fs.readFile(file, "utf8") + + const plugins = [ + posthtmlSri({ + algorithms: ["sha384"], + basePath: path.dirname(file), + }), + posthtmlCrossorigin({ + value: () => "anonymous", + }), + ] + + const result = await posthtml(plugins).process(contents) + // console.log(result) + + // Write to file + await fs.writeFile(file, result.html) + console.log("✅ SRI added to ", file) + } +} + +f() diff --git a/frontend-bundler/package-lock.json b/frontend-bundler/package-lock.json index 691ca8b386..338ab687a5 100644 --- a/frontend-bundler/package-lock.json +++ b/frontend-bundler/package-lock.json @@ -15,20 +15,25 @@ "@parcel/config-default": "^2.0.0", "mkdirp": "^1.0.4", "parcel": "^2.0.0", + "parcel-reporter-bundle-manifest": "^1.0.0", "parcel-resolver-like-a-browser": "file:../frontend-bundler/parcel-resolver-like-a-browser" }, "devDependencies": { "@parcel/optimizer-data-url": "^2.0.0", "@parcel/transformer-inline-string": "^2.0.0", - "@types/node": "^16.11.6" + "@plutojl/posthtml-crossorigin": "^1.0.0", + "@types/node": "^16.11.6", + "posthtml": "^0.16.6", + "posthtml-sri": "^1.2.0" } }, "node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -71,36 +76,23 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" @@ -124,43 +116,39 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -251,20 +239,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -291,12 +287,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -304,9 +300,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -344,30 +340,31 @@ } }, "node_modules/@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -384,21 +381,167 @@ } }, "node_modules/@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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==", + "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==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "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==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==" + }, + "node_modules/@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "dependencies": { + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@mischnic/json-sourcemap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz", + "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==", + "dependencies": { + "@lezer/common": "^0.15.7", + "@lezer/lr": "^0.15.4", + "json5": "^2.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -488,13 +631,14 @@ } }, "node_modules/@parcel/cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.0.0.tgz", - "integrity": "sha512-HThLpk1qXkyRyWrqXh5EYdINFd4tl4SCUgbipZ46pQWtwZ8+0nmudbuszeRKi1UCyNCdgktcZu8xmXmSVQNDyA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.5.0.tgz", + "integrity": "sha512-3kOO3cZQv0FAKhrMHGLdb4Qtzpmy78Q6jPN3u8eCY4yqeDTnyQBZvWNHoyCm5WlmL8y6Q6REYMbETLxSH1ggAQ==", "dependencies": { - "@parcel/logger": "^2.0.0", - "@parcel/utils": "^2.0.0", - "lmdb-store": "^1.5.5" + "@parcel/fs": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/utils": "2.5.0", + "lmdb": "2.2.4" }, "engines": { "node": ">= 12.0.0" @@ -504,18 +648,15 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.0.0" + "@parcel/core": "^2.5.0" } }, "node_modules/@parcel/codeframe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.0.0.tgz", - "integrity": "sha512-34L0qa72rxtzng2Bw195YYVAZWhuWm1V9u+0bHfajyl242BDUbUNpQOowP/AYRjj7XSmIN6XCUv3luogvMPo8A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.5.0.tgz", + "integrity": "sha512-qafqL8Vu2kr932cCWESoDEEoAeKVi7/xdzTBuhzEJng1AfmRT0rCbt/P4ao3RjiDyozPSjXsHOqM6GDZcto4eQ==", "dependencies": { - "chalk": "^4.1.0", - "emphasize": "^4.2.0", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" + "chalk": "^4.1.0" }, "engines": { "node": ">= 12.0.0" @@ -650,34 +791,34 @@ } }, "node_modules/@parcel/core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.0.0.tgz", - "integrity": "sha512-wiY3XyGetCpek0aEi+xB0eQQUn4v9xt20AKx71KpU30SShwcHnVEUEVxuVEi7+NgJQsUCsp8nXUeZluwRTfUFA==", - "dependencies": { - "@parcel/cache": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/events": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/graph": "^2.0.0", - "@parcel/hash": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/package-manager": "^2.0.0", - "@parcel/plugin": "^2.0.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.5.0.tgz", + "integrity": "sha512-dygDmPsfAYJKTnUftcbEzjCik7AAaPbFvJW8ETYz8diyjkAG9y6hvCAZIrJE5pNOjFzg32en4v4UWv8Sqlzl9g==", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/events": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/graph": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/package-manager": "2.5.0", + "@parcel/plugin": "2.5.0", "@parcel/source-map": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", - "@parcel/workers": "^2.0.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", + "@parcel/workers": "2.5.0", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", "clone": "^2.1.1", "dotenv": "^7.0.0", "dotenv-expand": "^5.1.0", - "json-source-map": "^0.6.1", - "json5": "^1.0.1", - "micromatch": "^4.0.2", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", "nullthrows": "^1.1.1", - "semver": "^5.4.1" + "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0" @@ -688,11 +829,11 @@ } }, "node_modules/@parcel/diagnostic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.0.0.tgz", - "integrity": "sha512-cADyFWaMlhDawQdraFt2TECpiD/DvQ76L+RK97X7sUj5b+cGY7fjrnWPKRVmog5+OoNlbmh1EO3FOLx5vuxzww==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.5.0.tgz", + "integrity": "sha512-KiMGGRpEV7wl5gjcxBKcgX84a+cG+IEn94gwy5LK3lENR09nuKShqqgKGAmj/17CobJgw1QNP94/H4Md+oxIWg==", "dependencies": { - "json-source-map": "^0.6.1", + "@mischnic/json-sourcemap": "^0.1.0", "nullthrows": "^1.1.1" }, "engines": { @@ -704,9 +845,9 @@ } }, "node_modules/@parcel/events": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.0.0.tgz", - "integrity": "sha512-v9+pXLtgc44+eIbNAs/SB2tyXKUv+5XF1f3TRsLJ44276e9ksa3Cstrs1EFxZtpi03UoXkXJQoJljGigb2bt8A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.5.0.tgz", + "integrity": "sha512-Gc2LPwL1H34Ony5MENbKZg7wvCscZ4x9y7Fu92sfbdWpLo3K13hVtsX3TMIIgYt3B7R7OmO8yR880U2T+JfVkQ==", "engines": { "node": ">= 12.0.0" }, @@ -716,22 +857,15 @@ } }, "node_modules/@parcel/fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.0.0.tgz", - "integrity": "sha512-1FQIVDO3zWE2vv9EJmLJq+EeZ7DE4lwi/e0fR1PAS1g5YbO9n3u01Xnpzy/jmlL14LnBXdhy4r7OBziShYLK6w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.5.0.tgz", + "integrity": "sha512-YYr14BWtx/bJ+hu6PPQQ6G/3omOTWgVqEw+UFI3iQH3P6+e0LRXW/Ja1yAcJeepGcTwIP0opnXZBQOm8PBQ2SA==", "dependencies": { - "@parcel/fs-search": "^2.0.0", - "@parcel/fs-write-stream-atomic": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/fs-search": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", "@parcel/watcher": "^2.0.0", - "@parcel/workers": "^2.0.0", - "graceful-fs": "^4.2.4", - "mkdirp": "^0.5.1", - "ncp": "^2.0.0", - "nullthrows": "^1.1.1", - "rimraf": "^3.0.2", - "utility-types": "^3.10.0" + "@parcel/workers": "2.5.0" }, "engines": { "node": ">= 12.0.0" @@ -741,13 +875,13 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.0.0" + "@parcel/core": "^2.5.0" } }, "node_modules/@parcel/fs-search": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.0.0.tgz", - "integrity": "sha512-OVWA0elZm5BKaHgS5FnvlmMwQiU++0sGW7PIyaNJnY0lvpZndU+Pot0xNTSrG3Aq7OkpQlcUWkEMA8KtkHZH1A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.5.0.tgz", + "integrity": "sha512-uBONkz9ZCNSOqbPGWJY3MNl+pqBTfvzHH9+4UhzHEHPArvK2oD0+syYPVE60+zGrxybXTESYMCJp4bHvH6Z2hA==", "dependencies": { "detect-libc": "^1.0.3" }, @@ -759,37 +893,12 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/fs-write-stream-atomic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs-write-stream-atomic/-/fs-write-stream-atomic-2.0.0.tgz", - "integrity": "sha512-PSvAcu7f+3zzjQZuYJjPQVRI99Lu2HEphr04JChwdO5wr/sm6dYFRQdL0SahH/vF1tnEaBFxC4vTslNEBT+9bg==", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^1.0.2", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/fs/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/@parcel/graph": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.0.0.tgz", - "integrity": "sha512-ZI3pYSWWqGAFi4qDa00kieiKpHz3xY9vPr4iVTjNiNXD6fU7C+Y25mxPmLv4uYbJTzccAo0iaN9VGqPo/FyiBg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.5.0.tgz", + "integrity": "sha512-qa2VtG08dJyTaWrxYAkMIlkoDRSPoiqLDNxxHKplkcxAjXBUw0/AkWaz82VO5r1G6jfOj+nM30ajH9uygZYwbw==", "dependencies": { + "@parcel/utils": "2.5.0", "nullthrows": "^1.1.1" }, "engines": { @@ -801,12 +910,12 @@ } }, "node_modules/@parcel/hash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.0.0.tgz", - "integrity": "sha512-+Yq+mGnZOSyJ6atLCFvA1Kyg/NVysVzlwSNrmA3dc3yO63GtXojQEEyW9U20d+Bj/DVlocLO52Z61d4P9ak4Tw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.5.0.tgz", + "integrity": "sha512-47JL0XpB7UvIW6Ijf8vv+yVMt9dLvB/lRlBHFmAkmovisueVMVbYD7smxVZnCSehD8UH8BcymKbMzyL5dimgoQ==", "dependencies": { "detect-libc": "^1.0.3", - "xxhash-wasm": "^0.4.1" + "xxhash-wasm": "^0.4.2" }, "engines": { "node": ">= 12.0.0" @@ -817,12 +926,12 @@ } }, "node_modules/@parcel/logger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.0.0.tgz", - "integrity": "sha512-jpESL6m4tEGP+Yj/PZGb6ellrOx3irEIvSjbhwZBGoXaApqqvB352dLXrVJ/vyrmzj9YLNdm2rPWeZWkMDGgMA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.5.0.tgz", + "integrity": "sha512-pT1L3ceH6trL1N3I3r2HawPjz/PCubOo/Kazu7IeXsMsKVjj1a6AeieZHzkNZIbhiGPtm/cHbBNLz2zTWDLeOA==", "dependencies": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/events": "^2.0.0" + "@parcel/diagnostic": "2.5.0", + "@parcel/events": "2.5.0" }, "engines": { "node": ">= 12.0.0" @@ -833,9 +942,9 @@ } }, "node_modules/@parcel/markdown-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.0.0.tgz", - "integrity": "sha512-AgxIXRaEpNi1GukjWC6FTLO7t/EImv+3KuwFF5tGlWhXO41V1Igl6gXCDpzRmTk5dBbdqOWdRWip1O5Qy74cwA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.5.0.tgz", + "integrity": "sha512-ixkNF3KWIqxMlfxTe9Gb2cp/uNmklQev8VEUxujMVxmUfGyQs4859zdJIQlIinabWYhArhsXATkVf3MzCUN6TQ==", "dependencies": { "chalk": "^4.1.0" }, @@ -1102,21 +1211,17 @@ } }, "node_modules/@parcel/package-manager": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.0.0.tgz", - "integrity": "sha512-zJY5SOaEC6pyU9bXLmGlnD7VRWURsbxPVNHVreFNttHg2DaT+0u1R5NAoor4BG38esw2TaGdi8QU9TmsTyhSUQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.5.0.tgz", + "integrity": "sha512-zTuF55/lITUjw9dUU/X0HiF++589xbPXw/zUiG9T6s8BQThLvrxAhYP89S719pw7cTqDimGkTxnIuK+a0djEkg==", "dependencies": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", - "@parcel/workers": "^2.0.0", - "command-exists": "^1.2.6", - "cross-spawn": "^6.0.4", - "nullthrows": "^1.1.1", - "semver": "^5.4.1", - "split2": "^3.1.1" + "@parcel/diagnostic": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", + "@parcel/workers": "2.5.0", + "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0" @@ -1126,7 +1231,7 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.0.0" + "@parcel/core": "^2.5.0" } }, "node_modules/@parcel/packager-css": { @@ -1227,11 +1332,11 @@ } }, "node_modules/@parcel/plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.0.0.tgz", - "integrity": "sha512-yOBRbizd27vivgFRxpTBxfViTIYMdoLeAvRHEoL49dkymKkKtq09hZQtVS+iQmypwyJnp4cMsG8FwN+srJub7w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.5.0.tgz", + "integrity": "sha512-obtb6/Gql6YFQ86bdv75A2Noabx8679reFZeyfKKf0L7Lppx4DFQetXwM9XVy7Gx6hJ1Ekm3UMuuIyVJk33YHQ==", "dependencies": { - "@parcel/types": "^2.0.0" + "@parcel/types": "2.5.0" }, "engines": { "node": ">= 12.0.0" @@ -1484,20 +1589,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/transformer-babel/node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@parcel/transformer-css": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.0.0.tgz", @@ -1616,38 +1707,23 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/transformer-json/node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@parcel/transformer-postcss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.0.0.tgz", - "integrity": "sha512-CnDgHs2G6nAQghpMWrB84K2QYVLQ2q8CucD4XTe9xc2mo1ObeCtpEijAxsORyp4TTZYOLsw4hmVbv/eY8uLOLg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.5.0.tgz", + "integrity": "sha512-IPNlWElekdQHMTBqhdwJNBCQomuYyo7xgNBdnTrt9VJ+R5ihy6n7ZJSWIAJXAH9VZxETTtunfrzRtgkmtjTeZQ==", "dependencies": { - "@parcel/hash": "^2.0.0", - "@parcel/plugin": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/plugin": "2.5.0", + "@parcel/utils": "2.5.0", "clone": "^2.1.1", - "css-modules-loader-core": "^1.1.0", "nullthrows": "^1.1.1", - "postcss-modules": "^3.2.2", - "postcss-value-parser": "^4.1.0", - "semver": "^5.4.1" + "postcss-value-parser": "^4.2.0", + "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.0.0" + "parcel": "^2.5.0" }, "funding": { "type": "opencollective", @@ -1655,21 +1731,21 @@ } }, "node_modules/@parcel/transformer-posthtml": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.0.0.tgz", - "integrity": "sha512-jaiymnLQshy99zNxp9JLvFWFGm41LWULFRwjHep1ALGyphcxPiw/zq4o0K7pvc8shlAXvE2M/3Q2SGFyCwe+zA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.5.0.tgz", + "integrity": "sha512-AZxg1XD8OXOS4bEGEmBBR+X9T9qoFdVsbVUg498zzejYSka1ZQHF7TgLI/+pUnE+ZVYNIp7/G0xXqsRVKMKmdQ==", "dependencies": { - "@parcel/plugin": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/plugin": "2.5.0", + "@parcel/utils": "2.5.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", "posthtml-render": "^3.0.0", - "semver": "^5.4.1" + "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.0.0" + "parcel": "^2.5.0" }, "funding": { "type": "opencollective", @@ -1733,45 +1809,31 @@ } }, "node_modules/@parcel/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.0.0.tgz", - "integrity": "sha512-117vnZuQ1HzXOrIo8qAFgG0lMfz5dck7u+smlaZP1aRxVJaxWBo2C2+8JoTPHjRn9tE5IZGH9PVIZW+X3F474g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.5.0.tgz", + "integrity": "sha512-bA0fhG6aXSGYEVo5Dt96x6lseUQHeVZVzgmiRdZsvb614Gvx22ItfaKhPmAVbM9vzbObZDHl9l9G2Ovw8Xve4g==", "dependencies": { - "@parcel/cache": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/package-manager": "^2.0.0", + "@parcel/cache": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/package-manager": "2.5.0", "@parcel/source-map": "^2.0.0", - "@parcel/workers": "^2.0.0", + "@parcel/workers": "2.5.0", "utility-types": "^3.10.0" } }, "node_modules/@parcel/utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.0.0.tgz", - "integrity": "sha512-4SX8qNyImHLyvVls1U9rxF+h+1kbbdWpxnRiHOFPBYW6H1LiUNBjXPPffTEpKb+RFOqmQ2uNh0aP0mCmROPfXg==", - "dependencies": { - "@iarna/toml": "^2.2.0", - "@parcel/codeframe": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/hash": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/markdown-ansi": "^2.0.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-kaLGXtQuOOH55KZqXdYDvczhh3mk2eeTVqrrXuuihGjbLKYFlUW2tFDm+5r2s9nCPwTQxOO43ZEOCKSnia+e4w==", + "dependencies": { + "@parcel/codeframe": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/markdown-ansi": "2.5.0", "@parcel/source-map": "^2.0.0", - "ansi-html-community": "0.0.8", - "chalk": "^4.1.0", - "clone": "^2.1.1", - "fast-glob": "3.1.1", - "fastest-levenshtein": "^1.0.8", - "is-glob": "^4.0.0", - "is-url": "^1.2.2", - "json5": "^1.0.1", - "lru-cache": "^6.0.0", - "micromatch": "^4.0.4", - "node-forge": "^0.10.0", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "terminal-link": "^2.1.1" + "chalk": "^4.1.0" }, "engines": { "node": ">= 12.0.0" @@ -1863,14 +1925,14 @@ } }, "node_modules/@parcel/workers": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.0.0.tgz", - "integrity": "sha512-emfezGXmmz5NNrtBvbZO4cFosdpEL+OqhIa4SpUH63aedx+9so/GI/rMp19FmTi0qPKQhOLJmD4VZ2RZHbZM4w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.5.0.tgz", + "integrity": "sha512-/Ow5OKJWs+9OzV3Jy4J++VnbNx0j3ls/M1CGVBLiBWyCada9DMtquYoBQ4Sk6Uam50BKkIFYetGOeXPNQyyMjg==", "dependencies": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", "chrome-trace-event": "^1.0.2", "nullthrows": "^1.1.1" }, @@ -1882,7 +1944,16 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.0.0" + "@parcel/core": "^2.5.0" + } + }, + "node_modules/@plutojl/posthtml-crossorigin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@plutojl/posthtml-crossorigin/-/posthtml-crossorigin-1.0.0.tgz", + "integrity": "sha512-Rblfw7JRp11OVON1bKFBfz+N+kE6T3eYLaqUTSrT7W2+UyLDJJC63U8iJhjbs12Eo6f3XMe77ktM6hE0quzqgQ==", + "dev": true, + "engines": { + "node": ">=10" } }, "node_modules/@swc/helpers": { @@ -1974,46 +2045,10 @@ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "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==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } @@ -2085,14 +2120,6 @@ "node": ">=0.8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/astring": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/astring/-/astring-1.7.5.tgz", @@ -2102,9 +2129,9 @@ } }, "node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "node_modules/async-limiter": { "version": "1.0.1", @@ -2180,14 +2207,6 @@ "tweetnacl": "^0.14.3" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "engines": { - "node": "*" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -2198,23 +2217,10 @@ "readable-stream": "^3.4.0" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/boolbase": { "version": "1.0.0", @@ -2295,32 +2301,22 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", + "elliptic": "^6.5.4", "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 6" + "node": ">= 4" } }, "node_modules/browserify-zlib": { @@ -2515,7 +2511,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colord": { "version": "2.8.0", @@ -2533,11 +2529,6 @@ "node": ">= 0.8" } }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -2619,11 +2610,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, "node_modules/cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -2678,21 +2664,6 @@ "sha.js": "^2.4.8" } }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, "node_modules/crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -2736,101 +2707,6 @@ "postcss": "^8.0.9" } }, - "node_modules/css-modules-loader-core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", - "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=", - "dependencies": { - "icss-replace-symbols": "1.1.0", - "postcss": "6.0.1", - "postcss-modules-extract-imports": "1.1.0", - "postcss-modules-local-by-default": "1.2.0", - "postcss-modules-scope": "1.1.0", - "postcss-modules-values": "1.3.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/chalk/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/postcss": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz", - "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=", - "dependencies": { - "chalk": "^1.1.3", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-modules-loader-core/node_modules/supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -2846,15 +2722,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "dependencies": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, "node_modules/css-tree": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", @@ -3224,11 +3091,11 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/ejs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", + "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", "dependencies": { - "jake": "^10.6.1" + "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" @@ -3266,92 +3133,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/emphasize": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/emphasize/-/emphasize-4.2.0.tgz", - "integrity": "sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg==", - "dependencies": { - "chalk": "^4.0.0", - "highlight.js": "~10.4.0", - "lowlight": "~1.17.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/emphasize/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/emphasize/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/emphasize/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/emphasize/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/emphasize/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/emphasize/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3449,7 +3230,7 @@ "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } @@ -3585,16 +3366,6 @@ "punycode": "^1.3.2" } }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" - }, - "node_modules/fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -3603,24 +3374,31 @@ "reusify": "^1.0.4" } }, - "node_modules/fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "node_modules/filelist": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", + "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "minimatch": "^5.0.1" } }, - "node_modules/filelist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "minimatch": "^3.0.4" + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/filesize": { @@ -3673,9 +3451,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", "funding": [ { "type": "individual", @@ -3717,14 +3495,6 @@ "node": ">= 0.12" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3735,14 +3505,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "node_modules/generic-names": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", - "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==", - "dependencies": { - "loader-utils": "^1.1.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3858,11 +3620,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" - }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -3895,25 +3652,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -3925,7 +3663,7 @@ "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { "node": ">=4" } @@ -3968,19 +3706,6 @@ "node": ">=4" } }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -3990,14 +3715,6 @@ "minimalistic-assert": "^1.0.1" } }, - "node_modules/highlight.js": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.1.tgz", - "integrity": "sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==", - "engines": { - "node": "*" - } - }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -4118,77 +3835,24 @@ "node": ">=0.10.0" } }, - "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": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - }, - "node_modules/icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/icss-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/icss-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/icss-utils/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/iferr": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", - "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==", - "engines": { - "node": ">=6.0.0" - } + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { "version": "5.1.8", @@ -4213,14 +3877,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -4332,20 +3988,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4560,11 +4202,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "node_modules/is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -4576,22 +4213,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "node_modules/isbinaryfile": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", @@ -4604,23 +4225,18 @@ "url": "https://github.com/sponsors/gjtorikian/" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "node_modules/jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "dependencies": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, @@ -4628,7 +4244,71 @@ "jake": "bin/cli.js" }, "engines": { - "node": "*" + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/js-tokens": { @@ -4702,48 +4382,43 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "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==" }, - "node_modules/json-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", - "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dependencies": { - "minimist": "^1.2.0" - }, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "engines": [ - "node >=0.6.0" - ], + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" } }, "node_modules/levn": { @@ -4771,33 +4446,17 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, - "node_modules/lmdb-store": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/lmdb-store/-/lmdb-store-1.6.8.tgz", - "integrity": "sha512-Ltok13VVAfgO5Fdj/jVzXjPJZjefl1iENEHerZyAfAlzFUhvOrA73UdKItqmEPC338U29mm56ZBQr5NJQiKXow==", + "node_modules/lmdb": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.2.4.tgz", + "integrity": "sha512-gto+BB2uEob8qRiTlOq+R3uX0YNHsX9mjxj9Sbdue/LIKqu6IlZjrsjKeGyOMquc/474GEqFyX2pdytpydp0rQ==", "hasInstallScript": true, "dependencies": { - "mkdirp": "^1.0.4", + "msgpackr": "^1.5.4", "nan": "^2.14.2", "node-gyp-build": "^4.2.3", - "ordered-binary": "^1.0.0", - "weak-lru-cache": "^1.0.0" - }, - "optionalDependencies": { - "msgpackr": "^1.3.7" - } - }, - "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" + "ordered-binary": "^1.2.4", + "weak-lru-cache": "^1.2.2" } }, "node_modules/lodash": { @@ -4805,11 +4464,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, "node_modules/lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", @@ -4909,30 +4563,6 @@ "node": ">=8" } }, - "node_modules/lowlight": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.17.0.tgz", - "integrity": "sha512-vmtBgYKD+QVNy7tIa7ulz5d//Il9R4MooOVh4nkOf9R9Cb/Dk5TXMSTieg/vDulkBkIWj59/BIlyFQxT9X1oAQ==", - "dependencies": { - "fault": "^1.0.0", - "highlight.js": "~10.4.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -5035,9 +4665,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5045,10 +4675,17 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "node_modules/minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/mkdirp": { "version": "1.0.4", @@ -5067,23 +4704,32 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/msgpackr": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.4.5.tgz", - "integrity": "sha512-AFmAehFqidJaSAWig6cp+8MZU3r7rtL1sgBxzXR9YICfG8vGRemCcVoqPG81CqRHdxP/VX/DyM85wltqPseXNw==", - "optional": true, + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.1.tgz", + "integrity": "sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==", "optionalDependencies": { - "msgpackr-extract": "^1.0.14" + "msgpackr-extract": "^3.0.2" } }, "node_modules/msgpackr-extract": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-1.0.14.tgz", - "integrity": "sha512-t8neMf53jNZRF+f0H9VvEUVvtjGZ21odSBRmFfjZiyxr9lKYY0mpY3kSWZAIc7YWXtCZGOvDQVx2oqcgGiRBrw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "hasInstallScript": true, "optional": true, "dependencies": { - "nan": "^2.14.2", - "node-gyp-build": "^4.2.3" + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" } }, "node_modules/nan": { @@ -5097,9 +4743,9 @@ "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==" }, "node_modules/nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5107,33 +4753,28 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "bin": { - "ncp": "bin/ncp" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, "node_modules/node-addon-api": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" }, "node_modules/node-fetch": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", - "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dependencies": { "whatwg-url": "^5.0.0" }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/node-fetch/node_modules/tr46": { @@ -5155,14 +4796,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/node-gyp-build": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", @@ -5173,6 +4806,17 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", @@ -5299,21 +4943,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -5417,9 +5046,9 @@ } }, "node_modules/ordered-binary": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.1.3.tgz", - "integrity": "sha512-tDTls+KllrZKJrqRXUYJtIcWIyoQycP7cVN7kzNNnhHKF2bMKHflcAQK+pF2Eb1iVaQodHxqZQr0yv4HWLGBhQ==" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.2.5.tgz", + "integrity": "sha512-djRmZoEpOGvIRW7ufsCDHtvcUa18UC9TxnPbHhSVFZHsoyg0dtut1bWtBZ/fmxdPN62oWXrV6adM7NoWU+CneA==" }, "node_modules/os-browserify": { "version": "0.3.0", @@ -5462,6 +5091,21 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/parcel-reporter-bundle-manifest": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parcel-reporter-bundle-manifest/-/parcel-reporter-bundle-manifest-1.0.0.tgz", + "integrity": "sha512-/fQDwYWT9LsXRddNikci9Jox6bJdKnfGKpnVd4++1TRUYRLXvFVGQjyGZg8Gsu/JQN6psST8ilRmpg61yN37pQ==", + "dependencies": { + "@parcel/plugin": "^2.0.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.0.0" + }, + "peerDependencies": { + "parcel": "^2.0.0" + } + }, "node_modules/parcel-resolver-like-a-browser": { "resolved": "parcel-resolver-like-a-browser", "link": true @@ -5601,14 +5245,6 @@ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "engines": { - "node": ">=4" - } - }, "node_modules/path-to-regexp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", @@ -5864,216 +5500,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-modules": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-3.2.2.tgz", - "integrity": "sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw==", - "dependencies": { - "generic-names": "^2.0.1", - "icss-replace-symbols": "^1.1.0", - "lodash.camelcase": "^4.3.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "string-hash": "^1.1.1" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", - "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", - "dependencies": { - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-extract-imports/node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-modules-extract-imports/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "dependencies": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-local-by-default/node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-modules-local-by-default/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "dependencies": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-scope/node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-modules-scope/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "dependencies": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-values/node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-modules-values/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-modules/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-modules/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-modules/node_modules/postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dependencies": { - "postcss": "^7.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules/node_modules/postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", - "dependencies": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules/node_modules/postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules/node_modules/postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "dependencies": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "node_modules/postcss-modules/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==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postcss-normalize-charset": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", @@ -6292,9 +5718,9 @@ } }, "node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/postcss/node_modules/picocolors": { "version": "0.2.1", @@ -6302,11 +5728,11 @@ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "node_modules/posthtml": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.5.tgz", - "integrity": "sha512-1qOuPsywVlvymhTFIBniDXwUDwvlDri5KUQuBqjmCc8Jj4b/HDSVWU//P6rTWke5rzrk+vj7mms2w8e1vD0nnw==", + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", "dependencies": { - "posthtml-parser": "^0.10.0", + "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" }, "engines": { @@ -6335,6 +5761,30 @@ "node": ">=12" } }, + "node_modules/posthtml-sri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/posthtml-sri/-/posthtml-sri-1.2.0.tgz", + "integrity": "sha512-2PFUHkDMJIOX5AoljGVLgJLleDyUz779Czn9R0MoxSnpmTcheGHM85bt/6bZ33Dm20gQTWyPbiSmfIfz1d3tIg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/posthtml/node_modules/posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -6351,11 +5801,6 @@ "node": ">= 0.6.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -6407,9 +5852,9 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "engines": { "node": ">=0.6" } @@ -6484,30 +5929,16 @@ } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/regenerator-runtime": { @@ -6638,20 +6069,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -6719,23 +6136,23 @@ } }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } }, "node_modules/serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "fast-url-parser": "1.1.3", "mime-types": "2.1.18", - "minimatch": "3.0.4", + "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "2.2.1", "range-parser": "1.2.0" @@ -6758,25 +6175,6 @@ "sha.js": "bin.js" } }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6803,52 +6201,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -6882,27 +6234,6 @@ "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/srcset": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", @@ -6938,6 +6269,18 @@ "node": ">=0.10.0" } }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -6968,19 +6311,6 @@ "readable-stream": "^3.5.0" } }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/stream-http": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", @@ -6992,19 +6322,6 @@ "xtend": "^4.0.2" } }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -7013,11 +6330,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7092,37 +6404,6 @@ "node": ">=4" } }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/svgo": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz", @@ -7149,24 +6430,9 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "node_modules/term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", "engines": { "node": ">=8" }, @@ -7175,12 +6441,13 @@ } }, "node_modules/terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -7190,19 +6457,22 @@ "node": ">=10" } }, + "node_modules/terser/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/terser/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==" }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "engines": { - "node": ">= 8" - } - }, "node_modules/timers-browserify": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", @@ -7555,9 +6825,9 @@ } }, "node_modules/weak-lru-cache": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.1.2.tgz", - "integrity": "sha512-Bi5ae8Bev3YulgtLTafpmHmvl3vGbanRkv+qqA2AX8c3qj/MUdvSuaHq7ukDYBcMDINIaRPTPEkXSNCqqWivuA==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==" }, "node_modules/webidl-conversions": { "version": "4.0.2", @@ -7587,17 +6857,6 @@ "webidl-conversions": "^4.0.2" } }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, "node_modules/which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -7633,9 +6892,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "engines": { "node": ">=0.10.0" } @@ -7737,7 +6996,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yaml": { "version": "1.10.2", @@ -7747,6 +7007,19 @@ "node": ">= 6" } }, + "parcel-optimizer-sri": { + "version": "1.0.0", + "extraneous": true, + "license": "ISC", + "dependencies": { + "@parcel/node-resolver-core": "^2.0.0", + "@parcel/plugin": "^2.0.0", + "node-fetch": "^2.6.5" + }, + "engines": { + "parcel": "2.x" + } + }, "parcel-resolver-like-a-browser": { "version": "1.0.0", "license": "ISC", @@ -7758,15 +7031,43 @@ "engines": { "parcel": "2.x" } + }, + "parcel-sri": { + "version": "1.0.0", + "extraneous": true, + "license": "ISC", + "dependencies": { + "@parcel/node-resolver-core": "^2.0.0", + "@parcel/plugin": "^2.0.0", + "node-fetch": "^2.6.5" + }, + "engines": { + "parcel": "2.x" + } + }, + "parcel-transformer-sri": { + "version": "1.0.0", + "extraneous": true, + "license": "ISC", + "dependencies": { + "@parcel/node-resolver-core": "^2.0.0", + "@parcel/plugin": "^2.0.0", + "node-fetch": "^2.6.5", + "posthtml": "^0.16.6" + }, + "engines": { + "parcel": "2.x" + } } }, "dependencies": { "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -7796,29 +7097,22 @@ "source-map": "^0.5.0" }, "dependencies": { - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, "@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { @@ -7833,36 +7127,32 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, - "@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "requires": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - } + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, - "@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -7929,17 +7219,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.14.5", @@ -7957,19 +7252,19 @@ } }, "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-syntax-flow": { "version": "7.14.5", @@ -7989,27 +7284,28 @@ } }, "@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -8022,18 +7318,116 @@ } }, "@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, - "@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@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==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@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==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==" + }, + "@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "requires": { + "@lezer/common": "^0.15.0" + } + }, + "@mischnic/json-sourcemap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz", + "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==", + "requires": { + "@lezer/common": "^0.15.7", + "@lezer/lr": "^0.15.4", + "json5": "^2.2.1" + } + }, + "@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "optional": true }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -8092,24 +7486,22 @@ } }, "@parcel/cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.0.0.tgz", - "integrity": "sha512-HThLpk1qXkyRyWrqXh5EYdINFd4tl4SCUgbipZ46pQWtwZ8+0nmudbuszeRKi1UCyNCdgktcZu8xmXmSVQNDyA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.5.0.tgz", + "integrity": "sha512-3kOO3cZQv0FAKhrMHGLdb4Qtzpmy78Q6jPN3u8eCY4yqeDTnyQBZvWNHoyCm5WlmL8y6Q6REYMbETLxSH1ggAQ==", "requires": { - "@parcel/logger": "^2.0.0", - "@parcel/utils": "^2.0.0", - "lmdb-store": "^1.5.5" + "@parcel/fs": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/utils": "2.5.0", + "lmdb": "2.2.4" } }, "@parcel/codeframe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.0.0.tgz", - "integrity": "sha512-34L0qa72rxtzng2Bw195YYVAZWhuWm1V9u+0bHfajyl242BDUbUNpQOowP/AYRjj7XSmIN6XCUv3luogvMPo8A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.5.0.tgz", + "integrity": "sha512-qafqL8Vu2kr932cCWESoDEEoAeKVi7/xdzTBuhzEJng1AfmRT0rCbt/P4ao3RjiDyozPSjXsHOqM6GDZcto4eQ==", "requires": { - "chalk": "^4.1.0", - "emphasize": "^4.2.0", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" + "chalk": "^4.1.0" }, "dependencies": { "ansi-styles": { @@ -8203,128 +7595,101 @@ } }, "@parcel/core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.0.0.tgz", - "integrity": "sha512-wiY3XyGetCpek0aEi+xB0eQQUn4v9xt20AKx71KpU30SShwcHnVEUEVxuVEi7+NgJQsUCsp8nXUeZluwRTfUFA==", - "requires": { - "@parcel/cache": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/events": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/graph": "^2.0.0", - "@parcel/hash": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/package-manager": "^2.0.0", - "@parcel/plugin": "^2.0.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.5.0.tgz", + "integrity": "sha512-dygDmPsfAYJKTnUftcbEzjCik7AAaPbFvJW8ETYz8diyjkAG9y6hvCAZIrJE5pNOjFzg32en4v4UWv8Sqlzl9g==", + "requires": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/events": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/graph": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/package-manager": "2.5.0", + "@parcel/plugin": "2.5.0", "@parcel/source-map": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", - "@parcel/workers": "^2.0.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", + "@parcel/workers": "2.5.0", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", "clone": "^2.1.1", "dotenv": "^7.0.0", "dotenv-expand": "^5.1.0", - "json-source-map": "^0.6.1", - "json5": "^1.0.1", - "micromatch": "^4.0.2", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", "nullthrows": "^1.1.1", - "semver": "^5.4.1" + "semver": "^5.7.1" } }, "@parcel/diagnostic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.0.0.tgz", - "integrity": "sha512-cADyFWaMlhDawQdraFt2TECpiD/DvQ76L+RK97X7sUj5b+cGY7fjrnWPKRVmog5+OoNlbmh1EO3FOLx5vuxzww==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.5.0.tgz", + "integrity": "sha512-KiMGGRpEV7wl5gjcxBKcgX84a+cG+IEn94gwy5LK3lENR09nuKShqqgKGAmj/17CobJgw1QNP94/H4Md+oxIWg==", "requires": { - "json-source-map": "^0.6.1", + "@mischnic/json-sourcemap": "^0.1.0", "nullthrows": "^1.1.1" } }, "@parcel/events": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.0.0.tgz", - "integrity": "sha512-v9+pXLtgc44+eIbNAs/SB2tyXKUv+5XF1f3TRsLJ44276e9ksa3Cstrs1EFxZtpi03UoXkXJQoJljGigb2bt8A==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.5.0.tgz", + "integrity": "sha512-Gc2LPwL1H34Ony5MENbKZg7wvCscZ4x9y7Fu92sfbdWpLo3K13hVtsX3TMIIgYt3B7R7OmO8yR880U2T+JfVkQ==" }, "@parcel/fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.0.0.tgz", - "integrity": "sha512-1FQIVDO3zWE2vv9EJmLJq+EeZ7DE4lwi/e0fR1PAS1g5YbO9n3u01Xnpzy/jmlL14LnBXdhy4r7OBziShYLK6w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.5.0.tgz", + "integrity": "sha512-YYr14BWtx/bJ+hu6PPQQ6G/3omOTWgVqEw+UFI3iQH3P6+e0LRXW/Ja1yAcJeepGcTwIP0opnXZBQOm8PBQ2SA==", "requires": { - "@parcel/fs-search": "^2.0.0", - "@parcel/fs-write-stream-atomic": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/fs-search": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", "@parcel/watcher": "^2.0.0", - "@parcel/workers": "^2.0.0", - "graceful-fs": "^4.2.4", - "mkdirp": "^0.5.1", - "ncp": "^2.0.0", - "nullthrows": "^1.1.1", - "rimraf": "^3.0.2", - "utility-types": "^3.10.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - } + "@parcel/workers": "2.5.0" } }, "@parcel/fs-search": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.0.0.tgz", - "integrity": "sha512-OVWA0elZm5BKaHgS5FnvlmMwQiU++0sGW7PIyaNJnY0lvpZndU+Pot0xNTSrG3Aq7OkpQlcUWkEMA8KtkHZH1A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.5.0.tgz", + "integrity": "sha512-uBONkz9ZCNSOqbPGWJY3MNl+pqBTfvzHH9+4UhzHEHPArvK2oD0+syYPVE60+zGrxybXTESYMCJp4bHvH6Z2hA==", "requires": { "detect-libc": "^1.0.3" } }, - "@parcel/fs-write-stream-atomic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/fs-write-stream-atomic/-/fs-write-stream-atomic-2.0.0.tgz", - "integrity": "sha512-PSvAcu7f+3zzjQZuYJjPQVRI99Lu2HEphr04JChwdO5wr/sm6dYFRQdL0SahH/vF1tnEaBFxC4vTslNEBT+9bg==", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^1.0.2", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, "@parcel/graph": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.0.0.tgz", - "integrity": "sha512-ZI3pYSWWqGAFi4qDa00kieiKpHz3xY9vPr4iVTjNiNXD6fU7C+Y25mxPmLv4uYbJTzccAo0iaN9VGqPo/FyiBg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.5.0.tgz", + "integrity": "sha512-qa2VtG08dJyTaWrxYAkMIlkoDRSPoiqLDNxxHKplkcxAjXBUw0/AkWaz82VO5r1G6jfOj+nM30ajH9uygZYwbw==", "requires": { + "@parcel/utils": "2.5.0", "nullthrows": "^1.1.1" } }, "@parcel/hash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.0.0.tgz", - "integrity": "sha512-+Yq+mGnZOSyJ6atLCFvA1Kyg/NVysVzlwSNrmA3dc3yO63GtXojQEEyW9U20d+Bj/DVlocLO52Z61d4P9ak4Tw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.5.0.tgz", + "integrity": "sha512-47JL0XpB7UvIW6Ijf8vv+yVMt9dLvB/lRlBHFmAkmovisueVMVbYD7smxVZnCSehD8UH8BcymKbMzyL5dimgoQ==", "requires": { "detect-libc": "^1.0.3", - "xxhash-wasm": "^0.4.1" + "xxhash-wasm": "^0.4.2" } }, "@parcel/logger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.0.0.tgz", - "integrity": "sha512-jpESL6m4tEGP+Yj/PZGb6ellrOx3irEIvSjbhwZBGoXaApqqvB352dLXrVJ/vyrmzj9YLNdm2rPWeZWkMDGgMA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.5.0.tgz", + "integrity": "sha512-pT1L3ceH6trL1N3I3r2HawPjz/PCubOo/Kazu7IeXsMsKVjj1a6AeieZHzkNZIbhiGPtm/cHbBNLz2zTWDLeOA==", "requires": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/events": "^2.0.0" + "@parcel/diagnostic": "2.5.0", + "@parcel/events": "2.5.0" } }, "@parcel/markdown-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.0.0.tgz", - "integrity": "sha512-AgxIXRaEpNi1GukjWC6FTLO7t/EImv+3KuwFF5tGlWhXO41V1Igl6gXCDpzRmTk5dBbdqOWdRWip1O5Qy74cwA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.5.0.tgz", + "integrity": "sha512-ixkNF3KWIqxMlfxTe9Gb2cp/uNmklQev8VEUxujMVxmUfGyQs4859zdJIQlIinabWYhArhsXATkVf3MzCUN6TQ==", "requires": { "chalk": "^4.1.0" }, @@ -8495,21 +7860,17 @@ } }, "@parcel/package-manager": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.0.0.tgz", - "integrity": "sha512-zJY5SOaEC6pyU9bXLmGlnD7VRWURsbxPVNHVreFNttHg2DaT+0u1R5NAoor4BG38esw2TaGdi8QU9TmsTyhSUQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.5.0.tgz", + "integrity": "sha512-zTuF55/lITUjw9dUU/X0HiF++589xbPXw/zUiG9T6s8BQThLvrxAhYP89S719pw7cTqDimGkTxnIuK+a0djEkg==", "requires": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", - "@parcel/workers": "^2.0.0", - "command-exists": "^1.2.6", - "cross-spawn": "^6.0.4", - "nullthrows": "^1.1.1", - "semver": "^5.4.1", - "split2": "^3.1.1" + "@parcel/diagnostic": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", + "@parcel/workers": "2.5.0", + "semver": "^5.7.1" } }, "@parcel/packager-css": { @@ -8570,11 +7931,11 @@ } }, "@parcel/plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.0.0.tgz", - "integrity": "sha512-yOBRbizd27vivgFRxpTBxfViTIYMdoLeAvRHEoL49dkymKkKtq09hZQtVS+iQmypwyJnp4cMsG8FwN+srJub7w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.5.0.tgz", + "integrity": "sha512-obtb6/Gql6YFQ86bdv75A2Noabx8679reFZeyfKKf0L7Lppx4DFQetXwM9XVy7Gx6hJ1Ekm3UMuuIyVJk33YHQ==", "requires": { - "@parcel/types": "^2.0.0" + "@parcel/types": "2.5.0" } }, "@parcel/reporter-cli": { @@ -8732,16 +8093,6 @@ "json5": "^2.1.0", "nullthrows": "^1.1.1", "semver": "^5.7.0" - }, - "dependencies": { - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } - } } }, "@parcel/transformer-css": { @@ -8816,46 +8167,35 @@ "requires": { "@parcel/plugin": "^2.0.0", "json5": "^2.1.0" - }, - "dependencies": { - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } - } } }, "@parcel/transformer-postcss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.0.0.tgz", - "integrity": "sha512-CnDgHs2G6nAQghpMWrB84K2QYVLQ2q8CucD4XTe9xc2mo1ObeCtpEijAxsORyp4TTZYOLsw4hmVbv/eY8uLOLg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.5.0.tgz", + "integrity": "sha512-IPNlWElekdQHMTBqhdwJNBCQomuYyo7xgNBdnTrt9VJ+R5ihy6n7ZJSWIAJXAH9VZxETTtunfrzRtgkmtjTeZQ==", "requires": { - "@parcel/hash": "^2.0.0", - "@parcel/plugin": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/plugin": "2.5.0", + "@parcel/utils": "2.5.0", "clone": "^2.1.1", - "css-modules-loader-core": "^1.1.0", "nullthrows": "^1.1.1", - "postcss-modules": "^3.2.2", - "postcss-value-parser": "^4.1.0", - "semver": "^5.4.1" + "postcss-value-parser": "^4.2.0", + "semver": "^5.7.1" } }, "@parcel/transformer-posthtml": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.0.0.tgz", - "integrity": "sha512-jaiymnLQshy99zNxp9JLvFWFGm41LWULFRwjHep1ALGyphcxPiw/zq4o0K7pvc8shlAXvE2M/3Q2SGFyCwe+zA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.5.0.tgz", + "integrity": "sha512-AZxg1XD8OXOS4bEGEmBBR+X9T9qoFdVsbVUg498zzejYSka1ZQHF7TgLI/+pUnE+ZVYNIp7/G0xXqsRVKMKmdQ==", "requires": { - "@parcel/plugin": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/plugin": "2.5.0", + "@parcel/utils": "2.5.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", "posthtml-render": "^3.0.0", - "semver": "^5.4.1" + "semver": "^5.7.1" } }, "@parcel/transformer-raw": { @@ -8891,45 +8231,31 @@ } }, "@parcel/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.0.0.tgz", - "integrity": "sha512-117vnZuQ1HzXOrIo8qAFgG0lMfz5dck7u+smlaZP1aRxVJaxWBo2C2+8JoTPHjRn9tE5IZGH9PVIZW+X3F474g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.5.0.tgz", + "integrity": "sha512-bA0fhG6aXSGYEVo5Dt96x6lseUQHeVZVzgmiRdZsvb614Gvx22ItfaKhPmAVbM9vzbObZDHl9l9G2Ovw8Xve4g==", "requires": { - "@parcel/cache": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/fs": "^2.0.0", - "@parcel/package-manager": "^2.0.0", + "@parcel/cache": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/fs": "2.5.0", + "@parcel/package-manager": "2.5.0", "@parcel/source-map": "^2.0.0", - "@parcel/workers": "^2.0.0", + "@parcel/workers": "2.5.0", "utility-types": "^3.10.0" } }, "@parcel/utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.0.0.tgz", - "integrity": "sha512-4SX8qNyImHLyvVls1U9rxF+h+1kbbdWpxnRiHOFPBYW6H1LiUNBjXPPffTEpKb+RFOqmQ2uNh0aP0mCmROPfXg==", - "requires": { - "@iarna/toml": "^2.2.0", - "@parcel/codeframe": "^2.0.0", - "@parcel/diagnostic": "^2.0.0", - "@parcel/hash": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/markdown-ansi": "^2.0.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-kaLGXtQuOOH55KZqXdYDvczhh3mk2eeTVqrrXuuihGjbLKYFlUW2tFDm+5r2s9nCPwTQxOO43ZEOCKSnia+e4w==", + "requires": { + "@parcel/codeframe": "2.5.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/hash": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/markdown-ansi": "2.5.0", "@parcel/source-map": "^2.0.0", - "ansi-html-community": "0.0.8", - "chalk": "^4.1.0", - "clone": "^2.1.1", - "fast-glob": "3.1.1", - "fastest-levenshtein": "^1.0.8", - "is-glob": "^4.0.0", - "is-url": "^1.2.2", - "json5": "^1.0.1", - "lru-cache": "^6.0.0", - "micromatch": "^4.0.4", - "node-forge": "^0.10.0", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "terminal-link": "^2.1.1" + "chalk": "^4.1.0" }, "dependencies": { "ansi-styles": { @@ -8987,18 +8313,24 @@ } }, "@parcel/workers": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.0.0.tgz", - "integrity": "sha512-emfezGXmmz5NNrtBvbZO4cFosdpEL+OqhIa4SpUH63aedx+9so/GI/rMp19FmTi0qPKQhOLJmD4VZ2RZHbZM4w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.5.0.tgz", + "integrity": "sha512-/Ow5OKJWs+9OzV3Jy4J++VnbNx0j3ls/M1CGVBLiBWyCada9DMtquYoBQ4Sk6Uam50BKkIFYetGOeXPNQyyMjg==", "requires": { - "@parcel/diagnostic": "^2.0.0", - "@parcel/logger": "^2.0.0", - "@parcel/types": "^2.0.0", - "@parcel/utils": "^2.0.0", + "@parcel/diagnostic": "2.5.0", + "@parcel/logger": "2.5.0", + "@parcel/types": "2.5.0", + "@parcel/utils": "2.5.0", "chrome-trace-event": "^1.0.2", "nullthrows": "^1.1.1" } }, + "@plutojl/posthtml-crossorigin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@plutojl/posthtml-crossorigin/-/posthtml-crossorigin-1.0.0.tgz", + "integrity": "sha512-Rblfw7JRp11OVON1bKFBfz+N+kE6T3eYLaqUTSrT7W2+UyLDJJC63U8iJhjbs12Eo6f3XMe77ktM6hE0quzqgQ==", + "dev": true + }, "@swc/helpers": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.13.tgz", @@ -9072,26 +8404,6 @@ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - } - } - }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -9157,20 +8469,15 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" - }, "astring": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/astring/-/astring-1.7.5.tgz", "integrity": "sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA==" }, "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "async-limiter": { "version": "1.0.1", @@ -9223,37 +8530,20 @@ "tweetnacl": "^0.14.3" } }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "boolbase": { "version": "1.0.0", @@ -9331,31 +8621,19 @@ } }, "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", + "elliptic": "^6.5.4", "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" } }, "browserify-zlib": { @@ -9495,7 +8773,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "colord": { "version": "2.8.0", @@ -9510,11 +8788,6 @@ "delayed-stream": "~1.0.0" } }, - "command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -9586,11 +8859,6 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz", "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==" }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -9644,18 +8912,6 @@ "sha.js": "^2.4.8" } }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -9687,81 +8943,6 @@ "timsort": "^0.3.0" } }, - "css-modules-loader-core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", - "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=", - "requires": { - "icss-replace-symbols": "1.1.0", - "postcss": "6.0.1", - "postcss-modules-extract-imports": "1.1.0", - "postcss-modules-local-by-default": "1.2.0", - "postcss-modules-scope": "1.1.0", - "postcss-modules-values": "1.3.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" - }, - "postcss": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz", - "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=", - "requires": { - "chalk": "^1.1.3", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, "css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -9774,15 +8955,6 @@ "nth-check": "^2.0.0" } }, - "css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, "css-tree": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", @@ -10059,11 +9231,11 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "ejs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", + "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", "requires": { - "jake": "^10.6.1" + "jake": "^10.8.5" } }, "electron-to-chromium": { @@ -10097,66 +9269,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" - }, - "emphasize": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/emphasize/-/emphasize-4.2.0.tgz", - "integrity": "sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg==", - "requires": { - "chalk": "^4.0.0", - "highlight.js": "~10.4.0", - "lowlight": "~1.17.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -10230,7 +9342,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "1.14.3", @@ -10331,16 +9443,6 @@ "punycode": "^1.3.2" } }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" - }, - "fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -10349,20 +9451,30 @@ "reusify": "^1.0.4" } }, - "fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", - "requires": { - "format": "^0.2.0" - } - }, "filelist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", + "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "filesize": { @@ -10408,9 +9520,9 @@ } }, "follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" }, "foreach": { "version": "2.0.5", @@ -10432,11 +9544,6 @@ "mime-types": "^2.1.12" } }, - "format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=" - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10447,14 +9554,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "generic-names": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", - "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==", - "requires": { - "loader-utils": "^1.1.0" - } - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -10534,11 +9633,6 @@ "slash": "^3.0.0" } }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -10561,21 +9655,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -10584,7 +9663,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-symbols": { "version": "1.0.2", @@ -10607,18 +9686,6 @@ "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "hash.js": { @@ -10630,11 +9697,6 @@ "minimalistic-assert": "^1.0.1" } }, - "highlight.js": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.1.tgz", - "integrity": "sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==" - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -10732,50 +9794,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - }, - "icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "requires": { - "postcss": "^7.0.14" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, - "iferr": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", - "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==" - }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", @@ -10790,11 +9813,6 @@ "resolve-from": "^4.0.0" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -10873,11 +9891,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -11011,11 +10024,6 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -11024,44 +10032,71 @@ "call-bind": "^1.0.0" } }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "isbinaryfile": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "requires": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "js-tokens": { @@ -11128,41 +10163,33 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "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==" }, - "json-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", - "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, @@ -11185,27 +10212,16 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, - "lmdb-store": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/lmdb-store/-/lmdb-store-1.6.8.tgz", - "integrity": "sha512-Ltok13VVAfgO5Fdj/jVzXjPJZjefl1iENEHerZyAfAlzFUhvOrA73UdKItqmEPC338U29mm56ZBQr5NJQiKXow==", + "lmdb": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.2.4.tgz", + "integrity": "sha512-gto+BB2uEob8qRiTlOq+R3uX0YNHsX9mjxj9Sbdue/LIKqu6IlZjrsjKeGyOMquc/474GEqFyX2pdytpydp0rQ==", "requires": { - "mkdirp": "^1.0.4", - "msgpackr": "^1.3.7", + "msgpackr": "^1.5.4", "nan": "^2.14.2", "node-gyp-build": "^4.2.3", - "ordered-binary": "^1.0.0", - "weak-lru-cache": "^1.0.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "ordered-binary": "^1.2.4", + "weak-lru-cache": "^1.2.2" } }, "lodash": { @@ -11213,11 +10229,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, "lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", @@ -11285,28 +10296,11 @@ "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "lowlight": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.17.0.tgz", - "integrity": "sha512-vmtBgYKD+QVNy7tIa7ulz5d//Il9R4MooOVh4nkOf9R9Cb/Dk5TXMSTieg/vDulkBkIWj59/BIlyFQxT9X1oAQ==", - "requires": { - "fault": "^1.0.0", - "highlight.js": "~10.4.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "md5.js": { @@ -11389,17 +10383,21 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } }, "mkdirp": { "version": "1.0.4", @@ -11412,22 +10410,26 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "msgpackr": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.4.5.tgz", - "integrity": "sha512-AFmAehFqidJaSAWig6cp+8MZU3r7rtL1sgBxzXR9YICfG8vGRemCcVoqPG81CqRHdxP/VX/DyM85wltqPseXNw==", - "optional": true, + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.1.tgz", + "integrity": "sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==", "requires": { - "msgpackr-extract": "^1.0.14" + "msgpackr-extract": "^3.0.2" } }, "msgpackr-extract": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-1.0.14.tgz", - "integrity": "sha512-t8neMf53jNZRF+f0H9VvEUVvtjGZ21odSBRmFfjZiyxr9lKYY0mpY3kSWZAIc7YWXtCZGOvDQVx2oqcgGiRBrw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "optional": true, "requires": { - "nan": "^2.14.2", - "node-gyp-build": "^4.2.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2", + "node-gyp-build-optional-packages": "5.0.7" } }, "nan": { @@ -11441,19 +10443,9 @@ "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==" }, "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, "node-addon-api": { "version": "3.2.1", @@ -11461,9 +10453,9 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" }, "node-fetch": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", - "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" }, @@ -11489,16 +10481,17 @@ } } }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, "node-gyp-build": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" }, + "node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "optional": true + }, "node-releases": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", @@ -11586,15 +10579,6 @@ "mimic-fn": "^2.1.0" } }, - "open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - } - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -11670,9 +10654,9 @@ } }, "ordered-binary": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.1.3.tgz", - "integrity": "sha512-tDTls+KllrZKJrqRXUYJtIcWIyoQycP7cVN7kzNNnhHKF2bMKHflcAQK+pF2Eb1iVaQodHxqZQr0yv4HWLGBhQ==" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.2.5.tgz", + "integrity": "sha512-djRmZoEpOGvIRW7ufsCDHtvcUa18UC9TxnPbHhSVFZHsoyg0dtut1bWtBZ/fmxdPN62oWXrV6adM7NoWU+CneA==" }, "os-browserify": { "version": "0.3.0", @@ -11750,6 +10734,14 @@ } } }, + "parcel-reporter-bundle-manifest": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parcel-reporter-bundle-manifest/-/parcel-reporter-bundle-manifest-1.0.0.tgz", + "integrity": "sha512-/fQDwYWT9LsXRddNikci9Jox6bJdKnfGKpnVd4++1TRUYRLXvFVGQjyGZg8Gsu/JQN6psST8ilRmpg61yN37pQ==", + "requires": { + "@parcel/plugin": "^2.0.0" + } + }, "parcel-resolver-like-a-browser": { "version": "file:parcel-resolver-like-a-browser", "requires": { @@ -11814,11 +10806,6 @@ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, "path-to-regexp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", @@ -11991,183 +10978,6 @@ "postcss-selector-parser": "^6.0.5" } }, - "postcss-modules": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-3.2.2.tgz", - "integrity": "sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw==", - "requires": { - "generic-names": "^2.0.1", - "icss-replace-symbols": "^1.1.0", - "lodash.camelcase": "^4.3.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "string-hash": "^1.1.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", - "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-modules-extract-imports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", - "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", - "requires": { - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, "postcss-normalize-charset": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", @@ -12300,17 +11110,27 @@ } }, "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "posthtml": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.5.tgz", - "integrity": "sha512-1qOuPsywVlvymhTFIBniDXwUDwvlDri5KUQuBqjmCc8Jj4b/HDSVWU//P6rTWke5rzrk+vj7mms2w8e1vD0nnw==", + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", "requires": { - "posthtml-parser": "^0.10.0", + "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" + }, + "dependencies": { + "posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "requires": { + "htmlparser2": "^7.1.1" + } + } } }, "posthtml-parser": { @@ -12329,6 +11149,16 @@ "is-json": "^2.0.1" } }, + "posthtml-sri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/posthtml-sri/-/posthtml-sri-1.2.0.tgz", + "integrity": "sha512-2PFUHkDMJIOX5AoljGVLgJLleDyUz779Czn9R0MoxSnpmTcheGHM85bt/6bZ33Dm20gQTWyPbiSmfIfz1d3tIg==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "ssri": "^8.0.0" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -12339,11 +11169,6 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -12393,9 +11218,9 @@ } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, "querystring": { "version": "0.2.0", @@ -12440,32 +11265,13 @@ "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==" }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "regenerator-runtime": { @@ -12562,14 +11368,6 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -12606,20 +11404,20 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", "fast-url-parser": "1.1.3", "mime-types": "2.1.18", - "minimatch": "3.0.4", + "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "2.2.1", "range-parser": "1.2.0" @@ -12639,19 +11437,6 @@ "safe-buffer": "^5.0.1" } }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -12672,39 +11457,6 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - } - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12731,26 +11483,6 @@ } } }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, "srcset": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", @@ -12772,6 +11504,15 @@ "tweetnacl": "~0.14.0" } }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -12794,18 +11535,6 @@ "requires": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "stream-http": { @@ -12817,18 +11546,6 @@ "inherits": "^2.0.4", "readable-stream": "^3.6.0", "xtend": "^4.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "string_decoder": { @@ -12839,11 +11556,6 @@ "safe-buffer": "~5.2.0" } }, - "string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -12897,30 +11609,6 @@ "has-flag": "^3.0.0" } }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "svgo": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz", @@ -12945,34 +11633,26 @@ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, "terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + }, "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==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" } } }, @@ -13265,9 +11945,9 @@ } }, "weak-lru-cache": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.1.2.tgz", - "integrity": "sha512-Bi5ae8Bev3YulgtLTafpmHmvl3vGbanRkv+qqA2AX8c3qj/MUdvSuaHq7ukDYBcMDINIaRPTPEkXSNCqqWivuA==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==" }, "webidl-conversions": { "version": "4.0.2", @@ -13297,14 +11977,6 @@ "webidl-conversions": "^4.0.2" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, "which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -13331,9 +12003,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==" }, "wrap-ansi": { "version": "7.0.0", @@ -13402,7 +12074,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "yaml": { "version": "1.10.2", diff --git a/frontend-bundler/package.json b/frontend-bundler/package.json index f981415a7c..c05068d4c9 100644 --- a/frontend-bundler/package.json +++ b/frontend-bundler/package.json @@ -6,8 +6,8 @@ "version": "1.0.0", "description": "", "scripts": { - "start": "cd ../frontend && parcel --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html sample.html", - "build": "cd ../frontend && parcel build --public-url . --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html sample.html", + "start": "cd ../frontend && parcel --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html", + "build": "cd ../frontend && parcel build --no-source-maps --public-url . --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html && node ../frontend-bundler/add_sri.js ../frontend-dist/editor.html", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", @@ -16,11 +16,15 @@ "@parcel/config-default": "^2.0.0", "mkdirp": "^1.0.4", "parcel": "^2.0.0", + "parcel-reporter-bundle-manifest": "^1.0.0", "parcel-resolver-like-a-browser": "file:../frontend-bundler/parcel-resolver-like-a-browser" }, "devDependencies": { "@parcel/optimizer-data-url": "^2.0.0", "@parcel/transformer-inline-string": "^2.0.0", - "@types/node": "^16.11.6" + "@plutojl/posthtml-crossorigin": "^1.0.0", + "@types/node": "^16.11.6", + "posthtml": "^0.16.6", + "posthtml-sri": "^1.2.0" } } diff --git a/frontend-bundler/parcel-resolver-like-a-browser/https-resolver.js b/frontend-bundler/parcel-resolver-like-a-browser/https-resolver.js index 018dcfbdfa..d17540df00 100644 --- a/frontend-bundler/parcel-resolver-like-a-browser/https-resolver.js +++ b/frontend-bundler/parcel-resolver-like-a-browser/https-resolver.js @@ -4,11 +4,24 @@ let fetch = require("node-fetch") let fs = require("fs/promises") let mkdirp = require("mkdirp") let { URL } = require("url") +let crypto = require("crypto") let DONT_INCLUDE = { isExcluded: true } const fileExists = async (path) => !!(await fs.stat(path).catch((e) => false)) +async function keep_trying(fn, max_tries = 10) { + try { + return await fn() + } catch (e) { + if (max_tries === 0) { + throw e + } else { + return await keep_trying(fn, max_tries - 1) + } + } +} + module.exports = new Resolver({ async resolve({ specifier, dependency, options }) { let my_temp_cave = path.join(options.cacheDir, ".net") @@ -41,26 +54,54 @@ module.exports = new Resolver({ let url = new URL(specifier) if (url.port !== "") throw new Error(`Port in urls not supported yet (${specifier})`) - if (url.search !== "") throw new Error(`Search in urls not supported yet (${specifier})`) if (url.hash !== "") throw new Error(`Hash in urls not supported yet (${specifier})`) if (url.username !== "") throw new Error(`Username in urls not supported (${specifier})`) if (url.password !== "") throw new Error(`Password in urls not supported (${specifier})`) - let url_to_path = path.join(url.protocol.slice(0, -1), url.hostname, ...url.pathname.slice(1).split("/")) + // If no file extension is given in the URL, guess one automatically. + let found_extension = /\.[a-zA-Z][a-zA-Z0-9]+$/.exec(url.pathname)?.[0] + + let extension_to_add = found_extension ?? (dependency.specifierType === "esm" ? ".mjs" : "") + + let search_component = "" + if (url.search !== "") { + search_component = "." + crypto.createHmac("sha256", "42").update(url.search).digest("hex").slice(0, 10) + } + + // If a search is given in the URL, this will search be appended to the path, so we need to repeat the extension. + let should_add_extension = search_component !== "" || found_extension == null + let suffix = should_add_extension ? extension_to_add : "" + + // Create a folder structure and file for the import. This folder structure will match the URL structure, to make sure that relative imports still work. + let filename_parts = (url.pathname.slice(1) + search_component + suffix).split("/") + let url_to_path = path.join(url.protocol.slice(0, -1), url.hostname, ...filename_parts) let fullpath = path.join(my_temp_cave, url_to_path) let folder = path.dirname(fullpath) if (!(await fileExists(fullpath))) { - let response = await fetch(specifier) - if (response.status !== 200) { - throw new Error(`${specifier} returned ${response.status}`) - } - // Can't directly use the value from the request, as parcel really wants a string, - // and converting binary assets into strings and then passing them doesn't work 🤷‍♀️. - let buffer = await response.buffer() - - await mkdirp(folder) - await fs.writeFile(fullpath, buffer) + await keep_trying(async () => { + let response = await fetch(specifier) + if (response.status !== 200) { + throw new Error(`${specifier} returned ${response.status}`) + } + // Can't directly use the value from the request, as parcel really wants a string, + // and converting binary assets into strings and then passing them doesn't work 🤷‍♀️. + let buffer = await response.buffer() + + const response_length = buffer.length + + if (response_length === 0) { + throw new Error(`${specifier} returned an empty reponse.`) + } + + await mkdirp(folder) + const write_result = await fs.writeFile(fullpath, buffer) + + // Verify that the file was written correctly: + if (write_result !== undefined || (await fs.readFile(fullpath)).length !== response_length) { + throw new Error(`Failed to write file ${fullpath}`) + } + }) } return { filePath: fullpath } diff --git a/frontend/Desktop.d.ts b/frontend/Desktop.d.ts new file mode 100644 index 0000000000..44d98d1749 --- /dev/null +++ b/frontend/Desktop.d.ts @@ -0,0 +1,55 @@ +declare global { + /** + * This namespace is meant for [PlutoDesktop](https://github.com/JuliaPluto/PlutoDesktop) + * related types and interfaces. + */ + namespace Desktop { + /** + * This enum has to be in sync with the enum "PlutoExport" + * defined in PlutoDesktop/{branch:master}/types/enums.ts + * + * @note Unfortunately enums can't be exported from .d.ts files. + * Inorder to use this, just map integers to the enum values + * - PlutoExport.FILE -> **0** + * - PlutoExport.HTML -> **1** + * - PlutoExport.STATE -> **2** + * - PlutoExport.PDF -> **3** + */ + enum PlutoExport { + FILE, + HTML, + STATE, + PDF, + } + + /** + * This type has to be in sync with the interface "Window" + * defined in PlutoDesktop/{branch:master}/src/renderer/preload.d.ts + */ + type PlutoDesktop = { + ipcRenderer: { + sendMessage(channel: String, args: unknown[]): void + on(channel: string, func: (...args: unknown[]) => void): (() => void) | undefined + once(channel: string, func: (...args: unknown[]) => void): void + } + fileSystem: { + /** + * @param type [default = 'new'] whether you want to open a new notebook + * open a notebook from a path or from a url + * @param pathOrURL location to the file, not needed if opening a new file, + * opens that notebook. If false and no path is there, opens the file selector. + * If true, opens a new blank notebook. + */ + openNotebook(type?: "url" | "path" | "new", pathOrURL?: string): void + shutdownNotebook(id?: string): void + moveNotebook(id?: string): void + exportNotebook(id: string, type: PlutoExport): void + } + } + } + interface Window { + plutoDesktop?: Desktop.PlutoDesktop + } +} + +export {} diff --git a/frontend/binder.css b/frontend/binder.css index fd68d3a771..1aadb93ec2 100644 --- a/frontend/binder.css +++ b/frontend/binder.css @@ -53,7 +53,7 @@ binder-spinner { } } -#launch_binder { +.edit_or_run { /* position: absolute; */ position: fixed; z-index: 2000; @@ -62,7 +62,7 @@ binder-spinner { /* width: 153.2px; */ /* height: 60px; */ } -#launch_binder button { +.binder_help_text button { padding: 7px 20px; background: #fffdf7; box-shadow: 0px 0px 20px 0px #ffffff; @@ -76,13 +76,12 @@ binder-spinner { display: block; } -body.wiggle_binder button#launch_binder, -body.wiggle_binder #binder_launch_help { +body.wiggle_binder .edit_or_run > button { /* position: fixed; */ - animation: wiggle 0.3s ease-in-out 0s 1; + animation: wiggle-binder-button 0.3s ease-in-out 0s 1; } -@keyframes wiggle { +@keyframes wiggle-binder-button { 0% { transform: rotate(0deg); } @@ -97,15 +96,16 @@ body.wiggle_binder #binder_launch_help { } } -#launch_binder button img { +.binder_help_text button img { margin: -8px; margin-left: 0px; font-style: normal; color: black; font-weight: 900; + height: 2.2em; } -#binder_launch_help { +.edit_or_run > button { width: 100%; display: block; text-align: center; @@ -113,40 +113,44 @@ body.wiggle_binder #binder_launch_help { box-shadow: none; cursor: pointer; background: unset; - background-color: white; - border: 3px solid #3f448c5e; - font-size: 14px; - font-style: italic; + background-color: var(--overlay-button-bg); + border: 3px solid hsl(236deg 28% 50% / 46%); + font-size: 16px; + /* font-style: italic; */ font-family: "Roboto Mono"; - letter-spacing: -0.2px; - color: #0000009c; + font-family: var(--lato-ui-font-stack); + letter-spacing: 0.1px; + color: var(--black); white-space: nowrap; padding: 8px 16px; border-radius: 30px; } -#binder_launch_help:hover { +.edit_or_run > button:hover { text-decoration: underline; } -#binder_help_text { +.binder_help_text { --width: min(85vw, 570px); position: fixed; - top: 5rem; max-height: calc(100vh - 4rem); overflow: auto; width: var(--width); padding: 16px; border-radius: 8px; - left: calc(50vw - var(--width) / 2); background-color: white; + color: black; + color-scheme: light; box-shadow: 0px 0px 0px 100vmax #0000004a; - - font-family: "Lato", sans-serif; + font-family: var(--sans-serif-font-stack); + border: 0; +} +.binder_help_text a { + color: black; } @media (max-width: 500px) { - #binder_help_text { + .binder_help_text { top: 0; width: 100vw; left: 0; @@ -154,13 +158,14 @@ body.wiggle_binder #binder_launch_help { } } -#binder_help_text .close { +.binder_help_text .close { position: absolute; - top: 12px; - right: 12px; - width: 24px; - height: 24px; - background-size: 24px 24px; + --size: 32px; + top: 5px; + right: 5px; + width: var(--size); + height: var(--size); + background-size: var(--size) var(--size); cursor: pointer; background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/close-outline.svg"); } @@ -176,7 +181,7 @@ body.wiggle_binder #binder_launch_help { } .download_div, -#launch_binder button, +.binder_help_text button, .download_div, .copy_div { width: max(60%, 10rem); @@ -271,13 +276,28 @@ body.wiggle_binder #binder_launch_help { font-weight: bold; margin-bottom: 0.75rem; } -#launch_binder li { +.edit_or_run li { margin-bottom: 2rem; } -#launch_binder li video, -#launch_binder li img { +.edit_or_run li video, +.edit_or_run li img { /* outline: 1px solid black; */ border: 5px solid rgb(212, 212, 212); border-radius: 5px; width: 100%; } + +.expected_runtime_box { + padding: 0.6em 1em; + border-radius: 0.6em; + font-style: italic; + display: block; + background: linear-gradient(45deg, hsl(222deg 52% 87%), #e5f7ff); + margin: 2em 0em -2em 0em; + color: #323232; +} + +.expected_runtime_box span { + font-style: initial; + font-weight: bold; +} diff --git a/frontend/common/Binder.js b/frontend/common/Binder.js index c897d402be..fdac9b1ba4 100644 --- a/frontend/common/Binder.js +++ b/frontend/common/Binder.js @@ -1,11 +1,13 @@ import immer from "../imports/immer.js" import { timeout_promise, ws_address_from_base } from "./PlutoConnection.js" import { alert, confirm } from "./alert_confirm.js" +import { with_query_params } from "./URLTools.js" -export const BinderPhase = { +export const BackendLaunchPhase = { wait_for_user: 0, requesting: 0.4, created: 0.6, + responded: 0.7, notebook_running: 0.9, ready: 1.0, } @@ -31,7 +33,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND export const trailingslash = (s) => (s.endsWith("/") ? s : s + "/") -export const request_binder = (build_url) => +export const request_binder = (build_url, { on_log }) => new Promise((resolve, reject) => { console.log("Starting binder connection to", build_url) try { @@ -42,18 +44,23 @@ export const request_binder = (build_url) => reject(err) } let phase = null + let logs = `` + let report_log = (msg) => { + console.log("Binder: ", msg, ` at ${new Date().toLocaleTimeString()}`) + + logs = `${logs}${msg}\n` + on_log(logs) + } es.onmessage = (evt) => { let msg = JSON.parse(evt.data) + if (msg.phase && msg.phase !== phase) { phase = msg.phase.toLowerCase() - console.log("Binder subphase: " + phase) - let status = phase - if (status === "ready") { - status = "server-ready" - } + + report_log(`\n\n⏱️ Binder subphase: ${phase}\n`) } if (msg.message) { - console.log("Binder message: " + msg.message) + report_log(msg.message.replace(`] `, `]\n`)) } switch (msg.phase) { case "failed": @@ -69,8 +76,6 @@ export const request_binder = (build_url) => binder_session_token: msg.token, }) break - default: - // console.log(msg); } } } catch (err) { @@ -83,23 +88,33 @@ export const request_binder = (build_url) => export const count_stat = (page) => fetch(`https://stats.plutojl.org/count?p=/${page}&s=${screen.width},${screen.height},${devicePixelRatio}#skip_sw`, { cache: "no-cache" }).catch(() => {}) +/** + * Start a 'headless' binder session, open our notebook in it, and connect to it. + */ export const start_binder = async ({ setStatePromise, connect, launch_params }) => { try { // view stats on https://stats.plutojl.org/ count_stat(`binder-start`) await setStatePromise( - immer((state) => { - state.binder_phase = BinderPhase.requesting - state.loading = true + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.backend_launch_phase = BackendLaunchPhase.requesting state.disable_ui = false + // Clear the Status of the process that generated the HTML + state.notebook.status_tree = null }) ) - const { binder_session_url, binder_session_token } = await request_binder(launch_params.binder_url.replace("mybinder.org/v2/", "mybinder.org/build/")) - const with_token = (u) => { - const new_url = new URL(u) - new_url.searchParams.set("token", binder_session_token) - return String(new_url) - } + + /// PART 1: Creating a binder session.. + const { binder_session_url, binder_session_token } = await request_binder(launch_params.binder_url.replace("mybinder.org/v2/", "mybinder.org/build/"), { + on_log: (logs) => + setStatePromise( + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.backend_launch_logs = logs + }) + ), + }) + const with_token = (u) => with_query_params(u, { token: binder_session_token }) + console.log("Binder URL:", with_token(binder_session_url)) //@ts-ignore @@ -108,58 +123,96 @@ export const start_binder = async ({ setStatePromise, connect, launch_params }) } await setStatePromise( - immer((state) => { - state.binder_phase = BinderPhase.created + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.backend_launch_phase = BackendLaunchPhase.created state.binder_session_url = binder_session_url state.binder_session_token = binder_session_token }) ) - // fetch index to say hello + // fetch index to say hello to the pluto server. this ensures that the pluto server is running and it triggers JIT compiling some of the HTTP code. await fetch(with_token(binder_session_url)) - let open_response + await setStatePromise( + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.backend_launch_phase = BackendLaunchPhase.responded + }) + ) + + /// PART 2: Using Pluto's REST API to open the notebook file. We either upload the notebook with a POST request, or we let the server open by giving it the filename/URL. + + let download_locally_and_upload = async () => { + const upload_url = with_token( + with_query_params(new URL("notebookupload", binder_session_url), { + name: new URLSearchParams(window.location.search).get("name"), + execution_allowed: "true", + }) + ) + console.log(`downloading locally and uploading `, upload_url, launch_params.notebookfile) - if (launch_params.notebookfile.startsWith("data:")) { - open_response = await fetch(with_token(new URL("notebookupload", binder_session_url)), { + return fetch(upload_url, { method: "POST", - body: await (await fetch(launch_params.notebookfile)).arrayBuffer(), + body: await (await fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity }))).arrayBuffer(), }) - } else { - for (const [p1, p2] of [ - ["path", launch_params.notebookfile], - ["url", new URL(launch_params.notebookfile, window.location.href).href], - ]) { - const open_url = new URL("open", binder_session_url) - open_url.searchParams.set(p1, p2) - - console.log(`open ${p1}:`, String(open_url)) - open_response = await fetch(with_token(open_url), { - method: "POST", - }) - if (open_response.ok) { - break - } + } + + let open_remotely = async (p1, p2) => { + const open_url = with_query_params(new URL("open", binder_session_url), { [p1]: p2 }) + + console.log(`open ${p1}:`, open_url) + return fetch(with_token(open_url), { + method: "POST", + }) + } + let open_remotely_fn = (p1, p2) => () => open_remotely(p1, p2) + + let methods_to_try = launch_params.notebookfile.startsWith("data:") + ? [download_locally_and_upload] + : [ + // + open_remotely_fn("path", launch_params.notebookfile), + // + open_remotely_fn("url", new URL(launch_params.notebookfile, window.location.href).href), + // + download_locally_and_upload, + ] + + let open_response = new Response() + for (let method of methods_to_try) { + open_response = await method() + if (open_response.ok) { + break } } + if (!open_response.ok) { + let b = await open_response.blob() + window.location.href = URL.createObjectURL(b) + return + } + + // Opening a notebook gives us the notebook ID, which means that we have a running session! Time to connect. + const new_notebook_id = await open_response.text() + const edit_url = with_token(with_query_params(new URL("edit", binder_session_url), { id: new_notebook_id })) console.info("notebook_id:", new_notebook_id) await setStatePromise( - immer((state) => { + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { state.notebook.notebook_id = new_notebook_id - state.binder_phase = BinderPhase.notebook_running + state.backend_launch_phase = BackendLaunchPhase.notebook_running + state.refresh_target = edit_url }) ) + + /// PART 3: We open the WebSocket connection to the Pluto server, connecting to the notebook ID that was created for us. If this fails, or after a 20 second timeout, we give up on hot-swapping a live backend into this static view, and instead we just redirect to the binder URL. + console.log("Connecting WebSocket") - const connect_promise = connect(with_token(ws_address_from_base(binder_session_url) + "channels")) - await timeout_promise(connect_promise, 10_000).catch((e) => { - console.error("Failed to establish connection within 10 seconds. Navigating to the edit URL directly.", e) - const edit_url = new URL("edit", binder_session_url) - edit_url.searchParams.set("id", new_notebook_id) - window.parent.location.href = with_token(edit_url) + const connect_promise = connect(with_token(new URL("channels", ws_address_from_base(binder_session_url)))) + await timeout_promise(connect_promise, 20_000).catch((e) => { + console.error("Failed to establish connection within 20 seconds. Navigating to the edit URL directly.", e) + window.parent.location.href = edit_url }) } catch (err) { console.error("Failed to initialize binder!", err) diff --git a/frontend/common/Bond.js b/frontend/common/Bond.js index 22df007c66..7cd904fc30 100644 --- a/frontend/common/Bond.js +++ b/frontend/common/Bond.js @@ -1,7 +1,9 @@ // import Generators_input from "https://unpkg.com/@observablehq/stdlib@3.3.1/src/generators/input.js" // import Generators_input from "https://unpkg.com/@observablehq/stdlib@3.3.1/src/generators/input.js" +import { open_pluto_popup } from "../common/open_pluto_popup.js" import _ from "../imports/lodash.js" +import { html } from "../imports/Preact.js" import observablehq from "./SetupCellEnvironment.js" /** @@ -10,7 +12,7 @@ import observablehq from "./SetupCellEnvironment.js" * @param {Element} input * @returns {any} */ -function get_input_value(input) { +export function get_input_value(input) { if (input instanceof HTMLInputElement) { switch (input.type) { case "range": @@ -22,7 +24,7 @@ function get_input_value(input) { case "checkbox": return input.checked case "file": - return input.multiple ? input.files : input.files[0] + return input.multiple ? input.files : input.files?.[0] default: return input.value } @@ -39,7 +41,7 @@ function get_input_value(input) { * @param {Element} input * @returns {string} */ -function eventof(input) { +export function eventof(input) { //@ts-ignore switch (input.type) { case "button": @@ -77,7 +79,10 @@ function input_generator(input) { * @param {Element} input * @param {any} new_value */ -const set_input_value = (input, new_value) => { +export const set_input_value = (input, new_value) => { + if (input instanceof HTMLInputElement && input.type === "file") { + return + } if (new_value == null) { //@ts-ignore input.value = new_value @@ -122,10 +127,14 @@ const set_input_value = (input, new_value) => { } } -export const set_bound_elements_to_their_value = (node, bond_values) => { - for (let bond_node of node.querySelectorAll("bond")) { +/** + * @param {NodeListOf} bond_nodes + * @param {import("../components/Editor.js").BondValuesDict} bond_values + */ +export const set_bound_elements_to_their_value = (bond_nodes, bond_values) => { + bond_nodes.forEach((bond_node) => { let bond_name = bond_node.getAttribute("def") - if (bond_node.firstElementChild != null && bond_values[bond_name] != null) { + if (bond_name != null && bond_node.firstElementChild != null && bond_values[bond_name] != null) { let val = bond_values[bond_name].value try { set_input_value(bond_node.firstElementChild, val) @@ -133,49 +142,86 @@ export const set_bound_elements_to_their_value = (node, bond_values) => { console.error(`Error while setting input value`, bond_node.firstElementChild, `to value`, val, `: `, error) } } - } + }) } /** - * @param {Element} node + * @param {NodeListOf} bond_nodes + * @param {Promise} invalidation + */ +export const add_bonds_disabled_message_handler = (bond_nodes, invalidation) => { + bond_nodes.forEach((bond_node) => { + const listener = (e) => { + if (e.target.closest(".bonds_disabled:where(.offer_binder, .offer_local)")) { + open_pluto_popup({ + type: "info", + source_element: e.target, + body: html`${`You are viewing a static document. `} + { + //@ts-ignore + window.open_edit_or_run_popup() + e.preventDefault() + window.dispatchEvent(new CustomEvent("close pluto popup")) + }} + >Run this notebook + ${` to enable interactivity.`}`, + }) + } + } + bond_node.addEventListener("click", listener) + invalidation.then(() => { + bond_node.removeEventListener("click", listener) + }) + }) +} + +/** + * @param {NodeListOf} bond_nodes * @param {(name: string, value: any) => Promise} on_bond_change - * @param {{[name: string]: any}} known_values Object of variable names that already have a value in the state, which we may not want to send the initial bond value for. When reloading the page, bonds are set to their values from the state, and we don't want to trigger a change event for those. + * @param {import("../components/Editor.js").BondValuesDict} known_values Object of variable names that already have a value in the state, which we may not want to send the initial bond value for. When reloading the page, bonds are set to their values from the state, and we don't want to trigger a change event for those. + * @param {Promise} invalidation */ -export const add_bonds_listener = (node, on_bond_change, known_values) => { +export const add_bonds_listener = (bond_nodes, on_bond_change, known_values, invalidation) => { // the node will be invalidated when the cell re-evaluates. when this happens, we need to stop processing input events let node_is_invalidated = false - node.querySelectorAll("bond").forEach(async (bond_node) => { + invalidation.then(() => { + node_is_invalidated = true + }) + + bond_nodes.forEach(async (bond_node) => { const name = bond_node.getAttribute("def") - const initial_value = get_input_value(bond_node.firstElementChild) + const bound_element_node = bond_node.firstElementChild + if (name != null && bound_element_node != null) { + const initial_value = get_input_value(bound_element_node) - let skip_initialize = Object.keys(known_values).includes(name) && _.isEqual(known_values[name]?.value, initial_value) - // Initialize the bond. This will send the data to the backend for the first time. If it's already there, and the value is the same, cells won't rerun. - const init_promise = skip_initialize ? null : on_bond_change(name, initial_value).catch(console.error) + let skip_initialize = Object.keys(known_values).includes(name) && _.isEqual(known_values[name]?.value, initial_value) + // Initialize the bond. This will send the data to the backend for the first time. If it's already there, and the value is the same, cells won't rerun. + const init_promise = skip_initialize ? null : on_bond_change(name, initial_value).catch(console.error) - // see the docs on Generators.input from observablehq/stdlib - let skippped_first = false - for (let val of input_generator(bond_node.firstElementChild)) { - if (node_is_invalidated) break + // see the docs on Generators.input from observablehq/stdlib + let skippped_first = false + for (let val of input_generator(bound_element_node)) { + if (node_is_invalidated) break - if (skippped_first === false) { - skippped_first = true - continue - } - // wait for a new input value. If a value is ready, then this promise resolves immediately - const to_send = await transformed_val(await val) + if (skippped_first === false) { + skippped_first = true + continue + } + // wait for a new input value. If a value is ready, then this promise resolves immediately + const to_send = await transformed_val(await val) - // send to the Pluto back-end (have a look at set_bond in Editor.js) - // await the setter to avoid collisions - //TODO : get this from state - await init_promise - await on_bond_change(name, to_send).catch(console.error) + // send to the Pluto back-end (have a look at set_bond in Editor.js) + // await the setter to avoid collisions + //TODO : get this from state + await init_promise + await on_bond_change(name, to_send).catch(console.error) + } } }) - - return function dispose_bond_listener() { - node_is_invalidated = true - } } /** diff --git a/frontend/common/Environment.js b/frontend/common/Environment.js new file mode 100644 index 0000000000..81447c40d0 --- /dev/null +++ b/frontend/common/Environment.js @@ -0,0 +1,31 @@ +function environment({ + client, + editor, + imports: { + preact: { html, useEffect, useState, useMemo }, + }, +}) { + const noop = () => false + + return { + custom_editor_header_component: noop, + custom_welcome: noop, + custom_recent: noop, + custom_filepicker: noop, + } +} + +export const get_environment = async (client) => { + let environment // Draal this is for you + // @ts-ignore + if (!window.pluto_injected_environment) { + const { default: env } = await import(client.session_options.server.injected_javascript_data_url) + environment = env + } else { + // @ts-ignore + environment = window.pluto_injected_environment.environment + } + return environment +} + +export default environment diff --git a/frontend/common/InstallTimeEstimate.js b/frontend/common/InstallTimeEstimate.js new file mode 100644 index 0000000000..89aaad2326 --- /dev/null +++ b/frontend/common/InstallTimeEstimate.js @@ -0,0 +1,99 @@ +import { useEffect, useState } from "../imports/Preact.js" +import _ from "../imports/lodash.js" + +const loading_times_url = `https://julia-loading-times-test.netlify.app/pkg_load_times.csv` +const package_list_url = `https://julia-loading-times-test.netlify.app/top_packages_sorted_with_deps.txt` + +/** @typedef {{ install: Number, precompile: Number, load: Number }} LoadingTime */ + +/** + * @typedef PackageTimingData + * @type {{ + * times: Map, + * packages: Map, + * }} + */ + +/** @type {{ current: Promise? }} */ +const data_promise_ref = { current: null } + +export const get_data = () => { + if (data_promise_ref.current != null) { + return data_promise_ref.current + } else { + const times_p = fetch(loading_times_url) + .then((res) => res.text()) + .then((text) => { + const lines = text.split("\n") + const header = lines[0].split(",") + return new Map( + lines.slice(1).map((line) => { + let [pkg, ...times] = line.split(",") + + return [pkg, { install: Number(times[0]), precompile: Number(times[1]), load: Number(times[2]) }] + }) + ) + }) + + const packages_p = fetch(package_list_url) + .then((res) => res.text()) + .then( + (text) => + new Map( + text.split("\n").map((line) => { + let [pkg, ...deps] = line.split(",") + return [pkg, deps] + }) + ) + ) + + data_promise_ref.current = Promise.all([times_p, packages_p]).then(([times, packages]) => ({ times, packages })) + + return data_promise_ref.current + } +} + +export const usePackageTimingData = () => { + const [data, set_data] = useState(/** @type {PackageTimingData?} */ (null)) + + useEffect(() => { + get_data().then(set_data) + }, []) + + return data +} + +const recursive_deps = (/** @type {PackageTimingData} */ data, /** @type {string} */ pkg, found = []) => { + const deps = data.packages.get(pkg) + if (deps == null) { + return [] + } else { + const newfound = _.union(found, deps) + return [...deps, ..._.difference(deps, found).flatMap((dep) => recursive_deps(data, dep, newfound))] + } +} + +export const time_estimate = (/** @type {PackageTimingData} */ data, /** @type {string[]} */ packages) => { + let deps = packages.flatMap((pkg) => recursive_deps(data, pkg)) + let times = _.uniq([...packages, ...deps]) + .map((pkg) => data.times.get(pkg)) + .filter((x) => x != null) + + console.log({ packages, deps, times, z: _.uniq([...packages, ...deps]) }) + let sum = (xs) => xs.reduce((acc, x) => acc + (x == null || isNaN(x) ? 0 : x), 0) + + return { + install: sum(times.map(_.property("install"))) * timing_weights.install, + precompile: sum(times.map(_.property("precompile"))) * timing_weights.precompile, + load: sum(times.map(_.property("load"))) * timing_weights.load, + } +} + +const timing_weights = { + // Because the GitHub Action runner has superfast internet + install: 2, + // Because the GitHub Action runner has average compute speed + load: 1, + // Because precompilation happens in parallel + precompile: 0.3, +} diff --git a/frontend/common/KeyboardShortcuts.js b/frontend/common/KeyboardShortcuts.js index 2590783a6c..ee1aac901e 100644 --- a/frontend/common/KeyboardShortcuts.js +++ b/frontend/common/KeyboardShortcuts.js @@ -1,6 +1,9 @@ export let is_mac_keyboard = /Mac/.test(navigator.platform) -export let ctrl_or_cmd_name = is_mac_keyboard ? "Cmd" : "Ctrl" +export let control_name = is_mac_keyboard ? "⌃" : "Ctrl" +export let ctrl_or_cmd_name = is_mac_keyboard ? "⌘" : "Ctrl" +export let alt_or_options_name = is_mac_keyboard ? "⌥" : "Alt" +export let and = is_mac_keyboard ? " " : "+" export let has_ctrl_or_cmd_pressed = (event) => event.ctrlKey || (is_mac_keyboard && event.metaKey) @@ -21,10 +24,10 @@ export let map_cmd_to_ctrl_on_mac = (keymap) => { } export let in_textarea_or_input = () => { - const in_footer = document.activeElement.closest("footer") != null - const in_header = document.activeElement.closest("header") != null - const in_cm = document.activeElement.closest(".cm-editor") != null + const in_footer = document.activeElement?.closest("footer") != null + const in_header = document.activeElement?.closest("header") != null + const in_cm = document.activeElement?.closest(".cm-editor") != null - const { tagName } = document.activeElement + const { tagName } = document.activeElement ?? {} return tagName === "INPUT" || tagName === "TEXTAREA" || in_footer || in_header || in_cm } diff --git a/frontend/common/MsgPack.js b/frontend/common/MsgPack.js index 7d139e302e..25e9f9ae0a 100644 --- a/frontend/common/MsgPack.js +++ b/frontend/common/MsgPack.js @@ -3,7 +3,7 @@ import msgpack from "../imports/msgpack-lite.js" // based on https://github.com/kawanet/msgpack-lite/blob/5b71d82cad4b96289a466a6403d2faaa3e254167/lib/ext-packer.js const codec = msgpack.createCodec() -const packTypedArray = (x) => new Uint8Array(x.buffer) +const packTypedArray = (x) => new Uint8Array(x.buffer, x.byteOffset, x.byteLength) codec.addExtPacker(0x11, Int8Array, packTypedArray) codec.addExtPacker(0x12, Uint8Array, packTypedArray) codec.addExtPacker(0x13, Int16Array, packTypedArray) diff --git a/frontend/common/NewUpdateMessage.js b/frontend/common/NewUpdateMessage.js new file mode 100644 index 0000000000..665e9c3e7c --- /dev/null +++ b/frontend/common/NewUpdateMessage.js @@ -0,0 +1,42 @@ +export const new_update_message = (client) => + fetch_pluto_releases() + .then((releases) => { + const local = client.version_info.pluto + const latest = releases[releases.length - 1].tag_name + console.log(`Pluto version ${local}`) + const local_index = releases.findIndex((r) => r.tag_name === local) + if (local_index !== -1) { + const updates = releases.slice(local_index + 1) + const recommended_updates = updates.filter((r) => r.body.toLowerCase().includes("recommended update")) + if (recommended_updates.length > 0) { + console.log(`Newer version ${latest} is available`) + if (!client.version_info.dismiss_update_notification) { + alert( + "A new version of Pluto.jl is available! 🎉\n\n You have " + + local + + ", the latest is " + + latest + + '.\n\nYou can update Pluto.jl using the julia package manager:\n import Pkg; Pkg.update("Pluto")\nAfterwards, exit Pluto.jl and restart julia.' + ) + } + } + } + }) + .catch(() => { + // Having this as a uncaught promise broke the frontend tests for me + // so I'm just swallowing the error explicitly - DRAL + }) + +const fetch_pluto_releases = async () => { + let response = await fetch("https://api.github.com/repos/fonsp/Pluto.jl/releases", { + method: "GET", + mode: "cors", + cache: "no-cache", + headers: { + "Content-Type": "application/json", + }, + redirect: "follow", + referrerPolicy: "no-referrer", + }) + return (await response.json()).reverse() +} diff --git a/frontend/common/NotebookLocationFromURL.js b/frontend/common/NotebookLocationFromURL.js new file mode 100644 index 0000000000..1f6d67f674 --- /dev/null +++ b/frontend/common/NotebookLocationFromURL.js @@ -0,0 +1,57 @@ +// should strip characters similar to how github converts filenames into the #file-... URL hash. +// test on: https://gist.github.com/fonsp/f7d230da4f067a11ad18de15bff80470 +const gist_normalizer = (str) => + str + .toLowerCase() + .normalize("NFD") + .replace(/[^a-z1-9]/g, "") + +export const guess_notebook_location = async (path_or_url) => { + try { + const u = new URL(path_or_url) + if (!["http:", "https:", "ftp:", "ftps:"].includes(u.protocol)) { + throw "Not a web URL" + } + if (u.host === "gist.github.com") { + console.log("Gist URL detected") + const parts = u.pathname.substring(1).split("/") + const gist_id = parts[1] + const gist = await ( + await fetch(`https://api.github.com/gists/${gist_id}`, { + headers: { Accept: "application/vnd.github.v3+json" }, + }).then((r) => (r.ok ? r : Promise.reject(r))) + ).json() + console.log(gist) + const files = Object.values(gist.files) + + const selected = files.find((f) => gist_normalizer("#file-" + f.filename) === gist_normalizer(u.hash)) + if (selected != null) { + return { + type: "url", + path_or_url: selected.raw_url, + } + } + + return { + type: "url", + path_or_url: files[0].raw_url, + } + } else if (u.host === "github.com") { + u.searchParams.set("raw", "true") + } + return { + type: "url", + path_or_url: u.href, + } + } catch (ex) { + /* Remove eventual single/double quotes from the path if they surround it, see + https://github.com/fonsp/Pluto.jl/issues/1639 */ + if (path_or_url[path_or_url.length - 1] === '"' && path_or_url[0] === '"') { + path_or_url = path_or_url.slice(1, -1) /* Remove first and last character */ + } + return { + type: "path", + path_or_url: path_or_url, + } + } +} diff --git a/frontend/common/PlutoConnection.js b/frontend/common/PlutoConnection.js index a9aead455e..c84479b629 100644 --- a/frontend/common/PlutoConnection.js +++ b/frontend/common/PlutoConnection.js @@ -1,13 +1,11 @@ import { Promises } from "../common/SetupCellEnvironment.js" import { pack, unpack } from "./MsgPack.js" -import { base64_arraybuffer, decode_base64_to_arraybuffer } from "./PlutoHash.js" +import { with_query_params } from "./URLTools.js" +import { base64_arraybuffer } from "./PlutoHash.js" import "./Polyfill.js" import { available as vscode_available, api as vscode_api } from "./VSCodeApi.js" import { alert, confirm } from "./alert_confirm.js" -// https://github.com/denysdovhan/wtfjs/issues/61 -const different_Infinity_because_js_is_yuck = 2147483646 - const reconnect_after_close_delay = 500 const retry_after_connect_failure_delay = 5000 @@ -80,11 +78,11 @@ const socket_is_alright_with_grace_period = (socket) => } }) -const try_close_socket_connection = (socket) => { +const try_close_socket_connection = (/** @type {WebSocket} */ socket) => { socket.onopen = () => { try_close_socket_connection(socket) } - socket.onmessage = socket.onclose = socket.onerror = undefined + socket.onmessage = socket.onclose = socket.onerror = null try { socket.close(1000, "byebye") } catch (ex) {} @@ -96,7 +94,7 @@ const try_close_socket_connection = (socket) => { * @param {string} address The WebSocket URL * @param {{on_message: Function, on_socket_close:Function}} callbacks * @param {number} timeout_s Timeout for creating the websocket connection (seconds) - * @return {Promise} + * @returns {Promise} */ const create_ws_connection = (address, { on_message, on_socket_close }, timeout_s = 30) => { return new Promise((resolve, reject) => { @@ -194,11 +192,10 @@ const create_vscode_connection = (address, { on_message, on_socket_close }, time try { const raw = event.data // The json-encoded data that the extension sent if (raw.type === "ws_proxy") { - const buffer = await decode_base64_to_arraybuffer(raw.base64_encoded) - const message = unpack(new Uint8Array(buffer)) - + const buffer = await base64_arraybuffer(raw.base64_encoded) + const message = buffer try { - window.DEBUG && console.info("message received!", message) + console.info("message received!", message) on_message(message) } catch (process_err) { console.error("Failed to process message from websocket", process_err, { message }) @@ -208,21 +205,17 @@ const create_vscode_connection = (address, { on_message, on_socket_close }, time } } catch (unpack_err) { console.error("Failed to unpack message from websocket", unpack_err, { event }) - // prettier-ignore alert(`Something went wrong! You might need to refresh the page.\n\nPlease open an issue on https://github.com/fonsp/Pluto.jl with this info:\n\nFailed to unpack message\n${unpack_err}\n\n${JSON.stringify(event)}`) } }) }) - const send_encoded = async (message) => { - window.DEBUG && console.log("Sending message!", message) + console.log("Sending message!", message) const encoded = pack(message) await vscode_api.postMessage({ type: "ws_proxy", base64_encoded: await base64_arraybuffer(encoded) }) } - let last_task = Promise.resolve() - resolve({ socket: {}, send: send_encoded, @@ -242,8 +235,8 @@ let next_tick_promise = () => { * I need to put it here so other code, * like running cells, will also wait for the updates to complete. * I SHALL MAKE IT MORE COMPLEX! (https://www.youtube.com/watch?v=aO3JgPUJ6iQ&t=195s) - * @param {Function} send - * @returns + * @param {import("./PlutoConnectionSendFn").SendFn} send + * @returns {import("./PlutoConnectionSendFn").SendFn} */ const batched_updates = (send) => { let current_combined_updates_promise = null @@ -278,10 +271,14 @@ const batched_updates = (send) => { return batched } -export const ws_address_from_base = (base_url) => { +export const ws_address_from_base = (/** @type {string | URL} */ base_url) => { const ws_url = new URL("./", base_url) ws_url.protocol = ws_url.protocol.replace("http", "ws") - return String(ws_url) + + // if the original URL had a secret in the URL, we can also add it here: + const ws_url_with_secret = with_query_params(ws_url, { secret: new URL(base_url).searchParams.get("secret") }) + + return ws_url_with_secret } const default_ws_address = () => ws_address_from_base(window.location.href) @@ -289,14 +286,15 @@ const default_ws_address = () => ws_address_from_base(window.location.href) /** * @typedef PlutoConnection * @type {{ - * session_options: Object, - * send: () => void, + * session_options: Record, + * send: import("./PlutoConnectionSendFn").SendFn, * kill: () => void, * version_info: { * julia: string, * pluto: string, * dismiss_update_notification: boolean, * }, + * notebook_exists: boolean, * }} */ @@ -313,7 +311,7 @@ const default_ws_address = () => ws_address_from_base(window.location.href) * @param {{ * on_unrequested_update: (message: PlutoMessage, by_me: boolean) => void, * on_reconnect: () => boolean, - * on_connection_status: (connection_status: boolean) => void, + * on_connection_status: (connection_status: boolean, hopeless: boolean) => void, * connect_metadata?: Object, * ws_address?: String, * }} options @@ -326,7 +324,9 @@ export const create_pluto_connection = async ({ connect_metadata = {}, ws_address = default_ws_address(), }) => { - let ws_connection = null // will be defined later i promise + let ws_connection = /** @type {WebsocketConnection?} */ (null) // will be defined later i promise + + /** @type {PlutoConnection} */ const client = { send: null, session_options: null, @@ -335,21 +335,18 @@ export const create_pluto_connection = async ({ pluto: "unknown", dismiss_update_notification: false, }, + notebook_exists: true, kill: null, } // same const client_id = get_unique_short_id() const sent_requests = new Map() - /** - * Send a message to the Pluto backend, and return a promise that resolves when the backend sends a response. Not all messages receive a response. - * @param {string} message_type - * @param {Object} body - * @param {{notebook_id?: string, cell_id?: string}} metadata - * @param {boolean} no_broadcast if false, the message will be emitteed to on_update - * @returns {(undefined|Promise)} - */ + /** @type {import("./PlutoConnectionSendFn").SendFn} */ const send = async (message_type, body = {}, metadata = {}, no_broadcast = true) => { + if (ws_connection == null) { + throw new Error("No connection established yet") + } const request_id = get_unique_short_id() const message = { @@ -394,19 +391,16 @@ export const create_pluto_connection = async ({ console.warn("Error while setting binder url:", error) } } - update_url_with_binder_token() + if (!vscode_available) { + update_url_with_binder_token() + } try { ws_connection = await (vscode_available ? create_vscode_connection : create_ws_connection)(String(ws_address), { on_message: (update) => { - const for_me = update.recipient_id === client_id - const by_me = update.initiator_id === client_id + const by_me = update.initiator_id == client_id const request_id = update.request_id - if (!for_me) { - return - } - if (by_me && request_id) { const request = sent_requests.get(request_id) if (request) { @@ -418,7 +412,7 @@ export const create_pluto_connection = async ({ on_unrequested_update(update, by_me) }, on_socket_close: async () => { - on_connection_status(false) + on_connection_status(false, false) console.log(`Starting new websocket`, new Date().toLocaleTimeString()) await Promises.delay(reconnect_after_close_delay) @@ -427,7 +421,7 @@ export const create_pluto_connection = async ({ console.log(`Starting state sync`, new Date().toLocaleTimeString()) const accept = on_reconnect() console.log(`State sync ${accept ? "" : "not "}successful`, new Date().toLocaleTimeString()) - on_connection_status(accept) + on_connection_status(accept, false) if (!accept) { alert("Connection out of sync 😥\n\nRefresh the page to continue") } @@ -438,20 +432,20 @@ export const create_pluto_connection = async ({ console.log("Hello?") const u = await send("connect", {}, connect_metadata) console.log("Hello!") + client.kill = () => { + if (ws_connection) ws_connection.socket.close() + } client.session_options = u.message.options client.version_info = u.message.version_info + client.notebook_exists = u.message.notebook_exists console.log("Client object: ", client) if (connect_metadata.notebook_id != null && !u.message.notebook_exists) { - // https://github.com/fonsp/Pluto.jl/issues/55 - if (await confirm("A new server was started - this notebook session is no longer running.\n\nWould you like to go back to the main menu?")) { - window.location.href = "./" - } - on_connection_status(false) + on_connection_status(false, true) return {} } - on_connection_status(true) + on_connection_status(true, false) const ping = () => { send("ping", {}, {}) @@ -459,7 +453,7 @@ export const create_pluto_connection = async ({ // Ping faster than timeout? setTimeout(ping, 28 * 1000) }) - .catch() + .catch(() => undefined) } ping() @@ -474,17 +468,3 @@ export const create_pluto_connection = async ({ return client } - -export const fetch_pluto_releases = async () => { - let response = await fetch("https://api.github.com/repos/fonsp/Pluto.jl/releases", { - method: "GET", - mode: "cors", - cache: "no-cache", - headers: { - "Content-Type": "application/json", - }, - redirect: "follow", - referrerPolicy: "no-referrer", - }) - return (await response.json()).reverse() -} diff --git a/frontend/common/PlutoConnectionSendFn.d.ts b/frontend/common/PlutoConnectionSendFn.d.ts new file mode 100644 index 0000000000..458394bd5f --- /dev/null +++ b/frontend/common/PlutoConnectionSendFn.d.ts @@ -0,0 +1,12 @@ +/** Send a message to the Pluto backend, and return a promise that resolves when the backend sends a response. Not all messages receive a response. */ +export function SendFn ( + message_type: string, + body?: Object, + metadata?: {notebook_id?: string, cell_id?: string}, + /** + * If false, then the server response will go through the `on_unrequested_update` callback of this client. (This is useful for requests that will cause a state change, like "Run cell". We want the response (state patch) to be handled by the `on_unrequested_update` logic.) + * + * If true (default), then the response will *only* go to you. This is useful for isolated requests, like "Please autocomplete `draw_rectang`". + * @default true */ + skip_onupdate_callback?: boolean, + ): Promise> diff --git a/frontend/common/PlutoContext.js b/frontend/common/PlutoContext.js index 4580a858fc..79344a17b2 100644 --- a/frontend/common/PlutoContext.js +++ b/frontend/common/PlutoContext.js @@ -1,5 +1,34 @@ import { createContext } from "../imports/Preact.js" -export let PlutoContext = createContext() -export let PlutoBondsContext = createContext(/** @type {{ [key: string]: { value: any } }} */ (null)) -export let PlutoJSInitializingContext = createContext() +export let PlutoActionsContext = createContext() +// export let PlutoActionsContext = createContext(/** @type {Record?} */ (null)) +export let PlutoBondsContext = createContext(/** @type {import("../components/Editor.js").BondValuesDict?} */ (null)) +export let PlutoJSInitializingContext = createContext(/** @type {SetWithEmptyCallback?} */ (null)) + +// Hey copilot, create a class like the built-in `Set` class, but with a callback that is fired when the set becomes empty. +/** + * A class like the built-in `Set` class, but with a callback that is fired when the set becomes empty. + * @template T + * @extends {Set} + */ +export class SetWithEmptyCallback extends Set { + /** + * @param {() => void} callback + */ + constructor(callback) { + super() + this.callback = callback + } + + /** + * @param {T} value + */ + delete(value) { + let result = super.delete(value) + if (result && this.size === 0) { + this.callback() + } + return result + } +} +// THANKS COPILOT ❤️ diff --git a/frontend/common/PlutoHash.js b/frontend/common/PlutoHash.js index 3ce93c30ea..8c71325735 100644 --- a/frontend/common/PlutoHash.js +++ b/frontend/common/PlutoHash.js @@ -1,3 +1,6 @@ +//@ts-ignore +import { sha256 } from "https://cdn.jsdelivr.net/gh/JuliaPluto/js-sha256@v0.9.0-es6/src/sha256.mjs" + export const base64_arraybuffer = async (/** @type {BufferSource} */ data) => { /** @type {string} */ const base64url = await new Promise((r) => { @@ -7,25 +10,58 @@ export const base64_arraybuffer = async (/** @type {BufferSource} */ data) => { reader.readAsDataURL(new Blob([data])) }) - return base64url.split(",", 2)[1] + return base64url.substring(base64url.indexOf(',')+1) +} + +/** Encode a buffer using the `base64url` encoding, which uses URL-safe special characters, see https://en.wikipedia.org/wiki/Base64#Variants_summary_table */ +export const base64url_arraybuffer = async (/** @type {BufferSource} */ data) => { + // This is roughly 0.5 as fast as `base64_arraybuffer`. See https://gist.github.com/fonsp/d2b84265012942dc40d0082b1fd405ba for benchmark and even slower alternatives. + let original = await base64_arraybuffer(data) + return base64_to_base64url(original) } -export const decode_base64_to_arraybuffer = async (/** @type {string} */ data) => { - let r = await fetch(`data:;base64,${data}`) - return await r.arrayBuffer() +/** Turn a base64-encoded string into a base64url-encoded string containing the same data. Do not apply on a `data://` URL. */ +export const base64_to_base64url = (/** @type {string} */ original) => { + return original.replaceAll(/[\+\/\=]/g, (s) => { + const c = s.charCodeAt(0) + return c === 43 ? "-" : c === 47 ? "_" : "" + }) } -export const hash_arraybuffer = async (/** @type {BufferSource} */ data) => { - // @ts-ignore - const hashed_buffer = await window.crypto.subtle.digest("SHA-256", data) - return await base64_arraybuffer(hashed_buffer) +/** Turn a base64url-encoded string into a base64-encoded string containing the same data. Do not apply on a `data://` URL. */ +export const base64url_to_base64 = (/** @type {string} */ original) => { + const result_before_padding = original.replaceAll(/[-_]/g, (s) => { + const c = s.charCodeAt(0) + return c === 45 ? "+" : c === 95 ? "/" : "" + }) + return result_before_padding + "=".repeat((4 - (result_before_padding.length % 4)) % 4) } -export const hash_str = async (/** @type {string} */ s) => { +const t1 = "AAA/AAA+ZMg=" +const t2 = "AAA_AAA-ZMg" + +console.assert(base64_to_base64url(t1) === t2) +console.assert(base64url_to_base64(t2) === t1) + +base64_arraybuffer(new Uint8Array([0, 0, 63, 0, 0, 62, 100, 200])).then((r) => console.assert(r === t1, r)) +base64url_arraybuffer(new Uint8Array([0, 0, 63, 0, 0, 62, 100, 200])).then((r) => console.assert(r === t2, r)) + +export const plutohash_arraybuffer = async (/** @type {BufferSource} */ data) => { + const hash = sha256.create() + hash.update(data) + const hashed_buffer = hash.arrayBuffer() + // const hashed_buffer = await window.crypto.subtle.digest("SHA-256", data) + return await base64url_arraybuffer(hashed_buffer) +} + +export const plutohash_str = async (/** @type {string} */ s) => { const data = new TextEncoder().encode(s) - return await hash_arraybuffer(data) + return await plutohash_arraybuffer(data) } +// hash_str("Hannes").then((r) => console.assert(r === "OI48wVWerxEEnz5lIj6CPPRB8NOwwba+LkFYTDp4aUU=", r)) +plutohash_str("Hannes").then((r) => console.assert(r === "OI48wVWerxEEnz5lIj6CPPRB8NOwwba-LkFYTDp4aUU", r)) + export const debounced_promises = (async_function) => { let currently_running = false let rerun_when_done = false diff --git a/frontend/common/Polyfill.js b/frontend/common/Polyfill.js index 28e226aa45..693a47f076 100644 --- a/frontend/common/Polyfill.js +++ b/frontend/common/Polyfill.js @@ -27,4 +27,7 @@ if (Blob.prototype.arrayBuffer == null) { } } -import "https://cdn.jsdelivr.net/npm/smoothscroll-polyfill@0.4.4/dist/smoothscroll.min.js" +//@ts-ignore +import { polyfill as scroll_polyfill } from "https://esm.sh/seamless-scroll-polyfill@2.1.8/lib/polyfill.js?pin=v113&target=es2020" + +scroll_polyfill() diff --git a/frontend/common/ProcessStatus.js b/frontend/common/ProcessStatus.js new file mode 100644 index 0000000000..00fa9d5e73 --- /dev/null +++ b/frontend/common/ProcessStatus.js @@ -0,0 +1,7 @@ +export const ProcessStatus = { + ready: "ready", + starting: "starting", + no_process: "no_process", + waiting_to_restart: "waiting_to_restart", + waiting_for_permission: "waiting_for_permission", +} diff --git a/frontend/common/RunLocal.js b/frontend/common/RunLocal.js new file mode 100644 index 0000000000..b43e8b90b5 --- /dev/null +++ b/frontend/common/RunLocal.js @@ -0,0 +1,83 @@ +import immer from "../imports/immer.js" +import { BackendLaunchPhase } from "./Binder.js" +import { timeout_promise } from "./PlutoConnection.js" +import { with_query_params } from "./URLTools.js" + +// This file is very similar to `start_binder` in Binder.js + +/** + * + * @param {{ + * launch_params: import("../components/Editor.js").LaunchParameters, + * setStatePromise: any, + * connect: () => Promise, + * }} props + */ +export const start_local = async ({ setStatePromise, connect, launch_params }) => { + try { + if (launch_params.pluto_server_url == null || launch_params.notebookfile == null) throw Error("Invalid launch parameters for starting locally.") + + await setStatePromise( + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.backend_launch_phase = BackendLaunchPhase.responded + state.disable_ui = false + // Clear the Status of the process that generated the HTML + state.notebook.status_tree = null + }) + ) + + const with_token = (x) => String(x) + const binder_session_url = new URL(launch_params.pluto_server_url, window.location.href) + + let open_response + + // We download the notebook file contents, and then upload them to the Pluto server. + const notebook_contents = await ( + await fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity ?? undefined })) + ).arrayBuffer() + + open_response = await fetch( + with_token( + with_query_params(new URL("notebookupload", binder_session_url), { + name: new URLSearchParams(window.location.search).get("name"), + clear_frontmatter: "yesplease", + execution_allowed: "yepperz", + }) + ), + { + method: "POST", + body: notebook_contents, + } + ) + + if (!open_response.ok) { + let b = await open_response.blob() + window.location.href = URL.createObjectURL(b) + return + } + + const new_notebook_id = await open_response.text() + const edit_url = with_query_params(new URL("edit", binder_session_url), { id: new_notebook_id }) + console.info("notebook_id:", new_notebook_id) + + window.history.replaceState({}, "", edit_url) + + await setStatePromise( + immer((/** @type {import("../components/Editor.js").EditorState} */ state) => { + state.notebook.notebook_id = new_notebook_id + state.backend_launch_phase = BackendLaunchPhase.notebook_running + }) + ) + console.log("Connecting WebSocket") + + const connect_promise = connect() + await timeout_promise(connect_promise, 20_000).catch((e) => { + console.error("Failed to establish connection within 20 seconds. Navigating to the edit URL directly.", e) + + window.parent.location.href = with_token(edit_url) + }) + } catch (err) { + console.error("Failed to initialize binder!", err) + alert("Something went wrong! 😮\n\nWe failed to open this notebook. Please try again with a different browser, or come back later.") + } +} diff --git a/frontend/common/Serialization.js b/frontend/common/Serialization.js index 77b989fd34..e1829da54e 100644 --- a/frontend/common/Serialization.js +++ b/frontend/common/Serialization.js @@ -1,5 +1,3 @@ -import { in_textarea_or_input } from "./KeyboardShortcuts.js" - /** * Serialize an array of cells into a string form (similar to the .jl file). * @@ -53,9 +51,9 @@ export function deserialize_repl(repl_session) { .filter((s) => s !== "") } -export const detect_deserializer = (topaste, check_in_textarea_or_input = true) => +export const detect_deserializer = (/** @type {string} */ topaste) => topaste.trim().startsWith(JULIA_REPL_PROMPT) ? deserialize_repl - : (check_in_textarea_or_input && !in_textarea_or_input()) || topaste.match(/# ╔═╡ ........-....-....-....-............/g)?.length + : topaste.match(/# ╔═╡ ........-....-....-....-............/g)?.length ? deserialize_cells : null diff --git a/frontend/common/SetupMathJax.js b/frontend/common/SetupMathJax.js index e56bae6f03..c60709efe0 100644 --- a/frontend/common/SetupMathJax.js +++ b/frontend/common/SetupMathJax.js @@ -1,50 +1,76 @@ -// @ts-nocheck -const deprecated = () => console.warn("Pluto uses MathJax 3, but a MathJax 2 function was called.") +import "https://cdn.jsdelivr.net/npm/requestidlecallback-polyfill@1.0.2/index.js" -window.MathJax = { - options: { - ignoreHtmlClass: "no-MαθJax", - processHtmlClass: "tex", - }, - startup: { - typeset: true, // because we load MathJax asynchronously - ready: () => { - window.MathJax.startup.defaultReady() +let setup_done = false - // plotly uses MathJax 2, so we have this shim to make it work kindof - window.MathJax.Hub = { - Queue: function () { - for (var i = 0, m = arguments.length; i < m; i++) { - var fn = window.MathJax.Callback(arguments[i]) - window.MathJax.startup.promise = window.MathJax.startup.promise.then(fn) - } - return window.MathJax.startup.promise - }, - Typeset: function (elements, callback) { - var promise = window.MathJax.typesetPromise(elements) - if (callback) { - promise = promise.then(callback) - } - return promise - }, - Register: { - MessageHook: deprecated, - StartupHook: deprecated, - LoadHook: deprecated, - }, - Config: deprecated, - Configured: deprecated, - setRenderer: deprecated, - } +export const setup_mathjax = () => { + if (setup_done) { + return + } + setup_done = true + + const deprecated = () => console.warn("Pluto uses MathJax 3, but a MathJax 2 function was called.") + + // @ts-ignore + window.MathJax = { + options: { + ignoreHtmlClass: "no-MαθJax", + processHtmlClass: "tex", + }, + startup: { + typeset: true, // because we load MathJax asynchronously + ready: () => { + // @ts-ignore + window.MathJax.startup.defaultReady() + + // plotly uses MathJax 2, so we have this shim to make it work kindof + // @ts-ignore + window.MathJax.Hub = { + Queue: function () { + for (var i = 0, m = arguments.length; i < m; i++) { + // @ts-ignore + var fn = window.MathJax.Callback(arguments[i]) + // @ts-ignore + window.MathJax.startup.promise = window.MathJax.startup.promise.then(fn) + } + // @ts-ignore + return window.MathJax.startup.promise + }, + Typeset: function (elements, callback) { + // @ts-ignore + var promise = window.MathJax.typesetPromise(elements) + if (callback) { + promise = promise.then(callback) + } + return promise + }, + Register: { + MessageHook: deprecated, + StartupHook: deprecated, + LoadHook: deprecated, + }, + Config: deprecated, + Configured: deprecated, + setRenderer: deprecated, + } + }, + }, + tex: { + inlineMath: [ + ["$", "$"], + ["\\(", "\\)"], + ], + }, + svg: { + fontCache: "global", + }, + } + + requestIdleCallback( + () => { + console.log("Loading mathjax!!") + const script = document.head.querySelector("#MathJax-script") + script.setAttribute("src", script.getAttribute("not-the-src-yet")) }, - }, - tex: { - inlineMath: [ - ["$", "$"], - ["\\(", "\\)"], - ], - }, - svg: { - fontCache: "global", - }, + { timeout: 2000 } + ) } diff --git a/frontend/common/SliderServerClient.js b/frontend/common/SliderServerClient.js index cf0c86fb93..f93f46efd3 100644 --- a/frontend/common/SliderServerClient.js +++ b/frontend/common/SliderServerClient.js @@ -1,11 +1,30 @@ import { trailingslash } from "./Binder.js" -import { hash_arraybuffer, debounced_promises, base64_arraybuffer } from "./PlutoHash.js" +import { plutohash_arraybuffer, debounced_promises, base64url_arraybuffer } from "./PlutoHash.js" import { pack, unpack } from "./MsgPack.js" import immer from "../imports/immer.js" import _ from "../imports/lodash.js" +const assert_response_ok = (/** @type {Response} */ r) => (r.ok ? r : Promise.reject(r)) + const actions_to_keep = ["get_published_object"] +const get_start = (graph, v) => Object.values(graph).find((node) => Object.keys(node.downstream_cells_map).includes(v))?.cell_id +const get_starts = (graph, vars) => new Set([...vars].map((v) => get_start(graph, v))) +const recursive_dependencies = (graph, starts) => { + const deps = new Set(starts) + const ends = [...starts] + while (ends.length > 0) { + const node = ends.splice(0, 1)[0] + _.flatten(Object.values(graph[node].downstream_cells_map)).forEach((child) => { + if (!deps.has(child)) { + ends.push(child) + deps.add(child) + } + }) + } + return deps +} + export const nothing_actions = ({ actions }) => Object.fromEntries( Object.entries(actions).map(([k, v]) => [ @@ -14,23 +33,41 @@ export const nothing_actions = ({ actions }) => ? // the original action v : // a no-op action - () => {}, + (...args) => { + console.info("Ignoring action", k, { args }) + }, ]) ) export const slider_server_actions = ({ setStatePromise, launch_params, actions, get_original_state, get_current_state, apply_notebook_patches }) => { - const notebookfile_hash = fetch(launch_params.notebookfile) + setStatePromise( + immer((state) => { + state.slider_server.connecting = true + }) + ) + + const notebookfile_hash = fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity })) + .then(assert_response_ok) .then((r) => r.arrayBuffer()) - .then(hash_arraybuffer) + .then(plutohash_arraybuffer) notebookfile_hash.then((x) => console.log("Notebook file hash:", x)) const bond_connections = notebookfile_hash - .then((hash) => fetch(trailingslash(launch_params.slider_server_url) + "bondconnections/" + encodeURIComponent(hash))) + .then((hash) => fetch(trailingslash(launch_params.slider_server_url) + "bondconnections/" + hash)) + .then(assert_response_ok) .then((r) => r.arrayBuffer()) .then((b) => unpack(new Uint8Array(b))) - bond_connections.then((x) => console.log("Bond connections:", x)) + bond_connections.then((x) => { + console.log("Bond connections:", x) + setStatePromise( + immer((state) => { + state.slider_server.connecting = false + state.slider_server.interactive = Object.keys(x).length > 0 + }) + ) + }) const mybonds = {} const bonds_to_set = { @@ -41,6 +78,20 @@ export const slider_server_actions = ({ setStatePromise, launch_params, actions, const hash = await notebookfile_hash const graph = await bond_connections + // compute dependencies and update cell running statuses + const dep_graph = get_current_state().cell_dependencies + const starts = get_starts(dep_graph, bonds_to_set.current) + const running_cells = [...recursive_dependencies(dep_graph, starts)] + + const update_cells_running = async (running) => + await setStatePromise( + immer((state) => { + running_cells.forEach((cell_id) => (state.notebook.cell_results[cell_id][starts.has(cell_id) ? "running" : "queued"] = running)) + }) + ) + + await update_cells_running(true) + if (bonds_to_set.current.size > 0) { const to_send = new Set(bonds_to_set.current) bonds_to_set.current.forEach((varname) => (graph[varname] ?? []).forEach((x) => to_send.add(x))) @@ -56,20 +107,21 @@ export const slider_server_actions = ({ setStatePromise, launch_params, actions, const packed = pack(mybonds_filtered) - const url = base + "staterequest/" + encodeURIComponent(hash) + "/" + const url = base + "staterequest/" + hash + "/" let unpacked = null try { - const use_get = url.length + (packed.length * 4) / 3 + 20 < 8000 + const force_post = get_current_state().metadata["sliderserver_force_post"] ?? false + const use_get = !force_post && url.length + (packed.length * 4) / 3 + 20 < 8000 const response = use_get - ? await fetch(url + encodeURIComponent(await base64_arraybuffer(packed)), { + ? await fetch(url + (await base64url_arraybuffer(packed)), { method: "GET", - }) + }).then(assert_response_ok) : await fetch(url, { method: "POST", body: packed, - }) + }).then(assert_response_ok) unpacked = unpack(new Uint8Array(await response.arrayBuffer())) const { patches, ids_of_cells_that_ran } = unpacked @@ -85,6 +137,9 @@ export const slider_server_actions = ({ setStatePromise, launch_params, actions, ) } catch (e) { console.error(unpacked, e) + } finally { + // reset cell running state regardless of request outcome + await update_cells_running(false) } } }) diff --git a/frontend/common/URLTools.js b/frontend/common/URLTools.js new file mode 100644 index 0000000000..7e10b58185 --- /dev/null +++ b/frontend/common/URLTools.js @@ -0,0 +1,15 @@ +export const with_query_params = (/** @type {String | URL} */ url_str, /** @type {Record} */ params) => { + const fake_base = "http://delete-me.com/" + const url = new URL(url_str, fake_base) + Object.entries(params).forEach(([key, val]) => { + if (val != null) url.searchParams.append(key, val) + }) + return url.toString().replace(fake_base, "") +} + +console.assert(with_query_params("https://example.com/", { a: "b c" }) === "https://example.com/?a=b+c") +console.assert(with_query_params(new URL("https://example.com/"), { a: "b c" }) === "https://example.com/?a=b+c") +console.assert(with_query_params(new URL("https://example.com/"), { a: "b c", asdf: null, xx: "123" }) === "https://example.com/?a=b+c&xx=123") +console.assert(with_query_params("index.html", { a: "b c" }) === "index.html?a=b+c") +console.assert(with_query_params("index.html?x=123", { a: "b c" }) === "index.html?x=123&a=b+c") +console.assert(with_query_params("index.html?x=123#asdf", { a: "b c" }) === "index.html?x=123&a=b+c#asdf") diff --git a/frontend/common/clock sync.js b/frontend/common/clock sync.js new file mode 100644 index 0000000000..0d30823fde --- /dev/null +++ b/frontend/common/clock sync.js @@ -0,0 +1,46 @@ +import { useContext, useState, useEffect } from "../imports/Preact.js" +import { PlutoActionsContext } from "./PlutoContext.js" + +/** Request the current time from the server, compare with the local time, and return the current best estimate of our time difference. Updates regularly. + * @param {{connected: boolean}} props + */ +export const useMyClockIsAheadBy = ({ connected }) => { + let pluto_actions = useContext(PlutoActionsContext) + + const [my_clock_is_ahead_by, set_my_clock_is_ahead_by] = useState(0) + + useEffect(() => { + if (connected) { + let f = async () => { + let getserver = () => pluto_actions.send("current_time").then((m) => m.message.time) + let getlocal = () => Date.now() / 1000 + + // once to precompile and to make sure that the server is not busy with other tasks + // console.log("getting server time warmup") + for (let i = 0; i < 16; i++) await getserver() + // console.log("getting server time warmup done") + + let t1 = await getlocal() + let s1 = await getserver() + let s2 = await getserver() + let t2 = await getlocal() + // console.log("getting server time done") + + let mytime = (t1 + t2) / 2 + let servertime = (s1 + s2) / 2 + + let diff = mytime - servertime + // console.info("My clock is ahead by ", diff, " s") + if (!isNaN(diff)) set_my_clock_is_ahead_by(diff) + } + + f() + + let handle = setInterval(f, 60 * 1000) + + return () => clearInterval(handle) + } + }, [connected]) + + return my_clock_is_ahead_by +} diff --git a/frontend/common/open_pluto_popup.js b/frontend/common/open_pluto_popup.js new file mode 100644 index 0000000000..2f69b7c084 --- /dev/null +++ b/frontend/common/open_pluto_popup.js @@ -0,0 +1,7 @@ +export const open_pluto_popup = (/** @type{import("../components/Popup").PkgPopupDetails | import("../components/Popup").MiscPopupDetails} */ detail) => { + window.dispatchEvent( + new CustomEvent("open pluto popup", { + detail, + }) + ) +} diff --git a/frontend/common/useDialog.js b/frontend/common/useDialog.js new file mode 100644 index 0000000000..e1a45f33de --- /dev/null +++ b/frontend/common/useDialog.js @@ -0,0 +1,23 @@ +//@ts-ignore +import dialogPolyfill from "https://cdn.jsdelivr.net/npm/dialog-polyfill@0.5.6/dist/dialog-polyfill.esm.min.js" + +import { useLayoutEffect, useMemo, useRef } from "../imports/Preact.js" + +/** + * @returns {[import("../imports/Preact.js").Ref, () => void, () => void, () => void]} + */ +export const useDialog = ({ light_dismiss = false } = {}) => { + const dialog_ref = useRef(/** @type {HTMLDialogElement?} */ (null)) + + useLayoutEffect(() => { + if (dialog_ref.current != null) dialogPolyfill.registerDialog(dialog_ref.current) + }, [dialog_ref.current]) + + return useMemo(() => { + const open = () => dialog_ref.current?.showModal() + const close = () => dialog_ref.current?.close() + const toggle = () => (dialog_ref.current?.open === true ? dialog_ref.current?.close() : dialog_ref.current?.showModal()) + + return [dialog_ref, open, close, toggle] + }, [dialog_ref]) +} diff --git a/frontend/common/useEventListener.js b/frontend/common/useEventListener.js new file mode 100644 index 0000000000..94b8911846 --- /dev/null +++ b/frontend/common/useEventListener.js @@ -0,0 +1,15 @@ +import { useCallback, useEffect } from "../imports/Preact.js" + +export const useEventListener = ( + /** @type {Document | HTMLElement | Window | null} */ element, + /** @type {string} */ event_name, + /** @type {EventListenerOrEventListenerObject} */ handler, + /** @type {any[] | undefined} */ deps +) => { + let handler_cached = useCallback(handler, deps) + useEffect(() => { + if (element == null) return + element.addEventListener(event_name, handler_cached) + return () => element.removeEventListener(event_name, handler_cached) + }, [element, event_name, handler_cached]) +} diff --git a/frontend/components/BottomRightPanel.js b/frontend/components/BottomRightPanel.js new file mode 100644 index 0000000000..fa7e7f320d --- /dev/null +++ b/frontend/components/BottomRightPanel.js @@ -0,0 +1,201 @@ +import { html, useState, useRef, useEffect, useMemo } from "../imports/Preact.js" +import { cl } from "../common/ClassTable.js" + +import { LiveDocsTab } from "./LiveDocsTab.js" +import { is_finished, ProcessTab, total_done, total_tasks, useStatusItem } from "./ProcessTab.js" +import { useMyClockIsAheadBy } from "../common/clock sync.js" +import { BackendLaunchPhase } from "../common/Binder.js" +import { useEventListener } from "../common/useEventListener.js" + +/** + * @typedef PanelTabName + * @type {"docs" | "process" | null} + */ + +export const open_bottom_right_panel = (/** @type {PanelTabName} */ tab) => window.dispatchEvent(new CustomEvent("open_bottom_right_panel", { detail: tab })) + +/** + * @param {{ + * notebook: import("./Editor.js").NotebookData, + * desired_doc_query: string?, + * on_update_doc_query: (query: string?) => void, + * connected: boolean, + * backend_launch_phase: number?, + * backend_launch_logs: string?, + * }} props + */ +export let BottomRightPanel = ({ desired_doc_query, on_update_doc_query, notebook, connected, backend_launch_phase, backend_launch_logs }) => { + let container_ref = useRef() + + const focus_docs_on_open_ref = useRef(false) + const [open_tab, set_open_tab] = useState(/** @type { PanelTabName} */ (null)) + const hidden = open_tab == null + + // Open panel when "open_bottom_right_panel" event is triggered + useEventListener( + window, + "open_bottom_right_panel", + (/** @type {CustomEvent} */ e) => { + console.log(e.detail) + // https://github.com/fonsp/Pluto.jl/issues/321 + focus_docs_on_open_ref.current = false + set_open_tab(e.detail) + if (window.getComputedStyle(container_ref.current).display === "none") { + alert("This browser window is too small to show docs.\n\nMake the window bigger, or try zooming out.") + } + }, + [set_open_tab] + ) + + const status = useWithBackendStatus(notebook, backend_launch_phase) + + const [status_total, status_done] = useMemo( + () => + status == null + ? [0, 0] + : [ + // total_tasks minus 1, to exclude the notebook task itself + total_tasks(status) - 1, + // the notebook task should never be done, but lets be sure and subtract 1 if it is: + total_done(status) - (is_finished(status) ? 1 : 0), + ], + [status] + ) + + const busy = status_done < status_total + + const show_business_outline = useDelayedTruth(busy, 700) + const show_business_counter = useDelayedTruth(busy, 3000) + + const my_clock_is_ahead_by = useMyClockIsAheadBy({ connected }) + + return html` + + ` +} + +export const useDelayedTruth = (/** @type {boolean} */ x, /** @type {number} */ timeout) => { + const [output, set_output] = useState(false) + + useEffect(() => { + if (x) { + let handle = setTimeout(() => { + set_output(true) + }, timeout) + return () => clearTimeout(handle) + } else { + set_output(false) + } + }, [x]) + + return output +} + +/** + * + * @param {import("./Editor.js").NotebookData} notebook + * @param {number?} backend_launch_phase + * @returns {import("./Editor.js").StatusEntryData?} + */ +const useWithBackendStatus = (notebook, backend_launch_phase) => { + const backend_launch = useBackendStatus(backend_launch_phase) + + return backend_launch_phase == null + ? notebook.status_tree + : { + name: "notebook", + started_at: 0, + finished_at: null, + subtasks: { + ...notebook.status_tree?.subtasks, + backend_launch, + }, + } +} + +const useBackendStatus = (/** @type {number | null} */ backend_launch_phase) => { + let x = backend_launch_phase ?? -1 + + const subtasks = Object.fromEntries( + ["requesting", "created", "responded", "notebook_running"].map((key) => { + let val = BackendLaunchPhase[key] + let name = `backend_${key}` + return [name, useStatusItem(name, x >= val, x > val)] + }) + ) + + return useStatusItem( + "backend_launch", + backend_launch_phase != null && backend_launch_phase > BackendLaunchPhase.wait_for_user, + backend_launch_phase === BackendLaunchPhase.ready, + subtasks + ) +} diff --git a/frontend/components/Cell.js b/frontend/components/Cell.js index 7305cb0dc5..81afa26d80 100644 --- a/frontend/components/Cell.js +++ b/frontend/components/Cell.js @@ -1,10 +1,15 @@ -import { html, useState, useEffect, useMemo, useRef, useContext, useLayoutEffect } from "../imports/Preact.js" +import _ from "../imports/lodash.js" +import { html, useState, useEffect, useMemo, useRef, useContext, useLayoutEffect, useErrorBoundary, useCallback } from "../imports/Preact.js" import { CellOutput } from "./CellOutput.js" import { CellInput } from "./CellInput.js" +import { Logs } from "./Logs.js" import { RunArea, useDebouncedTruth } from "./RunArea.js" import { cl } from "../common/ClassTable.js" -import { PlutoContext } from "../common/PlutoContext.js" +import { PlutoActionsContext } from "../common/PlutoContext.js" +import { open_pluto_popup } from "../common/open_pluto_popup.js" +import { SafePreviewOutput } from "./SafePreviewUI.js" +import { useEventListener } from "../common/useEventListener.js" const useCellApi = (node_ref, published_object_keys, pluto_actions) => { const [cell_api_ready, set_cell_api_ready] = useState(false) @@ -26,46 +31,149 @@ const useCellApi = (node_ref, published_object_keys, pluto_actions) => { return cell_api_ready } +/** + * @param {String} a_cell_id + * @param {import("./Editor.js").NotebookData} notebook + * @returns {Array} + */ +const upstream_of = (a_cell_id, notebook) => Object.values(notebook?.cell_dependencies?.[a_cell_id]?.upstream_cells_map || {}).flatMap((x) => x) + +/** + * @param {String} a_cell_id + * @param {import("./Editor.js").NotebookData} notebook + * @param {Function} predicate + * @param {Set} explored + * @returns {String | null} + */ +const find_upstream_of = (a_cell_id, notebook, predicate, explored = new Set([])) => { + if (explored.has(a_cell_id)) return null + explored.add(a_cell_id) + + if (predicate(a_cell_id)) { + return a_cell_id + } + + for (let upstream of upstream_of(a_cell_id, notebook)) { + const upstream_val = find_upstream_of(upstream, notebook, predicate, explored) + if (upstream_val !== null) { + return upstream_val + } + } + + return null +} + +/** + * @param {String} flag_name + * @returns {Function} + */ +const hasTargetBarrier = (flag_name) => { + return (a_cell_id, notebook) => { + return notebook?.cell_inputs?.[a_cell_id].metadata[flag_name] + } +} + +const on_jump = (hasBarrier, pluto_actions, cell_id) => () => { + const notebook = pluto_actions.get_notebook() || {} + const barrier_cell_id = find_upstream_of(cell_id, notebook, (c) => hasBarrier(c, notebook)) + if (barrier_cell_id !== null) { + window.dispatchEvent( + new CustomEvent("cell_focus", { + detail: { + cell_id: barrier_cell_id, + line: 0, // 1-based to 0-based index + }, + }) + ) + } +} + /** * @param {{ * cell_result: import("./Editor.js").CellResultData, * cell_input: import("./Editor.js").CellInputData, - * cell_input_local: import("./Editor.js").CellInputData, + * cell_input_local: { code: String }, * cell_dependencies: import("./Editor.js").CellDependencyData + * nbpkg: import("./Editor.js").NotebookPkgData?, * selected: boolean, - * selected_cells: Array, * force_hide_input: boolean, * focus_after_creation: boolean, + * process_waiting_for_permission: boolean, + * sanitize_html: boolean, * [key: string]: any, * }} props * */ export const Cell = ({ - cell_input: { cell_id, code, code_folded, running_disabled }, - cell_result: { queued, running, runtime, errored, output, published_object_keys, depends_on_disabled_cells }, + cell_input: { cell_id, code, code_folded, metadata }, + cell_result: { queued, running, runtime, errored, output, logs, published_object_keys, depends_on_disabled_cells, depends_on_skipped_cells }, cell_dependencies, cell_input_local, notebook_id, - on_update_doc_query, - on_change, - on_focus_neighbor, selected, - selected_cells, force_hide_input, focus_after_creation, is_process_ready, disable_input, + process_waiting_for_permission, + sanitize_html = true, nbpkg, + global_definition_locations, + is_first_cell, }) => { - let pluto_actions = useContext(PlutoContext) - const notebook = pluto_actions.get_notebook() - let variables_in_all_notebook = Object.fromEntries( - Object.values(notebook?.cell_dependencies ?? {}).flatMap((x) => Object.keys(x.downstream_cells_map).map((variable) => [variable, x.cell_id])) - ) - const variables = Object.keys(notebook?.cell_dependencies?.[cell_id]?.downstream_cells_map || {}) + const { show_logs, disabled: running_disabled, skip_as_script } = metadata + let pluto_actions = useContext(PlutoActionsContext) + // useCallback because pluto_actions.set_doc_query can change value when you go from viewing a static document to connecting (to binder) + const on_update_doc_query = useCallback((...args) => pluto_actions.set_doc_query(...args), [pluto_actions]) + const on_focus_neighbor = useCallback((...args) => pluto_actions.focus_on_neighbor(...args), [pluto_actions]) + const on_change = useCallback((val) => pluto_actions.set_local_cell(cell_id, val), [cell_id, pluto_actions]) + const variables = useMemo(() => Object.keys(cell_dependencies?.downstream_cells_map ?? {}), [cell_dependencies]) + + // We need to unmount & remount when a destructive error occurs. + // For that reason, we will use a simple react key and increment it on error + const [key, setKey] = useState(0) + const cell_key = useMemo(() => cell_id + key, [cell_id, key]) + + const [, resetError] = useErrorBoundary((error) => { + console.log(`An error occured in the CodeMirror code, resetting CellInput component. See error below:\n\n${error}\n\n -------------- `) + setKey(key + 1) + resetError() + }) + + const remount = useMemo(() => () => setKey(key + 1)) // cm_forced_focus is null, except when a line needs to be highlighted because it is part of a stack trace - const [cm_forced_focus, set_cm_forced_focus] = useState(null) - useEffect(() => { - const focusListener = (e) => { + const [cm_forced_focus, set_cm_forced_focus] = useState(/** @type {any} */ (null)) + const [cm_highlighted_range, set_cm_highlighted_range] = useState(/** @type {{from, to}?} */ (null)) + const [cm_highlighted_line, set_cm_highlighted_line] = useState(null) + const [cm_diagnostics, set_cm_diagnostics] = useState([]) + + useEventListener( + window, + "cell_diagnostics", + (e) => { + if (e.detail.cell_id === cell_id) { + set_cm_diagnostics(e.detail.diagnostics) + } + }, + [cell_id, set_cm_diagnostics] + ) + + useEventListener( + window, + "cell_highlight_range", + (e) => { + if (e.detail.cell_id == cell_id && e.detail.from != null && e.detail.to != null) { + set_cm_highlighted_range({ from: e.detail.from, to: e.detail.to }) + } else { + set_cm_highlighted_range(null) + } + }, + [cell_id] + ) + + useEventListener( + window, + "cell_focus", + useCallback((e) => { if (e.detail.cell_id === cell_id) { if (e.detail.line != null) { const ch = e.detail.ch @@ -84,13 +192,8 @@ export const Cell = ({ } } } - } - window.addEventListener("cell_focus", focusListener) - // cleanup - return () => { - window.removeEventListener("cell_focus", focusListener) - } - }, []) + }, []) + ) // When you click to run a cell, we use `waiting_to_run` to immediately set the cell's traffic light to 'queued', while waiting for the backend to catch up. const [waiting_to_run, set_waiting_to_run] = useState(false) @@ -103,143 +206,239 @@ export const Cell = ({ const class_code_differs = code !== (cell_input_local?.code ?? code) const class_code_folded = code_folded && cm_forced_focus == null + const no_output_yet = (output?.last_run_timestamp ?? 0) === 0 + const code_not_trusted_yet = process_waiting_for_permission && no_output_yet // during the initial page load, force_hide_input === true, so that cell outputs render fast, and codemirrors are loaded after - let show_input = !force_hide_input && (errored || class_code_differs || !class_code_folded) + let show_input = !force_hide_input && (code_not_trusted_yet || errored || class_code_differs || !class_code_folded) + const [line_heights, set_line_heights] = useState([15]) const node_ref = useRef(null) const disable_input_ref = useRef(disable_input) disable_input_ref.current = disable_input const should_set_waiting_to_run_ref = useRef(true) should_set_waiting_to_run_ref.current = !running_disabled && !depends_on_disabled_cells - const set_waiting_to_run_smart = (x) => set_waiting_to_run(x && should_set_waiting_to_run_ref.current) + useEventListener( + window, + "set_waiting_to_run_smart", + (e) => { + if (e.detail.cell_ids.includes(cell_id)) set_waiting_to_run(should_set_waiting_to_run_ref.current) + }, + [cell_id, set_waiting_to_run] + ) const cell_api_ready = useCellApi(node_ref, published_object_keys, pluto_actions) + const on_delete = useCallback(() => { + pluto_actions.confirm_delete_multiple("Delete", pluto_actions.get_selected_cells(cell_id, selected)) + }, [pluto_actions, selected, cell_id]) + const on_submit = useCallback(() => { + if (!disable_input_ref.current) { + pluto_actions.set_and_run_multiple([cell_id]) + } + }, [pluto_actions, cell_id]) + const on_change_cell_input = useCallback( + (new_code) => { + if (!disable_input_ref.current) { + if (code_folded && cm_forced_focus != null) { + pluto_actions.fold_remote_cells([cell_id], false) + } + on_change(new_code) + } + }, + [code_folded, cm_forced_focus, pluto_actions, on_change] + ) + const on_add_after = useCallback(() => { + pluto_actions.add_remote_cell(cell_id, "after") + }, [pluto_actions, cell_id, selected]) + const on_code_fold = useCallback(() => { + pluto_actions.fold_remote_cells(pluto_actions.get_selected_cells(cell_id, selected), !code_folded) + }, [pluto_actions, cell_id, selected, code_folded]) + const on_run = useCallback(() => { + pluto_actions.set_and_run_multiple(pluto_actions.get_selected_cells(cell_id, selected)) + }, [pluto_actions, cell_id, selected]) + const set_show_logs = useCallback( + (show_logs) => + pluto_actions.update_notebook((notebook) => { + notebook.cell_inputs[cell_id].metadata.show_logs = show_logs + }), + [pluto_actions, cell_id] + ) + const set_cell_disabled = useCallback( + async (new_val) => { + await pluto_actions.update_notebook((notebook) => { + notebook.cell_inputs[cell_id].metadata["disabled"] = new_val + }) + // we also 'run' the cell if it is disabled, this will make the backend propage the disabled state to dependent cells + await on_submit() + }, + [pluto_actions, cell_id, on_submit] + ) + + const any_logs = useMemo(() => !_.isEmpty(logs), [logs]) + + const skip_as_script_jump = useCallback(on_jump(hasTargetBarrier("skip_as_script"), pluto_actions, cell_id), [pluto_actions, cell_id]) + const disabled_jump = useCallback(on_jump(hasTargetBarrier("disabled"), pluto_actions, cell_id), [pluto_actions, cell_id]) return html` 0, hooked_up: output?.has_pluto_hook_features ?? false, + no_output_yet, })} id=${cell_id} > ${variables.map((name) => html``)} - - - - - ${cell_api_ready ? html`<${CellOutput} errored=${errored} ...${output} cell_id=${cell_id} />` : html``} + + + + + ${code_not_trusted_yet + ? html`<${SafePreviewOutput} />` + : cell_api_ready + ? html`<${CellOutput} errored=${errored} ...${output} sanitize_html=${sanitize_html} cell_id=${cell_id} />` + : html``} <${CellInput} local_code=${cell_input_local?.code ?? code} remote_code=${code} cell_dependencies=${cell_dependencies} - variables_in_all_notebook=${variables_in_all_notebook} + global_definition_locations=${global_definition_locations} disable_input=${disable_input} focus_after_creation=${focus_after_creation} cm_forced_focus=${cm_forced_focus} set_cm_forced_focus=${set_cm_forced_focus} show_input=${show_input} - on_submit=${() => { - if (!disable_input_ref.current) { - set_waiting_to_run_smart(true) - pluto_actions.set_and_run_multiple([cell_id]) - } - }} - on_delete=${() => { - let cells_to_delete = selected ? selected_cells : [cell_id] - pluto_actions.confirm_delete_multiple("Delete", cells_to_delete) - }} - on_add_after=${() => { - pluto_actions.add_remote_cell(cell_id, "after") - }} - on_fold=${(new_folded) => pluto_actions.fold_remote_cell(cell_id, new_folded)} - on_change=${(new_code) => { - if (!disable_input_ref.current) { - if (code_folded && cm_forced_focus != null) { - pluto_actions.fold_remote_cell(cell_id, false) - } - on_change(new_code) - } - }} + on_submit=${on_submit} + on_delete=${on_delete} + on_add_after=${on_add_after} + on_change=${on_change_cell_input} on_update_doc_query=${on_update_doc_query} on_focus_neighbor=${on_focus_neighbor} + on_line_heights=${set_line_heights} nbpkg=${nbpkg} cell_id=${cell_id} notebook_id=${notebook_id} - running_disabled=${running_disabled} + metadata=${metadata} + any_logs=${any_logs} + show_logs=${show_logs} + set_show_logs=${set_show_logs} + set_cell_disabled=${set_cell_disabled} + cm_highlighted_line=${cm_highlighted_line} + cm_highlighted_range=${cm_highlighted_range} + cm_diagnostics=${cm_diagnostics} + onerror=${remount} /> + ${show_logs && cell_api_ready + ? html`<${Logs} + logs=${Object.values(logs)} + line_heights=${line_heights} + set_cm_highlighted_line=${set_cm_highlighted_line} + sanitize_html=${sanitize_html} + />` + : null} <${RunArea} cell_id=${cell_id} running_disabled=${running_disabled} depends_on_disabled_cells=${depends_on_disabled_cells} - on_run=${() => { - set_waiting_to_run_smart(true) - let cell_to_run = selected ? selected_cells : [cell_id] - pluto_actions.set_and_run_multiple(cell_to_run) - }} + on_run=${on_run} on_interrupt=${() => { pluto_actions.interrupt_remote(cell_id) }} + set_cell_disabled=${set_cell_disabled} runtime=${runtime} running=${running} code_differs=${class_code_differs} queued=${queued} + on_jump=${disabled_jump} /> + ${skip_as_script + ? html`
{ + open_pluto_popup({ + type: "info", + source_element: e.target, + body: html`This cell is currently stored in the notebook file as a Julia comment, instead of code.
+ This way, it will not run when the notebook runs as a script outside of Pluto.
+ Use the context menu to enable it again`, + }) + }} + >
` + : depends_on_skipped_cells + ? html`
{ + open_pluto_popup({ + type: "info", + source_element: e.target, + body: html`This cell is currently stored in the notebook file as a Julia comment, instead of code.
+ This way, it will not run when the notebook runs as a script outside of Pluto.
+ An upstream cell is indirectly disabling in file this one; enable + the upstream one to affect + this cell.`, + }) + }} + >
` + : null}
` } - -export const IsolatedCell = ({ cell_id, cell_results: { output, published_object_keys }, hidden }) => { +/** + * @param {{ + * cell_result: import("./Editor.js").CellResultData, + * cell_input: import("./Editor.js").CellInputData, + * [key: string]: any, + * }} props + * */ +export const IsolatedCell = ({ cell_input: { cell_id, metadata }, cell_result: { logs, output, published_object_keys }, hidden }, sanitize_html = true) => { const node_ref = useRef(null) - let pluto_actions = useContext(PlutoContext) + let pluto_actions = useContext(PlutoActionsContext) const cell_api_ready = useCellApi(node_ref, published_object_keys, pluto_actions) + const { show_logs } = metadata return html` - ${cell_api_ready ? html`<${CellOutput} ...${output} cell_id=${cell_id} />` : html``} + ${cell_api_ready ? html`<${CellOutput} ...${output} sanitize_html=${sanitize_html} cell_id=${cell_id} />` : html``} + ${show_logs ? html`<${Logs} logs=${Object.values(logs)} line_heights=${[15]} set_cm_highlighted_line=${() => {}} />` : null} ` } diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index f931161a54..22b3f6ffbd 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -2,10 +2,10 @@ import { html, useState, useEffect, useLayoutEffect, useRef, useContext, useMemo import _ from "../imports/lodash.js" import { utf8index_to_ut16index } from "../common/UnicodeTools.js" -import { PlutoContext } from "../common/PlutoContext.js" +import { PlutoActionsContext } from "../common/PlutoContext.js" import { get_selected_doc_from_state } from "./CellInput/LiveDocsFromCursor.js" -import { go_to_definition_plugin, ScopeStateField, UsedVariablesFacet } from "./CellInput/go_to_definition_plugin.js" -import { detect_deserializer } from "../common/Serialization.js" +import { go_to_definition_plugin, GlobalDefinitionsFacet } from "./CellInput/go_to_definition_plugin.js" +// import { debug_syntax_plugin } from "./CellInput/debug_syntax_plugin.js" import { EditorState, @@ -23,29 +23,27 @@ import { HighlightStyle, lineNumbers, highlightSpecialChars, - foldGutter, drawSelection, indentOnInput, - defaultHighlightStyle, closeBrackets, rectangularSelection, highlightSelectionMatches, closeBracketsKeymap, - searchKeymap, foldKeymap, - commentKeymap, - syntaxTree, - Decoration, - ViewUpdate, - ViewPlugin, - WidgetType, indentUnit, - StateField, - StateEffect, autocomplete, + htmlLanguage, + markdownLanguage, + javascriptLanguage, + pythonLanguage, + syntaxHighlighting, + cssLanguage, + setDiagnostics, + moveLineUp, } from "../imports/CodemirrorPlutoSetup.js" -import { markdown, html as htmlLang, javascript, sqlLang, python, julia_andrey } from "./CellInput/mixedParsers.js" +import { markdown, html as htmlLang, javascript, sqlLang, python, julia_mixed } from "./CellInput/mixedParsers.js" +import { julia_andrey } from "../imports/CodemirrorPlutoSetup.js" import { pluto_autocomplete } from "./CellInput/pluto_autocomplete.js" import { NotebookpackagesFacet, pkgBubblePlugin } from "./CellInput/pkg_bubble_plugin.js" import { awesome_line_wrapping } from "./CellInput/awesome_line_wrapping.js" @@ -53,54 +51,258 @@ import { cell_movement_plugin, prevent_holding_a_key_from_doing_things_across_ce import { pluto_paste_plugin } from "./CellInput/pluto_paste_plugin.js" import { bracketMatching } from "./CellInput/block_matcher_plugin.js" import { cl } from "../common/ClassTable.js" +import { HighlightLineFacet, HighlightRangeFacet, highlightLinePlugin, highlightRangePlugin } from "./CellInput/highlight_line.js" +import { commentKeymap } from "./CellInput/comment_mixed_parsers.js" +import { ScopeStateField } from "./CellInput/scopestate_statefield.js" +import { mod_d_command } from "./CellInput/mod_d_command.js" +import { open_bottom_right_panel } from "./BottomRightPanel.js" +import { timeout_promise } from "../common/PlutoConnection.js" +import { LastFocusWasForcedEffect, tab_help_plugin } from "./CellInput/tab_help_plugin.js" +import { useEventListener } from "../common/useEventListener.js" +import { moveLineDown } from "../imports/CodemirrorPlutoSetup.js" -export const pluto_syntax_colors = HighlightStyle.define([ - /* The following three need a specific version of the julia parser, will add that later (still messing with it 😈) */ - // Symbol - { tag: tags.literal, color: "#5e7ad3", fontWeight: 700 }, - { tag: tags.macroName, color: "#5668a4", fontWeight: 700 }, - // `nothing` I guess... Any others? - { tag: tags.standard(tags.variableName), color: "#5e7ad3", fontWeight: 700 }, - - { tag: tags.bool, color: "#5e7ad3", fontWeight: 700 }, - - { tag: tags.keyword, color: "#fc6" }, - { tag: tags.comment, color: "#e96ba8", fontStyle: "italic" }, - { tag: tags.atom, color: "#815ba4" }, - { tag: tags.number, color: "#815ba4" }, - { tag: tags.bracket, color: "#48b685" }, - { tag: tags.keyword, color: "#ef6155" }, - { tag: tags.string, color: "#da5616" }, - { tag: tags.variableName, color: "#5668a4", fontWeight: 700 }, - // { tag: tags.variable2, color: "#06b6ef" }, - { tag: tags.definition(tags.variableName), color: "#f99b15" }, - { tag: tags.bracket, color: "#41323f" }, - { tag: tags.brace, color: "#41323f" }, - { tag: tags.tagName, color: "#ef6155" }, - { tag: tags.link, color: "#815ba4" }, - { tag: tags.invalid, color: "#000", background: "#ef6155" }, - // Object.keys(tags).map((x) => ({ tag: x, color: x })), - // Markdown - { tag: tags.heading, color: "#081e87", fontWeight: 500 }, - { tag: tags.heading1, color: "#081e87", fontWeight: 500, fontSize: "1.5em" }, - { tag: tags.heading2, color: "#081e87", fontWeight: 500, fontSize: "1.4em" }, - { tag: tags.heading3, color: "#081e87", fontWeight: 500, fontSize: "1.25em" }, - { tag: tags.heading4, color: "#081e87", fontWeight: 500, fontSize: "1.1em" }, - { tag: tags.heading5, color: "#081e87", fontWeight: 500, fontSize: "1em" }, - { tag: tags.heading6, color: "#081e87", fontWeight: "bold", fontSize: "0.8em" }, - { tag: tags.url, color: "#48b685", textDecoration: "underline" }, - { tag: tags.quote, color: "#444", fontStyle: "italic" }, - { tag: tags.literal, color: "#232227", fontWeight: 700 }, - // HTML - { tag: tags.tagName, color: "#01654f", fontWeight: 600 }, - { tag: tags.attributeName, color: "#01654f", fontWeight: 400 }, - { tag: tags.attributeValue, color: "#01654f", fontWeight: 600 }, - { tag: tags.angleBracket, color: "#01654f", fontWeight: 600 }, - { tag: tags.content, color: "#232227", fontWeight: 400 }, - { tag: tags.documentMeta, color: "#232227", fontStyle: "italic" }, - // CSS - { tag: tags.className, color: "grey", fontWeight: "bold" }, -]) +export const ENABLE_CM_MIXED_PARSER = window.localStorage.getItem("ENABLE_CM_MIXED_PARSER") === "true" + +if (ENABLE_CM_MIXED_PARSER) { + console.log(`YOU ENABLED THE CODEMIRROR MIXED LANGUAGE PARSER +Thanks! Awesome! +Please let us know if you find any bugs... +If enough people do this, we can make it the default parser. +`) +} + +// Added this so we can have people test the mixed parser, because I LIKE IT SO MUCH - DRAL +// @ts-ignore +window.PLUTO_TOGGLE_CM_MIXED_PARSER = () => { + window.localStorage.setItem("ENABLE_CM_MIXED_PARSER", String(!ENABLE_CM_MIXED_PARSER)) + window.location.reload() +} + +export const pluto_syntax_colors = HighlightStyle.define( + [ + /* The following three need a specific version of the julia parser, will add that later (still messing with it 😈) */ + // Symbol + // { tag: tags.controlKeyword, color: "var(--cm-keyword-color)", fontWeight: 700 }, + + { tag: tags.propertyName, color: "var(--cm-property-color)" }, + { tag: tags.unit, color: "var(--cm-tag-color)" }, + { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, + { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, + + // I (ab)use `special(brace)` for interpolations. + // lang-javascript does the same so I figure it is "best practice" 😅 + { tag: tags.special(tags.brace), color: "var(--cm-macro-color)", fontWeight: 700 }, + + // `nothing` I guess... Any others? + { + tag: tags.standard(tags.variableName), + color: "var(--cm-builtin-color)", + fontWeight: 700, + }, + + { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, + + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, + { tag: tags.atom, color: "var(--cm-atom-color)" }, + { tag: tags.number, color: "var(--cm-number-color)" }, + // { tag: tags.property, color: "#48b685" }, + // { tag: tags.attribute, color: "#48b685" }, + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.string, color: "var(--cm-string-color)" }, + { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, + // { tag: tags.variable2, color: "#06b6ef" }, + { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.bracket, color: "var(--cm-bracket-color)" }, + { tag: tags.brace, color: "var(--cm-bracket-color)" }, + { tag: tags.tagName, color: "var(--cm-tag-color)" }, + { tag: tags.link, color: "var(--cm-link-color)" }, + { + tag: tags.invalid, + color: "var(--cm-error-color)", + background: "var(--cm-error-bg-color)", + }, + ], + { + all: { color: `var(--cm-editor-text-color)` }, + scope: julia_andrey().language, + } +) + +export const pluto_syntax_colors_javascript = HighlightStyle.define( + [ + // SAME AS JULIA: + { tag: tags.propertyName, color: "var(--cm-property-color)" }, + { tag: tags.unit, color: "var(--cm-tag-color)" }, + { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, + { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, + + // `nothing` I guess... Any others? + { + tag: tags.standard(tags.variableName), + color: "var(--cm-builtin-color)", + fontWeight: 700, + }, + + { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, + + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.atom, color: "var(--cm-atom-color)" }, + { tag: tags.number, color: "var(--cm-number-color)" }, + // { tag: tags.property, color: "#48b685" }, + // { tag: tags.attribute, color: "#48b685" }, + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.string, color: "var(--cm-string-color)" }, + { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, + // { tag: tags.variable2, color: "#06b6ef" }, + { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.bracket, color: "var(--cm-bracket-color)" }, + { tag: tags.brace, color: "var(--cm-bracket-color)" }, + { tag: tags.tagName, color: "var(--cm-tag-color)" }, + { tag: tags.link, color: "var(--cm-link-color)" }, + { + tag: tags.invalid, + color: "var(--cm-error-color)", + background: "var(--cm-error-bg-color)", + }, + + // JAVASCRIPT SPECIFIC + { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic", filter: "none" }, + ], + { + scope: javascriptLanguage, + all: { + color: `var(--cm-editor-text-color)`, + filter: `contrast(0.5)`, + }, + } +) + +export const pluto_syntax_colors_python = HighlightStyle.define( + [ + // SAME AS JULIA: + { tag: tags.propertyName, color: "var(--cm-property-color)" }, + { tag: tags.unit, color: "var(--cm-tag-color)" }, + { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, + { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, + + // `nothing` I guess... Any others? + { + tag: tags.standard(tags.variableName), + color: "var(--cm-builtin-color)", + fontWeight: 700, + }, + + { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, + + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, + { tag: tags.atom, color: "var(--cm-atom-color)" }, + { tag: tags.number, color: "var(--cm-number-color)" }, + // { tag: tags.property, color: "#48b685" }, + // { tag: tags.attribute, color: "#48b685" }, + { tag: tags.keyword, color: "var(--cm-keyword-color)" }, + { tag: tags.string, color: "var(--cm-string-color)" }, + { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, + // { tag: tags.variable2, color: "#06b6ef" }, + { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, + { tag: tags.bracket, color: "var(--cm-bracket-color)" }, + { tag: tags.brace, color: "var(--cm-bracket-color)" }, + { tag: tags.tagName, color: "var(--cm-tag-color)" }, + { tag: tags.link, color: "var(--cm-link-color)" }, + { + tag: tags.invalid, + color: "var(--cm-error-color)", + background: "var(--cm-error-bg-color)", + }, + + // PYTHON SPECIFIC + ], + { + scope: pythonLanguage, + all: { + color: "var(--cm-editor-text-color)", + filter: `contrast(0.5)`, + }, + } +) + +export const pluto_syntax_colors_css = HighlightStyle.define( + [ + { tag: tags.propertyName, color: "var(--cm-css-accent-color)", fontWeight: 700 }, + { tag: tags.variableName, color: "var(--cm-css-accent-color)", fontWeight: 700 }, + { tag: tags.definitionOperator, color: "var(--cm-css-color)" }, + { tag: tags.keyword, color: "var(--cm-css-color)" }, + { tag: tags.modifier, color: "var(--cm-css-accent-color)" }, + { tag: tags.punctuation, opacity: 0.5 }, + { tag: tags.literal, color: "var(--cm-css-color)" }, + // { tag: tags.unit, color: "var(--cm-css-accent-color)" }, + { tag: tags.tagName, color: "var(--cm-css-color)", fontWeight: 700 }, + { tag: tags.className, color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, + { tag: tags.constant(tags.className), color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, + + // Comment from julia + { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, + ], + { + scope: cssLanguage, + all: { color: "var(--cm-css-color)" }, + } +) + +export const pluto_syntax_colors_html = HighlightStyle.define( + [ + { tag: tags.tagName, color: "var(--cm-html-accent-color)", fontWeight: 600 }, + { tag: tags.attributeName, color: "var(--cm-html-accent-color)", fontWeight: 600 }, + { tag: tags.attributeValue, color: "var(--cm-html-accent-color)" }, + { tag: tags.angleBracket, color: "var(--cm-html-accent-color)", fontWeight: 600, opacity: 0.7 }, + { tag: tags.content, color: "var(--cm-html-color)", fontWeight: 400 }, + { tag: tags.documentMeta, color: "var(--cm-html-accent-color)" }, + { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, + ], + { + scope: htmlLanguage, + all: { + color: "var(--cm-html-color)", + }, + } +) + +// https://github.com/codemirror/lang-markdown/blob/main/src/markdown.ts +export const pluto_syntax_colors_markdown = HighlightStyle.define( + [ + { tag: tags.content, color: "var(--cm-md-color)" }, + { tag: tags.quote, color: "var(--cm-md-color)" }, + { tag: tags.link, textDecoration: "underline" }, + { tag: tags.url, color: "var(--cm-md-color)", textDecoration: "none" }, + { tag: tags.emphasis, fontStyle: "italic" }, + { tag: tags.strong, fontWeight: "bolder" }, + + { tag: tags.heading, color: "var(--cm-md-color)", fontWeight: 700 }, + { + tag: tags.comment, + color: "var(--cm-comment-color)", + fontStyle: "italic", + }, + { + // These are all the things you won't see in the result: + // `-` bullet points, the `#` for headers, the `>` with quoteblocks. + tag: tags.processingInstruction, + color: "var(--cm-md-accent-color) !important", + opacity: "0.5", + }, + { tag: tags.monospace, color: "var(--cm-md-accent-color)" }, + ], + { + scope: markdownLanguage, + all: { + color: "var(--cm-md-color)", + }, + } +) const getValue6 = (/** @type {EditorView} */ cm) => cm.state.doc.toString() const setValue6 = (/** @type {EditorView} */ cm, value) => @@ -113,7 +315,7 @@ const replaceRange6 = (/** @type {EditorView} */ cm, text, from, to) => }) // Compartments: https://codemirror.net/6/examples/config/ -let useCompartment = (/** @type {import("../imports/Preact.js").Ref} */ codemirror_ref, value) => { +let useCompartment = (/** @type {import("../imports/Preact.js").Ref} */ codemirror_ref, value) => { let compartment = useRef(new Compartment()) let initial_value = useRef(compartment.current.of(value)) @@ -138,7 +340,8 @@ let line_and_ch_to_cm6_position = (/** @type {import("../imports/CodemirrorPluto * remote_code: string, * scroll_into_view_after_creation: boolean, * cell_dependencies: import("./Editor.js").CellDependencyData, - * variables_in_all_notebook: { [variable_name: string]: string }, + * nbpkg: import("./Editor.js").NotebookPkgData?, + * global_definition_locations: { [variable_name: string]: string }, * [key: string]: any, * }} props */ @@ -156,23 +359,40 @@ export const CellInput = ({ on_change, on_update_doc_query, on_focus_neighbor, + on_line_heights, nbpkg, cell_id, notebook_id, - running_disabled, - cell_dependencies, - variables_in_all_notebook, + any_logs, + show_logs, + set_show_logs, + set_cell_disabled, + cm_highlighted_line, + cm_highlighted_range, + metadata, + global_definition_locations, + cm_diagnostics, }) => { - let pluto_actions = useContext(PlutoContext) + let pluto_actions = useContext(PlutoActionsContext) + const { disabled: running_disabled, skip_as_script } = metadata + let [error, set_error] = useState(null) + if (error) { + const to_throw = error + set_error(null) + throw to_throw + } + + const notebook_id_ref = useRef(notebook_id) + notebook_id_ref.current = notebook_id - const newcm_ref = useRef(/** @type {EditorView} */ (null)) - const dom_node_ref = useRef(/** @type {HTMLElement} */ (null)) - const remote_code_ref = useRef(null) - const on_change_ref = useRef(null) - on_change_ref.current = on_change + const newcm_ref = useRef(/** @type {EditorView?} */ (null)) + const dom_node_ref = useRef(/** @type {HTMLElement?} */ (null)) + const remote_code_ref = useRef(/** @type {string?} */ (null)) let nbpkg_compartment = useCompartment(newcm_ref, NotebookpackagesFacet.of(nbpkg)) - let used_variables_compartment = useCompartment(newcm_ref, UsedVariablesFacet.of(variables_in_all_notebook)) + let global_definitions_compartment = useCompartment(newcm_ref, GlobalDefinitionsFacet.of(global_definition_locations)) + let highlighted_line_compartment = useCompartment(newcm_ref, HighlightLineFacet.of(cm_highlighted_line)) + let highlighted_range_compartment = useCompartment(newcm_ref, HighlightRangeFacet.of(cm_highlighted_range)) let editable_compartment = useCompartment(newcm_ref, EditorState.readOnly.of(disable_input)) let on_change_compartment = useCompartment( @@ -188,6 +408,8 @@ export const CellInput = ({ ) useLayoutEffect(() => { + if (dom_node_ref.current == null) return + const keyMapSubmit = () => { on_submit() return true @@ -208,8 +430,13 @@ export const CellInput = ({ let select_autocomplete_command = autocomplete.completionKeymap.find((keybinding) => keybinding.key === "Enter") let keyMapTab = (/** @type {EditorView} */ cm) => { + // I think this only gets called when we are not in an autocomplete situation, otherwise `tab_completion_command` is called. I think it only happens when you have a selection. + + if (cm.state.readOnly) { + return false + } // This will return true if the autocomplete select popup is open - if (select_autocomplete_command.run(cm)) { + if (select_autocomplete_command?.run?.(cm)) { return true } @@ -226,7 +453,7 @@ export const CellInput = ({ } } const keyMapMD = () => { - const cm = newcm_ref.current + const cm = /** @type{EditorView} */ (newcm_ref.current) const value = getValue6(cm) const trimmed = value.trim() const offset = value.length - value.trimStart().length @@ -269,7 +496,11 @@ export const CellInput = ({ cm.dispatch({ changes: [ { from: 0, to: 0, insert: prefix }, - { from: cm.state.doc.length, to: cm.state.doc.length, insert: suffix }, + { + from: cm.state.doc.length, + to: cm.state.doc.length, + insert: suffix, + }, ], selection: selection.from === 0 @@ -292,11 +523,12 @@ export const CellInput = ({ on_delete() return true } + return false } const keyMapBackspace = (/** @type {EditorView} */ cm) => { if (cm.state.facet(EditorState.readOnly)) { - return + return false } // Previously this was a very elaborate timed implementation...... @@ -308,6 +540,41 @@ export const CellInput = ({ on_delete() return true } + return false + } + + const keyMapMoveLine = (/** @type {EditorView} */ cm, direction) => { + if (cm.state.facet(EditorState.readOnly)) { + return false + } + + const selection = cm.state.selection.main + const all_is_selected = selection.anchor === 0 && selection.head === cm.state.doc.length + console.log({ all_is_selected }) + + if (all_is_selected || cm.state.doc.lines === 1) { + pluto_actions.move_remote_cells([cell_id], pluto_actions.get_notebook().cell_order.indexOf(cell_id) + (direction === -1 ? -1 : 2)) + + // workaround for https://github.com/preactjs/preact/issues/4235 + // but the crollintoview behaviour is nice, also when the preact issue is fixed. + requestIdleCallback(() => { + cm.dispatch({ + // TODO: remove me after fix + selection: { + anchor: 0, + head: cm.state.doc.length, + }, + + // TODO: keep me after fix + scrollIntoView: true, + }) + // TODO: remove me after fix + cm.focus() + }) + return true + } else { + return direction === 1 ? moveLineDown(cm) : moveLineUp(cm) + } } const plutoKeyMaps = [ @@ -324,9 +591,13 @@ export const CellInput = ({ { key: "Ctrl-Delete", run: keyMapDelete }, { key: "Backspace", run: keyMapBackspace }, { key: "Ctrl-Backspace", run: keyMapBackspace }, + { key: "Alt-ArrowUp", run: (x) => keyMapMoveLine(x, -1) }, + { key: "Alt-ArrowDown", run: (x) => keyMapMoveLine(x, 1) }, + + mod_d_command, ] - let DOCS_UPDATER_VERBOSE = true + let DOCS_UPDATER_VERBOSE = false const docs_updater = EditorView.updateListener.of((update) => { if (!update.view.hasFocus) { return @@ -334,30 +605,32 @@ export const CellInput = ({ if (update.docChanged || update.selectionSet) { let state = update.state - DOCS_UPDATER_VERBOSE && console.groupCollapsed("Selection") - let result = get_selected_doc_from_state(state, DOCS_UPDATER_VERBOSE) - DOCS_UPDATER_VERBOSE && console.log("Result:", result) - DOCS_UPDATER_VERBOSE && console.groupEnd() - - if (result != null) { - on_update_doc_query(result) + DOCS_UPDATER_VERBOSE && console.groupCollapsed("Live docs updater") + try { + let result = get_selected_doc_from_state(state, DOCS_UPDATER_VERBOSE) + if (result != null) { + on_update_doc_query(result) + } + } finally { + DOCS_UPDATER_VERBOSE && console.groupEnd() } } }) - // TODO remove me - //@ts-ignore - window.tags = tags + const usesDarkTheme = window.matchMedia("(prefers-color-scheme: dark)").matches const newcm = (newcm_ref.current = new EditorView({ - /** Migration #0: New */ state: EditorState.create({ doc: local_code, - extensions: [ + EditorView.theme({}, { dark: usesDarkTheme }), // Compartments coming from react state/props nbpkg_compartment, - used_variables_compartment, + highlighted_line_compartment, + highlighted_range_compartment, + global_definitions_compartment, editable_compartment, + highlightLinePlugin(), + highlightRangePlugin(), // This is waaaay in front of the keys it is supposed to override, // Which is necessary because it needs to run before *any* keymap, @@ -366,9 +639,14 @@ export const CellInput = ({ // TODO Use https://codemirror.net/6/docs/ref/#state.Prec when added to pluto-codemirror-setup prevent_holding_a_key_from_doing_things_across_cells, - pkgBubblePlugin({ pluto_actions, notebook_id }), + pkgBubblePlugin({ pluto_actions, notebook_id_ref }), ScopeStateField, - pluto_syntax_colors, + syntaxHighlighting(pluto_syntax_colors), + syntaxHighlighting(pluto_syntax_colors_html), + syntaxHighlighting(pluto_syntax_colors_markdown), + syntaxHighlighting(pluto_syntax_colors_javascript), + syntaxHighlighting(pluto_syntax_colors_python), + syntaxHighlighting(pluto_syntax_colors_css), lineNumbers(), highlightSpecialChars(), history(), @@ -377,7 +655,6 @@ export const CellInput = ({ // Multiple cursors with `alt` instead of the default `ctrl` (which we use for go to definition) EditorView.clickAddsSelectionRange.of((event) => event.altKey && !event.shiftKey), indentOnInput(), - defaultHighlightStyle.fallback, // Experimental: Also add closing brackets for tripple string // TODO also add closing string when typing a string macro EditorState.languageData.of((state, pos, side) => { @@ -390,41 +667,70 @@ export const CellInput = ({ highlightSelectionMatches(), bracketMatching(), docs_updater, + tab_help_plugin, // Remove selection on blur EditorView.domEventHandlers({ blur: (event, view) => { - view.dispatch({ - selection: { - anchor: view.state.selection.main.head, - head: view.state.selection.main.head, - }, - }) - set_cm_forced_focus(null) + console.warn("blur") + // it turns out that this condition is true *exactly* if and only if the blur event was triggered by blurring the window + let caused_by_window_blur = document.activeElement === view.contentDOM + + if (!caused_by_window_blur) { + // then it's caused by focusing something other than this cell in the editor. + // in this case, we want to collapse the selection into a single point, for aesthetic reasons. + setTimeout(() => { + view.dispatch({ + selection: { + anchor: view.state.selection.main.head, + }, + scrollIntoView: false, + }) + // and blur the DOM again (because the previous transaction might have re-focused it) + view.contentDOM.blur() + }, 0) + + set_cm_forced_focus(null) + } }, }), pluto_paste_plugin({ - pluto_actions: pluto_actions, - cell_id: cell_id, + pluto_actions, + cell_id, }), // Update live docs when in a cell that starts with `?` EditorView.updateListener.of((update) => { if (!update.docChanged) return if (update.state.doc.length > 0 && update.state.sliceDoc(0, 1) === "?") { - window.dispatchEvent(new CustomEvent("open_live_docs")) + open_bottom_right_panel("docs") } }), EditorState.tabSize.of(4), indentUnit.of("\t"), - julia_andrey(), - markdown(), - htmlLang(), //Provides tag closing!, - javascript(), - python(), - sqlLang, + ...(ENABLE_CM_MIXED_PARSER + ? [ + julia_mixed(), + markdown({ + defaultCodeLanguage: julia_mixed(), + }), + htmlLang(), //Provides tag closing!, + javascript(), + python(), + sqlLang, + ] + : [ + // + julia_andrey(), + ]), go_to_definition_plugin, pluto_autocomplete({ request_autocomplete: async ({ text }) => { - let { message } = await pluto_actions.send("complete", { query: text }, { notebook_id: notebook_id }) + let response = await timeout_promise( + pluto_actions.send("complete", { query: text }, { notebook_id: notebook_id_ref.current }), + 5000 + ).catch(console.warn) + if (!response) return null + + let { message } = response return { start: utf8index_to_ut16index(text, message.start), stop: utf8index_to_ut16index(text, message.stop), @@ -437,17 +743,42 @@ export const CellInput = ({ // I put plutoKeyMaps separately because I want make sure we have // higher priority 😈 keymap.of(plutoKeyMaps), + keymap.of(commentKeymap), // Before default keymaps (because we override some of them) // but after the autocomplete plugin, because we don't want to move cell when scrolling through autocomplete - cell_movement_plugin({ focus_on_neighbor: ({ cell_delta, line, character }) => on_focus_neighbor(cell_id, cell_delta, line, character) }), - keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...foldKeymap, ...commentKeymap]), + cell_movement_plugin({ + focus_on_neighbor: ({ cell_delta, line, character }) => on_focus_neighbor(cell_id, cell_delta, line, character), + }), + keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...foldKeymap]), placeholder("Enter cell code..."), EditorView.lineWrapping, - // Disabled awesome_line_wrapping because it still fails in a lot of cases - // awesome_line_wrapping, + // Wowww this has been enabled for some time now... wonder if there are issues about this yet ;) - DRAL + awesome_line_wrapping, + + // Reset diagnostics on change + EditorView.updateListener.of((update) => { + if (!update.docChanged) return + update.view.dispatch(setDiagnostics(update.state, [])) + }), on_change_compartment, + + // This is my weird-ass extension that checks the AST and shows you where + // there're missing nodes.. I'm not sure if it's a good idea to have it + // show_missing_syntax_plugin(), + + // Enable this plugin if you want to see the lezer tree, + // and possible lezer errors and maybe more debug info in the console: + // debug_syntax_plugin, + // Handle errors hopefully? + EditorView.exceptionSink.of((exception) => { + set_error(exception) + console.error("EditorView exception!", exception) + // alert( + // `We ran into an issue! We have lost your cursor 😞😓😿\n If this appears again, please press F12, then click the "Console" tab, eport an issue at https://github.com/fonsp/Pluto.jl/issues` + // ) + }), ], }), parent: dom_node_ref.current, @@ -463,6 +794,7 @@ export const CellInput = ({ if (focus_after_creation) { setTimeout(() => { let view = newcm_ref.current + if (view == null) return view.dom.scrollIntoView({ behavior: "smooth", block: "nearest", @@ -472,12 +804,38 @@ export const CellInput = ({ anchor: view.state.doc.length, head: view.state.doc.length, }, + effects: [LastFocusWasForcedEffect.of(true)], }) view.focus() }) } + + // @ts-ignore + const lines_wrapper_dom_node = dom_node_ref.current.querySelector("div.cm-content") + if (lines_wrapper_dom_node) { + const lines_wrapper_resize_observer = new ResizeObserver(() => { + const line_nodes = lines_wrapper_dom_node.children + const tops = _.map(line_nodes, (c) => /** @type{HTMLElement} */ (c).offsetTop) + const diffs = tops.slice(1).map((y, i) => y - tops[i]) + const heights = [...diffs, 15] + on_line_heights(heights) + }) + + lines_wrapper_resize_observer.observe(lines_wrapper_dom_node) + return () => { + lines_wrapper_resize_observer.unobserve(lines_wrapper_dom_node) + } + } }, []) + useEffect(() => { + if (newcm_ref.current == null) return + const cm = newcm_ref.current + const diagnostics = cm_diagnostics + + cm.dispatch(setDiagnostics(cm.state, diagnostics)) + }, [cm_diagnostics]) + // Effect to apply "remote_code" to the cell when it changes... // ideally this won't be necessary as we'll have actual multiplayer, // or something to tell the user that the cell is out of sync. @@ -498,6 +856,7 @@ export const CellInput = ({ useEffect(() => { const cm = newcm_ref.current + if (cm == null) return if (cm_forced_focus == null) { cm.dispatch({ selection: { @@ -530,59 +889,147 @@ export const CellInput = ({ // block: "center", }) - newcm_ref.current.focus() - newcm_ref.current.dispatch({ + cm.focus() + cm.dispatch({ + scrollIntoView: true, selection: new_selection, + effects: [ + EditorView.scrollIntoView(EditorSelection.range(new_selection.anchor, new_selection.head), { + yMargin: 80, + }), + LastFocusWasForcedEffect.of(true), + ], }) } }, [cm_forced_focus]) return html` - <${InputContextMenu} on_delete=${on_delete} cell_id=${cell_id} run_cell=${on_submit} running_disabled=${running_disabled} /> + <${InputContextMenu} + on_delete=${on_delete} + cell_id=${cell_id} + run_cell=${on_submit} + skip_as_script=${skip_as_script} + running_disabled=${running_disabled} + any_logs=${any_logs} + show_logs=${show_logs} + set_show_logs=${set_show_logs} + set_cell_disabled=${set_cell_disabled} + /> ` } -const InputContextMenu = ({ on_delete, cell_id, run_cell, running_disabled }) => { +const InputContextMenu = ({ on_delete, cell_id, run_cell, skip_as_script, running_disabled, any_logs, show_logs, set_show_logs, set_cell_disabled }) => { const timeout = useRef(null) - let pluto_actions = useContext(PlutoContext) - const [open, setOpen] = useState(false) + let pluto_actions = useContext(PlutoActionsContext) + const [open, setOpenState] = useState(false) + const element_ref = useRef(/** @type {HTMLButtonElement?} */ (null)) + const prevously_focused_element_ref = useRef(/** @type {Element?} */ (null)) + const setOpen = (val) => { + if (val) { + prevously_focused_element_ref.current = document.activeElement + } + setOpenState(val) + } + useLayoutEffect(() => { + if (open) { + element_ref.current?.querySelector("li")?.focus() + } else { + if (prevously_focused_element_ref.current instanceof HTMLElement) prevously_focused_element_ref.current?.focus() + } + }, [open]) + const mouseenter = () => { - clearTimeout(timeout.current) + if (timeout.current) clearTimeout(timeout.current) } - const toggle_running_disabled = async (e) => { - const new_val = !running_disabled + const toggle_skip_as_script = async (e) => { + const new_val = !skip_as_script e.preventDefault() - e.stopPropagation() + // e.stopPropagation() await pluto_actions.update_notebook((notebook) => { - notebook.cell_inputs[cell_id].running_disabled = new_val + notebook.cell_inputs[cell_id].metadata["skip_as_script"] = new_val }) - // we also 'run' the cell if it is disabled, this will make the backend propage the disabled state to dependent cells - await run_cell() + } + const toggle_running_disabled = async (e) => { + const new_val = !running_disabled + await set_cell_disabled(new_val) + } + const toggle_logs = () => set_show_logs(!show_logs) + + const is_copy_output_supported = () => { + let notebook = /** @type{import("./Editor.js").NotebookData?} */ (pluto_actions.get_notebook()) + let cell_result = notebook?.cell_results?.[cell_id] + return !!cell_result && !cell_result.errored && !cell_result.queued && cell_result.output.mime === "text/plain" && cell_result.output.body + } + + const copy_output = () => { + let notebook = /** @type{import("./Editor.js").NotebookData?} */ (pluto_actions.get_notebook()) + let cell_output = notebook?.cell_results?.[cell_id]?.output.body ?? "" + cell_output && + navigator.clipboard.writeText(cell_output).catch((err) => { + alert(`Error copying cell output`) + }) } + useEventListener(window, "keydown", (e) => { + if (e.key === "Escape") { + setOpen(false) + } + }) + return html` ` diff --git a/frontend/components/CellInput/LiveDocsFromCursor.js b/frontend/components/CellInput/LiveDocsFromCursor.js index a9c4a71d90..6e89f344f5 100644 --- a/frontend/components/CellInput/LiveDocsFromCursor.js +++ b/frontend/components/CellInput/LiveDocsFromCursor.js @@ -1,5 +1,5 @@ import { EditorState, syntaxTree } from "../../imports/CodemirrorPlutoSetup.js" -import { ScopeStateField } from "./go_to_definition_plugin.js" +import { ScopeStateField } from "./scopestate_statefield.js" let get_root_variable_from_expression = (cursor) => { if (cursor.name === "SubscriptExpression") { @@ -24,9 +24,24 @@ let VALID_DOCS_TYPES = [ "MacroFieldExpression", "MacroIdentifier", "Operator", + "Definition", "ParameterizedIdentifier", ] -let keywords_that_have_docs_and_are_cool = ["import", "export", "try", "catch", "finally", "quote", "do", "struct", "mutable"] +let keywords_that_have_docs_and_are_cool = [ + "import", + "export", + "try", + "catch", + "finally", + "quote", + "do", + "struct", + "mutable", + "module", + "baremodule", + "if", + "let", +] let is_docs_searchable = (/** @type {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} */ cursor) => { if (keywords_that_have_docs_and_are_cool.includes(cursor.name)) { @@ -42,6 +57,9 @@ let is_docs_searchable = (/** @type {import("../../imports/CodemirrorPlutoSetup. if (cursor.name === "TypeArgumentList") { continue } + if (cursor.name === "FieldName" || cursor.name === "MacroName" || cursor.name === "MacroFieldName") { + continue + } if (!is_docs_searchable(cursor)) { return false } @@ -92,7 +110,7 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb iterations = iterations + 1 // Collect parents in a list so I can compare them easily - let parent_cursor = cursor.node.cursor + let parent_cursor = cursor.node.cursor() let parents = [] while (parent_cursor.parent()) { parents.push(parent_cursor.name) @@ -115,6 +133,15 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb // We're inside a `... = ...` inside the struct } else if (parents.includes("TypedExpression") && parents.indexOf("TypedExpression") < index_of_struct_in_parents) { // We're inside a `x::X` inside the struct + } else if (parents.includes("SubtypedExpression") && parents.indexOf("SubtypedExpression") < index_of_struct_in_parents) { + // We're inside `Real` in `struct MyNumber<:Real` + while (parent?.name !== "SubtypedExpression") { + parent = parent.parent + } + const type_node = parent.lastChild + if (type_node.from <= cursor.from && type_node.to >= cursor.to) { + return state.doc.sliceString(type_node.from, type_node.to) + } } else if (cursor.name === "struct" || cursor.name === "mutable") { cursor.parent() cursor.firstChild() @@ -158,7 +185,7 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb } // `html"asd"` should yield "html" - if (cursor.name === "Identifier" && parent.name === "PrefixedString") { + if (cursor.name === "Identifier" && parent.name === "Prefix") { continue } if (cursor.name === "PrefixedString") { @@ -217,7 +244,8 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb if ( cursor.name === "Identifier" && parent.name === "ArgumentList" && - (parent.parent.name === "FunctionAssignmentExpression" || parent.parent.name === "FunctionDefinition") + (parent.parent.parent.name === "FunctionAssignmentExpression" || + parent.parent.name === "FunctionDefinition") ) { continue } @@ -269,6 +297,7 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb if (VALID_DOCS_TYPES.includes(cursor.name) || keywords_that_have_docs_and_are_cool.includes(cursor.name)) { if (!is_docs_searchable(cursor)) { + console.log("NOT DOCS SEARCHABLE") return undefined } @@ -280,7 +309,7 @@ export let get_selected_doc_from_state = (/** @type {EditorState} */ state, verb } // We have do find the current usage of the variable, and make sure it has no definition inside this cell - let usage = Array.from(scopestate.usages).find((x) => x.usage.from === root_variable_node.from && x.usage.to === root_variable_node.to) + let usage = scopestate.usages.find((x) => x.usage.from === root_variable_node.from && x.usage.to === root_variable_node.to) // If we can't find the usage... we just assume it can be docs showed I guess if (usage?.definition == null) { return state.doc.sliceString(cursor.from, cursor.to) diff --git a/frontend/components/CellInput/awesome_line_wrapping.js b/frontend/components/CellInput/awesome_line_wrapping.js index 4dce1f2b41..8abf500853 100644 --- a/frontend/components/CellInput/awesome_line_wrapping.js +++ b/frontend/components/CellInput/awesome_line_wrapping.js @@ -1,5 +1,7 @@ import _ from "../../imports/lodash.js" import { StateEffect, StateField, EditorView, Decoration } from "../../imports/CodemirrorPlutoSetup.js" +import { ReactWidget } from "./ReactWidget.js" +import { html } from "../../imports/Preact.js" /** * Plugin that makes line wrapping in the editor respect the identation of the line. @@ -28,25 +30,6 @@ const extra_cycle_character_width = StateField.define({ }, }) -// https://github.com/codemirror/view/blob/590690c71df9a3f25fd4d78edea5322f18114507/src/dom.ts#L223 -/** @type {Range} */ -let scratchRange -export function textRange(node, from, to = from) { - let range = scratchRange || (scratchRange = document.createRange()) - range.setEnd(node, to) - range.setStart(node, from) - console.log(`range:`, range.cloneContents()) - console.log(`range:`, range.startOffset, range.endOffset) - console.log(`range:`, range) - return range -} -// https://github.com/codemirror/view/blob/590690c71df9a3f25fd4d78edea5322f18114507/src/dom.ts#L41 -export function clientRectsFor(dom) { - if (dom.nodeType == 3) return textRange(dom, 0, dom.nodeValue.length).getClientRects() - else if (dom.nodeType == 1) return dom.getClientRects() - else return [] -} - let character_width_listener = EditorView.updateListener.of((viewupdate) => { let width = viewupdate.view.defaultCharacterWidth let { defaultCharacterWidth, measuredSpaceWidth } = viewupdate.view.state.field(extra_cycle_character_width, false) @@ -76,66 +59,14 @@ let character_width_listener = EditorView.updateListener.of((viewupdate) => { } }) -let indent_decorations = StateField.define({ - create() { - return Decoration.none - }, - update(deco, tr) { - if (!tr.docChanged && deco !== Decoration.none) return deco - - let decorations = [] - - for (let i of _.range(0, tr.state.doc.lines)) { - let line = tr.state.doc.line(i + 1) - if (line.length === 0) continue - - let indented_chars = 0 - for (let ch of line.text) { - if (ch === "\t") { - indented_chars = indented_chars + 1 - } else if (ch === " ") { - indented_chars = indented_chars + 1 - } else { - break - } - } - - const line_wrapping = Decoration.line({ - attributes: { - style: "display: flex", - }, - }) - decorations.push(line_wrapping.range(line.from, line.from)) - - if (indented_chars !== 0) { - const wrap_indentation = Decoration.mark({ - class: "indentation", - attributes: { - style: "flex-shrink: 0;", - }, - }) - decorations.push(wrap_indentation.range(line.from, line.from + indented_chars)) - } - - if (line.from + indented_chars - line.to !== 0) { - const wrap_rest = Decoration.mark({ - class: "indentation-rest", - }) - decorations.push(wrap_rest.range(line.from + indented_chars, line.to)) - } - } - return Decoration.set(decorations, true) - }, - provide: (f) => EditorView.decorations.from(f), -}) - -let ARBITRARY_INDENT_LINE_WRAP_LIMIT = 48 +let ARBITRARY_INDENT_LINE_WRAP_LIMIT = 12 let line_wrapping_decorations = StateField.define({ create() { return Decoration.none }, update(deco, tr) { - let tabSize = tr.state.tabSize + // let tabSize = tr.state.tabSize + let tabSize = 4 let previous = tr.startState.field(extra_cycle_character_width, false) let previous_space_width = previous.measuredSpaceWidth ?? previous.defaultCharacterWidth let { measuredSpaceWidth, defaultCharacterWidth } = tr.state.field(extra_cycle_character_width, false) @@ -146,27 +77,57 @@ let line_wrapping_decorations = StateField.define({ let decorations = [] - console.log(`space_width:`, space_width) - // TODO? Only apply to visible lines? Wouldn't that screw stuff up?? // TODO? Don't create new decorations when a line hasn't changed? for (let i of _.range(0, tr.state.doc.lines)) { let line = tr.state.doc.line(i + 1) if (line.length === 0) continue - let indented_chars = 0 + let indented_tabs = 0 for (let ch of line.text) { if (ch === "\t") { - indented_chars = indented_chars + tabSize - } else if (ch === " ") { - indented_chars = indented_chars + 1 + indented_tabs++ + // For now I ignore spaces... because they are weird... and stupid! + // } else if (ch === " ") { + // indented_chars = indented_chars + 1 + // indented_text_characters++ } else { break } } + const characters_to_count = Math.min(indented_tabs, ARBITRARY_INDENT_LINE_WRAP_LIMIT) + const offset = characters_to_count * tabSize * space_width + + const linerwapper = Decoration.line({ + attributes: { + // style: rules.cssText, + style: `--indented: ${offset}px;`, + class: "awesome-wrapping-plugin-the-line", + }, + }) + // Need to push before the tabs one else codemirror gets madddd + decorations.push(linerwapper.range(line.from, line.from)) + + if (characters_to_count !== 0) { + decorations.push( + Decoration.mark({ + class: "awesome-wrapping-plugin-the-tabs", + }).range(line.from, line.from + characters_to_count) + ) + } + if (indented_tabs > characters_to_count) { + for (let i of _.range(characters_to_count, indented_tabs)) { + decorations.push( + Decoration.replace({ + widget: new ReactWidget(html``), + block: false, + }).range(line.from + i, line.from + i + 1) + ) + } + } + // let tabs_in_front = Math.min(line.text.match(/^\t*/)[0].length) * tabSize - const offset = Math.min(indented_chars, ARBITRARY_INDENT_LINE_WRAP_LIMIT) * space_width // TODO? Cache the CSSStyleDeclaration? // This is used when we don't use a css class, but we do need a css class because @@ -175,21 +136,95 @@ let line_wrapping_decorations = StateField.define({ // rules.setProperty("--idented", `${offset}px`) // rules.setProperty("text-indent", "calc(-1 * var(--idented) - 1px)") // I have no idea why, but without the - 1px it behaves weirdly periodically // rules.setProperty("padding-left", "calc(var(--idented) + var(--cm-left-padding, 4px))") + } + return Decoration.set(decorations) + }, + provide: (f) => EditorView.decorations.from(f), +}) - const linerwapper = Decoration.line({ - attributes: { - // style: rules.cssText, - style: `--indented: ${offset}px;`, - class: "awesome-wrapping-plugin-indent", - }, - }) +// Add this back in +// let dont_break_before_spaces_matcher = new MatchDecorator({ +// regexp: /[^ \t]+[ \t]+/g, +// decoration: Decoration.mark({ +// class: "indentation-so-dont-break", +// }), +// }) - decorations.push(linerwapper.range(line.from, line.from)) +let identation_so_dont_break_marker = Decoration.mark({ + class: "indentation-so-dont-break", +}) + +let dont_break_before_spaces = StateField.define({ + create() { + return Decoration.none + }, + update(deco, tr) { + let decorations = [] + let pos = 0 + for (const line of tr.newDoc) { + for (const match of /** @type{string} */ (line).matchAll(/[^ \t]+([ \t]|$)+/g)) { + if (match.index == null || match.index === 0) continue // Sneaky negative lookbehind + decorations.push(identation_so_dont_break_marker.range(pos + match.index, pos + match.index + match[0].length)) + } } return Decoration.set(decorations, true) }, provide: (f) => EditorView.decorations.from(f), }) -// export let awesome_line_wrapping = [extra_cycle_character_width, character_width_listener, line_wrapping_decorations] -export let awesome_line_wrapping = [indent_decorations] +// let break_after_space_matcher = new MatchDecorator({ +// regexp: /[ ](?=[^ \t])/g, +// decoration: Decoration.widget({ +// widget: new ReactWidget(html` `), +// block: false, +// side: 1, +// }), +// }) + +// let break_after_space = ViewPlugin.define( +// (view) => { +// return { +// decorations: break_after_space_matcher.createDeco(view), +// update(update) { +// this.decorations = break_after_space_matcher.updateDeco(update, this.decorations) +// }, +// } +// }, +// { +// decorations: (v) => v.decorations, +// } +// ) + +// let dont_break_start_of_line_matcher = new MatchDecorator({ +// regexp: /^[ \t]+[^ \t]/g, +// decoration: Decoration.mark({ +// class: "Uhhh", +// }), +// }) + +// let dont_break_start_of_line = ViewPlugin.define( +// (view) => { +// return { +// decorations: dont_break_start_of_line_matcher.createDeco(view), +// update(update) { +// this.decorations = dont_break_start_of_line_matcher.updateDeco(update, this.decorations) +// }, +// } +// }, +// { +// decorations: (v) => v.decorations, +// } +// ) + +// console.log(`awesome_line_wrapping:`, indent_decorations) +export let awesome_line_wrapping = [ + // dont_break_start_of_line, + extra_cycle_character_width, + character_width_listener, + line_wrapping_decorations, + // break_after_space, + // dont_break_before_spaces, +] +// export let awesome_line_wrapping = [] +// export let awesome_line_wrapping = indent_decorations +// export let awesome_line_wrapping = [dont_break_before_spaces, break_after_space] diff --git a/frontend/components/CellInput/block_matcher_plugin.js b/frontend/components/CellInput/block_matcher_plugin.js index a9907eecfe..b6d05bbee8 100644 --- a/frontend/components/CellInput/block_matcher_plugin.js +++ b/frontend/components/CellInput/block_matcher_plugin.js @@ -13,9 +13,39 @@ import { Decoration } from "../../imports/CodemirrorPlutoSetup.js" * Also it doesn't do non-matching now, there is just matching or nothing. */ +function match_try_node(node) { + let try_node = node.parent.firstChild + let possibly_end = node.parent.lastChild + let did_match = possibly_end.name === "end" + if (!did_match) return null + + let catch_node = node.parent.getChild("CatchClause")?.firstChild + let else_node = node.parent.getChild("TryElseClause")?.firstChild + let finally_node = node.parent.getChild("FinallyClause")?.firstChild + + return [ + { from: try_node.from, to: try_node.to }, + catch_node && { from: catch_node.from, to: catch_node.to }, + else_node && { from: else_node.from, to: else_node.to }, + finally_node && { from: finally_node.from, to: finally_node.to }, + { from: possibly_end.from, to: possibly_end.to }, + ].filter((x) => x != null) + +} + function match_block(node) { if (node.name === "end") { - node = node.parent.firstChild + if (node.parent.name === "IfStatement") { + // Try moving to the "if" part because + // the rest of the code is looking for that + node = node.parent?.firstChild?.firstChild + } else { + node = node.parent.firstChild + } + } + + if (node == null) { + return [] } // if (node.name === "StructDefinition") node = node.firstChild @@ -144,48 +174,56 @@ function match_block(node) { ] } - if (node.name === "try" || node.name === "catch" || node.name === "finally") { - if (node.name === "catch") node = node.parent - if (node.name === "finally") node = node.parent - - let try_node = node.parent.firstChild - let possibly_end = node.parent.lastChild - let did_match = possibly_end.name === "end" - if (!did_match) return null - - let catch_node = node.parent.getChild("CatchClause")?.firstChild - let finally_node = node.parent.getChild("FinallyClause")?.firstChild - - return [ - { from: try_node.from, to: try_node.to }, - catch_node && { from: catch_node.from, to: catch_node.to }, - finally_node && { from: finally_node.from, to: finally_node.to }, - { from: possibly_end.from, to: possibly_end.to }, - ].filter((x) => x != null) - } - if (node.name === "if" || node.name === "else" || node.name === "elseif") { - if (node.name === "else") node = node.parent + if (node.name === "if") node = node.parent + let iselse = false + if (node.name === "else") { + node = node.parent + iselse = true + } + if (node.name === "elseif") node = node.parent.parent let try_node = node.parent.firstChild let possibly_end = node.parent.lastChild let did_match = possibly_end.name === "end" if (!did_match) return null + if (iselse && try_node.name === "try") { + return match_try_node(node) // try catch else finally end + } + let decorations = [] decorations.push({ from: try_node.from, to: try_node.to }) + for (let elseif_clause_node of node.parent.getChildren("ElseifClause")) { + let elseif_node = elseif_clause_node.firstChild + decorations.push({ from: elseif_node.from, to: elseif_node.to }) + } for (let else_clause_node of node.parent.getChildren("ElseClause")) { let else_node = else_clause_node.firstChild decorations.push({ from: else_node.from, to: else_node.to }) } - for (let elseif_node of node.parent.getChildren("elseif")) { - decorations.push({ from: elseif_node.from, to: elseif_node.to }) - } decorations.push({ from: possibly_end.from, to: possibly_end.to }) return decorations } + if (node.name === "try" + || node.name === "catch" + || node.name === "finally" + || node.name === "else") { + + if (node.name === "catch") node = node.parent + if (node.name === "finally") node = node.parent + if (node.name === "else") node = node.parent + + let possibly_end = node.parent.lastChild + let did_match = possibly_end.name === "end" + if (!did_match) return null + + return match_try_node(node) + } + + return null } diff --git a/frontend/components/CellInput/comment_mixed_parsers.js b/frontend/components/CellInput/comment_mixed_parsers.js new file mode 100644 index 0000000000..0ba87618d4 --- /dev/null +++ b/frontend/components/CellInput/comment_mixed_parsers.js @@ -0,0 +1,168 @@ +// This is "just" https://github.com/codemirror/comment/blob/da336b8660dedab23e06ced2b430f2ac56ef202d/src/comment.ts +// (@codemirror/comment) +// But with a change that helps mixed parser environments: +// If the comment-style (`#`, `//`, `/* */`, etc) at the begin and end of the selection is the same, +// we don't use the comment-style per line, but use the begin/end style for every line. + +import { EditorSelection, EditorState } from "../../imports/CodemirrorPlutoSetup.js" + +/// Comment or uncomment the current selection. Will use line comments +/// if available, otherwise falling back to block comments. +export const toggleComment = (target) => { + let config = getConfig(target.state) + return config.line ? toggleLineComment(target) : config.block ? toggleBlockComment(target) : false +} +function command(f, option) { + return ({ state, dispatch }) => { + if (state.readOnly) return false + let tr = f(option, state.selection.ranges, state) + if (!tr) return false + dispatch(state.update(tr)) + return true + } +} +/// Comment or uncomment the current selection using line comments. +/// The line comment syntax is taken from the +/// [`commentTokens`](#comment.CommentTokens) [language +/// data](#state.EditorState.languageDataAt). +export const toggleLineComment = command(changeLineComment, 0 /* Toggle */) +/// Comment the current selection using line comments. +export const lineComment = command(changeLineComment, 1 /* Comment */) +/// Uncomment the current selection using line comments. +export const lineUncomment = command(changeLineComment, 2 /* Uncomment */) +/// Comment or uncomment the current selection using block comments. +/// The block comment syntax is taken from the +/// [`commentTokens`](#comment.CommentTokens) [language +/// data](#state.EditorState.languageDataAt). +export const toggleBlockComment = command(changeBlockComment, 0 /* Toggle */) +/// Comment the current selection using block comments. +export const blockComment = command(changeBlockComment, 1 /* Comment */) +/// Uncomment the current selection using block comments. +export const blockUncomment = command(changeBlockComment, 2 /* Uncomment */) +/// Default key bindings for this package. +/// +/// - Ctrl-/ (Cmd-/ on macOS): [`toggleComment`](#comment.toggleComment). +/// - Shift-Alt-a: [`toggleBlockComment`](#comment.toggleBlockComment). +export const commentKeymap = [ + { key: "Mod-/", run: toggleComment }, + { key: "Alt-A", run: toggleBlockComment }, +] +function getConfig(state, pos = state.selection.main.head) { + let data = state.languageDataAt("commentTokens", pos) + return data.length ? data[0] : {} +} +const SearchMargin = 50 +/// Determines if the given range is block-commented in the given +/// state. +function findBlockComment(state, { open, close }, from, to) { + let textBefore = state.sliceDoc(from - SearchMargin, from) + let textAfter = state.sliceDoc(to, to + SearchMargin) + let spaceBefore = /\s*$/.exec(textBefore)[0].length, + spaceAfter = /^\s*/.exec(textAfter)[0].length + let beforeOff = textBefore.length - spaceBefore + if (textBefore.slice(beforeOff - open.length, beforeOff) == open && textAfter.slice(spaceAfter, spaceAfter + close.length) == close) { + return { open: { pos: from - spaceBefore, margin: spaceBefore && 1 }, close: { pos: to + spaceAfter, margin: spaceAfter && 1 } } + } + let startText, endText + if (to - from <= 2 * SearchMargin) { + startText = endText = state.sliceDoc(from, to) + } else { + startText = state.sliceDoc(from, from + SearchMargin) + endText = state.sliceDoc(to - SearchMargin, to) + } + let startSpace = /^\s*/.exec(startText)[0].length, + endSpace = /\s*$/.exec(endText)[0].length + let endOff = endText.length - endSpace - close.length + if (startText.slice(startSpace, startSpace + open.length) == open && endText.slice(endOff, endOff + close.length) == close) { + return { + open: { pos: from + startSpace + open.length, margin: /\s/.test(startText.charAt(startSpace + open.length)) ? 1 : 0 }, + close: { pos: to - endSpace - close.length, margin: /\s/.test(endText.charAt(endOff - 1)) ? 1 : 0 }, + } + } + return null +} +// Performs toggle, comment and uncomment of block comments in +// languages that support them. +function changeBlockComment(option, ranges, state) { + let tokens = ranges.map((r) => getConfig(state, r.from).block) + if (!tokens.every((c) => c)) return null + let comments = ranges.map((r, i) => findBlockComment(state, tokens[i], r.from, r.to)) + if (option != 2 /* Uncomment */ && !comments.every((c) => c)) { + let index = 0 + return state.changeByRange((range) => { + let { open, close } = tokens[index++] + if (comments[index]) return { range } + let shift = open.length + 1 + return { + changes: [ + { from: range.from, insert: open + " " }, + { from: range.to, insert: " " + close }, + ], + range: EditorSelection.range(range.anchor + shift, range.head + shift), + } + }) + } else if (option != 1 /* Comment */ && comments.some((c) => c)) { + let changes = [] + for (let i = 0, comment; i < comments.length; i++) + if ((comment = comments[i])) { + let token = tokens[i], + { open, close } = comment + changes.push( + { from: open.pos - token.open.length, to: open.pos + open.margin }, + { from: close.pos - close.margin, to: close.pos + token.close.length } + ) + } + return { changes } + } + return null +} +// Performs toggle, comment and uncomment of line comments. +function changeLineComment(option, ranges, state) { + let lines = [] + let prevLine = -1 + for (let { from, to } of ranges) { + // DRAL EDIIIIIITS + // If the comment tokens at the begin and end are the same, + // I assume we want these for the whole range! + let comment_token_from = getConfig(state, from).line + let comment_token_to = getConfig(state, to).line + let overwrite_token = comment_token_from === comment_token_to ? comment_token_from : null + + let startI = lines.length, + minIndent = 1e9 + for (let pos = from; pos <= to; ) { + let line = state.doc.lineAt(pos) + if (line.from > prevLine && (from == to || to > line.from)) { + prevLine = line.from + // DRAL EDIIIIIIIITS + let token = overwrite_token ?? getConfig(state, pos).line + if (!token) continue + let indent = /^\s*/.exec(line.text)[0].length + let empty = indent == line.length + let comment = line.text.slice(indent, indent + token.length) == token ? indent : -1 + if (indent < line.text.length && indent < minIndent) minIndent = indent + lines.push({ line, comment, token, indent, empty, single: false }) + } + pos = line.to + 1 + } + if (minIndent < 1e9) for (let i = startI; i < lines.length; i++) if (lines[i].indent < lines[i].line.text.length) lines[i].indent = minIndent + if (lines.length == startI + 1) lines[startI].single = true + } + if (option != 2 /* Uncomment */ && lines.some((l) => l.comment < 0 && (!l.empty || l.single))) { + let changes = [] + for (let { line, token, indent, empty, single } of lines) if (single || !empty) changes.push({ from: line.from + indent, insert: token + " " }) + let changeSet = state.changes(changes) + return { changes: changeSet, selection: state.selection.map(changeSet, 1) } + } else if (option != 1 /* Comment */ && lines.some((l) => l.comment >= 0)) { + let changes = [] + for (let { line, comment, token } of lines) + if (comment >= 0) { + let from = line.from + comment, + to = from + token.length + if (line.text[to - line.from] == " ") to++ + changes.push({ from, to }) + } + return { changes } + } + return null +} diff --git a/frontend/components/CellInput/debug_syntax_plugin.js b/frontend/components/CellInput/debug_syntax_plugin.js new file mode 100644 index 0000000000..83d4d6ca5d --- /dev/null +++ b/frontend/components/CellInput/debug_syntax_plugin.js @@ -0,0 +1,67 @@ +import { EditorView, syntaxTree, syntaxTreeAvailable } from "../../imports/CodemirrorPlutoSetup.js" +import { iterate_with_cursor } from "./lezer_template.js" + +/** + * @param {any} doc + * @param {ReturnType} tree + */ +let find_error_nodes = (doc, tree) => { + iterate_with_cursor({ + tree: tree, + enter: (cursor) => { + if (cursor.type.isError) { + console.group(`Found error node in ${cursor.node.parent?.name}`) + try { + let text_before_cursor = doc.sliceString(cursor.from - 10, cursor.from) + let text = doc.sliceString(cursor.from, cursor.to) + let text_after_cursor = doc.sliceString(cursor.to, cursor.to + 10) + + if (text === "") { + console.log(`${text_before_cursor}⚠${text_after_cursor}`) + console.log(`${" ".repeat(text_before_cursor.length)}^$${" ".repeat(text_after_cursor.length)}`) + } else { + console.log(`${text_before_cursor}${text}${text_after_cursor}`) + console.log(`${" ".repeat(text_before_cursor.length)}${"^".repeat(text.length)}$${" ".repeat(text_after_cursor.length)}`) + } + } finally { + console.groupEnd() + } + return false + } + }, + leave: () => {}, + }) +} + +export const debug_syntax_plugin = EditorView.updateListener.of((update) => { + if (update.docChanged || update.selectionSet || syntaxTree(update.state) !== syntaxTree(update.startState)) { + if (syntaxTreeAvailable(update.state)) { + let state = update.state + console.group("Selection") + try { + console.groupCollapsed("Lezer tree") + try { + console.log(syntaxTree(state).toString()) + } finally { + console.groupEnd() + } + console.groupCollapsed("Document text") + try { + console.log(update.state.doc.sliceString(0, update.state.doc.length)) + } finally { + console.groupEnd() + } + console.group("Lezer errors") + try { + find_error_nodes(update.state.doc, syntaxTree(state)) + } finally { + console.groupEnd() + } + } finally { + console.groupEnd() + } + } else { + console.log("⚠️ Full syntax tree not available") + } + } +}) diff --git a/frontend/components/CellInput/go_to_definition_plugin.js b/frontend/components/CellInput/go_to_definition_plugin.js index 42b2c7ad5d..4dd753747f 100644 --- a/frontend/components/CellInput/go_to_definition_plugin.js +++ b/frontend/components/CellInput/go_to_definition_plugin.js @@ -1,723 +1,29 @@ -import { syntaxTree, Facet, ViewPlugin, Decoration, StateField, EditorView, EditorSelection, EditorState } from "../../imports/CodemirrorPlutoSetup.js" +import { Facet, ViewPlugin, Decoration, EditorView } from "../../imports/CodemirrorPlutoSetup.js" import { ctrl_or_cmd_name, has_ctrl_or_cmd_pressed } from "../../common/KeyboardShortcuts.js" import _ from "../../imports/lodash.js" +import { ScopeStateField } from "./scopestate_statefield.js" /** - * This function work bottom up: you give it an identifier, and it will look at it parents to figure out what it is... - * Ideally we use the top-down approach for everything, like we do in `explore_variable_usage`. + * @param {any} state + * @param {{ + * scopestate: import("./scopestate_statefield.js").ScopeState, + * global_definitions: { [key: string]: string } + * }} context */ -let node_is_variable_usage = (node) => { - let parent = node.parent - - if (parent == null) return false - if (parent.name === "VariableDeclarator") return false - if (parent.name === "Symbol") return false - - // If we are the first child of a FieldExpression, we are the usage - if (parent.name === "FieldExpression" || parent.name === "MacroFieldExpression") { - let firstchild = parent.firstChild - if (node.from === firstchild?.from && node.to === firstchild?.to) { - return true - } else { - return false - } - } - - // Ignore left side of an assigment - // TODO Tuple assignment - if (parent.name === "AssignmentExpression") { - let firstchild = parent?.firstChild - if (node.from === firstchild?.from && node.to === firstchild?.to) { - return false - } - } - - // If we are the name of a macro of function definition, we are not usage - if (parent.name === "MacroDefinition" || parent.name === "FunctionDefinition") { - let function_name = parent?.firstChild?.nextSibling - if (node.from === function_name?.from && node.to === function_name?.to) { - return false - } - } - - if (parent.name === "ArgumentList") { - if (parent.parent.name === "MacroDefinition" || parent.parent.name === "FunctionDefinition") { - return false - } - } - - if (parent.name === "TypedExpression") return node_is_variable_usage(parent) - if (parent.name === "NamedField") return node_is_variable_usage(parent) - if (parent.name === "BareTupleExpression") return node_is_variable_usage(parent) - if (parent.name === "MacroIdentifier") return node_is_variable_usage(parent) - - return true -} - -let empty_variables = [] - -/** - * @typedef Range - * @property {number} from - * @property {number} to - * - * @typedef ScopeState - * @property {Set<{ usage: Range, definition: Range? }>} usages - * @property {Map} definitions - */ - -/** - * @param {ScopeState} a - * @param {ScopeState} b - * @returns {ScopeState} - */ -let merge_scope_state = (a, b) => { - if (a === b) return a - - let usages = new Set([...a.usages, ...b.usages]) - let definitions = new Map(a.definitions) - for (let [key, value] of b.definitions) { - definitions.set(key, value) - } - return { usages, definitions } -} - -/** - * Clone scopestate - * @param {ScopeState} scopestate - * @returns {ScopeState} - */ -let clone_scope_state = (scopestate) => { - let usages = new Set(scopestate.usages) - let definitions = new Map(scopestate.definitions) - return { usages, definitions } -} - -/** - * @param {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} cursor - * @returns {Array} - */ -let get_variables_from_assignment = (cursor) => { - if (cursor.name === "Identifier") { - return [{ to: cursor.to, from: cursor.from }] - } - // `function f(x...)` => ["x"] - // `x... = 10` => ["x"] - if (cursor.name === "SpreadExpression") { - if (cursor.firstChild()) { - try { - return get_variables_from_assignment(cursor) - } finally { - cursor.parent() - } - } - } - // `function f(x = 10)` => ["x"] - // First need to go into NamedArgument, then need to go into NamedField. - if (cursor.name === "NamedArgument" || cursor.name === "NamedField") { - if (cursor.firstChild()) { - try { - return get_variables_from_assignment(cursor) - } finally { - cursor.parent() - } - } - } - // `function f(x::Any)` => ["x"] - // `x::Any = 10` => ["x"] - if (cursor.name === "TypedExpression") { - if (cursor.firstChild()) { - try { - return get_variables_from_assignment(cursor) - } finally { - cursor.parent() - } - } - } - // `function f( (x,y) )` => ["x", "y"] - // `(x, y) = arr` => ["x", "y"] - // `x,y = arr` => ["x", "y"] - if (cursor.name === "TupleExpression" || cursor.name === "BareTupleExpression") { - let variables = [] - if (cursor.firstChild()) { - do { - variables.push(...get_variables_from_assignment(cursor)) - } while (cursor.nextSibling()) - cursor.parent() - } - return variables - } - return [] -} - -let children = function* (cursor) { - if (cursor.firstChild()) { - try { - do { - yield cursor - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } -} - -let all_children = function* (cursor) { - for (let child of children(cursor)) { - yield* all_children(child) - } -} - -/** - * @param {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} cursor - */ -let go_through_quoted_expression_looking_for_interpolations = function* (cursor) { - if (cursor.name !== "QuoteExpression") throw new Error("Expected QuotedExpression") - - for (let child of all_children(cursor)) { - // @ts-ignore - if (child.name === "InterpolationExpression") { - yield cursor - } - } -} - -/** - * @param {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} cursor - * @param {any} doc - * @param {ScopeState} scopestate - * @returns {ScopeState} - */ -let explore_variable_usage = ( - cursor, - doc, - scopestate = { - usages: new Set(), - definitions: new Map(), - }, - verbose = false -) => { - let start_node = null - if (verbose) { - verbose && console.group(`Explorer: ${cursor.toString()}`) - verbose && console.log("Full text:", doc.sliceString(cursor.from, cursor.to)) - start_node = cursor.node - } - try { - if (cursor.name === "Symbol") { - // Nothing, ha! - } else if (cursor.name === "AbstractDefinition") { - // Also nothing! - } else if (cursor.name === "StructDefinition" && cursor.firstChild()) { - try { - // @ts-ignore - if (cursor.name === "mutable") cursor.nextSibling() - // @ts-ignore - if (cursor.name === "struct") cursor.nextSibling() - - // We're at the identifier (possibly ParameterizedIdentifier) - // @ts-ignore - if (cursor.name === "Identifier") { - let name = doc.sliceString(cursor.from, cursor.to) - scopestate.definitions.set(name, { - from: cursor.from, - to: cursor.to, - }) - cursor.nextSibling() - } - // @ts-ignore - if (cursor.name === "ParameterizedIdentifier" && cursor.firstChild()) { - try { - let name = doc.sliceString(cursor.from, cursor.to) - scopestate.definitions.set(name, { - from: cursor.from, - to: cursor.to, - }) - - cursor.nextSibling() // Typed part - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } finally { - cursor.parent() - } - cursor.nextSibling() - } - - // @ts-ignore - if (cursor.name === "TypedExpression" && cursor.node.getChildren("Identifier").length === 1) { - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - cursor.nextSibling() - } - - // We are now in the actual struct body - do { - // @ts-ignore - if (cursor.name === "Identifier") { - // Nothing, this is just the name inside the struct blegh get it out of here - } - // @ts-ignore - if (cursor.name === "TypedExpression") { - // We're in X::Y, and Y is a reference - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor.node.lastChild.cursor, doc, scopestate)) - } - // I'm not so sure about this - // @ts-ignore - if (cursor.name === "AssignmentExpression" && cursor.firstChild()) { - try { - if (cursor.name === "Identifier") { - // Nothing, this is just the name inside the struct blegh get it out of here - } - if (cursor.name === "TypedExpression") { - // We're in X::Y, and Y is a reference - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor.node.lastChild.cursor, doc, scopestate)) - } - - cursor.nextSibling() - cursor.nextSibling() - - // We're in X::Y, and Y is a reference - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } finally { - cursor.parent() - } - } - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } else if (cursor.name === "QuoteExpression") { - for (let interpolation_cursor of go_through_quoted_expression_looking_for_interpolations(cursor)) { - scopestate = merge_scope_state(scopestate, explore_variable_usage(interpolation_cursor, doc, scopestate)) - } - verbose && console.log("Interpolating over") - } else if (cursor.name === "ModuleDefinition" && cursor.firstChild()) { - // Ugh.. - try { - // First child is "module", next child is the name - cursor.nextSibling() - let name = doc.sliceString(cursor.from, cursor.to) - scopestate.definitions.set(name, { - from: cursor.from, - to: cursor.to, - }) - - // Next children are the body - // These have a new scope, not even escaping definitions - /** @type {ScopeState} */ - let module_scopestate = { - usages: new Set(), - definitions: new Map(), - } - while (cursor.nextSibling()) { - module_scopestate = merge_scope_state(module_scopestate, explore_variable_usage(cursor, doc, module_scopestate)) - } - // We still merge the module scopestate with the global scopestate, but only the usages that don't escape. - // (Later we can have also shadowed definitions for the dimming of unused variables) - scopestate = merge_scope_state(scopestate, { - usages: new Set(Array.from(module_scopestate.usages).filter((x) => x.definition != null)), - definitions: new Map(), - }) - } finally { - cursor.parent() - } - } else if (cursor.name === "ExportStatement" && cursor.firstChild()) { - try { - // @ts-ignore - if (cursor.name === "export") cursor.nextSibling() - do { - // @ts-ignore - if (cursor.name === "Identifier") { - // Because lezer-julia isn't smart enough yet, we have to check if this is a macro - // by plainly checking if there is an @ in front of the identifier :P - let name_with_possibly_an_at = doc.sliceString(cursor.from - 1, cursor.to) - if (name_with_possibly_an_at[0] !== "@") { - name_with_possibly_an_at = name_with_possibly_an_at.slice(1) - } - scopestate.usages.add({ - usage: { - from: cursor.to - name_with_possibly_an_at.length, - to: cursor.to, - }, - definition: scopestate.definitions.get(name_with_possibly_an_at) ?? null, - }) - } - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } else if (cursor.name === "CompoundExpression" && cursor.firstChild()) { - // begin ... end, go through all the children one by one and keep adding their definitions - try { - do { - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } else if (cursor.name === "ImportStatement" && cursor.firstChild()) { - try { - // let is_using = cursor.name === "using" - cursor.nextSibling() - - // @ts-ignore - if (cursor.name === "Import" && cursor.firstChild()) { - do { - let node = cursor.node - if (cursor.name === "Identifier") { - // node = node 🤷‍♀️ - } - if (cursor.name === "RenamedIdentifier") { - node = node.lastChild - } - - let name = doc.sliceString(node.from, node.to) - scopestate.definitions.set(name, { - from: cursor.from, - to: cursor.to, - }) - } while (cursor.nextSibling()) - cursor.parent() - } - - // @ts-ignore - if (cursor.name === "SelectedImport") { - // First child is the module we are importing from, so we skip to the next child - for (let child of children(cursor)) { - let node = cursor.node - if (cursor.name === "Identifier") { - // node = node 🤷‍♀️ - } - if (cursor.name === "RenamedImport") { - node = node.lastChild - } - let name = doc.sliceString(node.from, node.to) - scopestate.definitions.set(name, { - from: cursor.from, - to: cursor.to, - }) - } - } - } finally { - cursor.parent() - } - } else if (cursor.name === "ForStatement" && cursor.firstChild()) { - try { - let nested_scope = { - usages: new Set(), - definitions: new Map(scopestate.definitions), - } - - // @ts-ignore - if (cursor.name === "for") { - cursor.nextSibling() - } - - // @ts-ignore - if (cursor.name === "ForBinding" && cursor.firstChild()) { - try { - for (let variable_node of get_variables_from_assignment(cursor)) { - let name = doc.sliceString(variable_node.from, variable_node.to) - nested_scope.definitions.set(name, { - from: variable_node.from, - to: variable_node.to, - }) - } - cursor.nextSibling() - - // @ts-ignore - if (cursor.name === "in") { - cursor.nextSibling() - } - - // Right hand side of `for ... in ...` - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } finally { - cursor.parent() - } - } - - cursor.nextSibling() - - // Go through the expressions in the for body - do { - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - - scopestate = { - usages: new Set([...scopestate.usages, ...nested_scope.usages]), - definitions: scopestate.definitions, - } - } finally { - cursor.parent() - } - } else if (cursor.name === "DoClause" && cursor.firstChild()) { - try { - // It's not yet possible to be SURE that we have the arguments, because of the way @lezer/julia works... - // But imma do my best, and soon contribute to @lezer/julia - - cursor.nextSibling() // We are now supposed to be in the argumentlist.. - // Problem is: we might also be in the first statement of the function... - // So we'll make sure that we have something that is valid as arguments, - // but then still someone MIGHT have a plain identifier in the first statement. - - let nested_scope = { - usages: new Set(), - definitions: new Map(scopestate.definitions), - } - for (let variable_node of get_variables_from_assignment(cursor)) { - let name = doc.sliceString(variable_node.from, variable_node.to) - nested_scope.definitions.set(name, { - from: variable_node.from, - to: variable_node.to, - }) - } - - cursor.nextSibling() - - do { - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - - scopestate = { - usages: new Set([...scopestate.usages, ...nested_scope.usages]), - definitions: scopestate.definitions, - } - } finally { - cursor.parent() - } - } else if (cursor.name === "FunctionDefinition" || cursor.name === "MacroDefinition") { - let full_node = cursor.node - if (cursor.firstChild()) { - // Two things - // 1. Add the function name to the current scope - // 2. Go through the function in a nested scope - - try { - // @ts-ignore - // If we are at "function", skip it - if (cursor.name === "function") { - cursor.nextSibling() - } - let in_macro = false - // @ts-ignore - // If we are at "function", skip it - if (cursor.name === "macro") { - in_macro = true // So we add `@` to the name - cursor.nextSibling() - } - // @ts-ignore - // Function name, add to current scope - if (cursor.name === "Identifier") { - let name = doc.sliceString(cursor.from, cursor.to) - if (in_macro) { - name = `@${name}` - } - // Add the full node as position, so it selects the whole thing - // scopestate.definitions.set(name, { from: full_node.from, to: full_node.to }) - scopestate.definitions.set(name, { from: cursor.from, to: cursor.to }) - cursor.nextSibling() - } - - let nested_scope = { - usages: new Set(), - definitions: new Map(scopestate.definitions), - } - // @ts-ignore - // Cycle through arguments - if (cursor.name === "ArgumentList" && cursor.firstChild()) { - try { - do { - // I tried doing this the way it is, but lezer-julia isn't there yet. - // It is too hard (and not worth it) to do it the way it is now. - // So we only take simple identifiers, and we don't care about the rest. - for (let variable_node of get_variables_from_assignment(cursor)) { - let name = doc.sliceString(variable_node.from, variable_node.to) - nested_scope.definitions.set(name, { - from: variable_node.from, - to: variable_node.to, - }) - } - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } - - cursor.nextSibling() - - do { - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - - scopestate = { - usages: new Set([...scopestate.usages, ...nested_scope.usages]), - definitions: scopestate.definitions, - } - } finally { - cursor.parent() - } - } - } else if (cursor.name === "LetStatement" && cursor.firstChild()) { - try { - let nested_scope = { - usages: new Set(), - definitions: new Map(scopestate.definitions), - } - do { - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - scopestate = { - usages: new Set([...scopestate.usages, ...nested_scope.usages]), - definitions: scopestate.definitions, - } - } finally { - cursor.parent() - } - } else if (cursor.name === "VariableDeclaration" || cursor.name === "AssignmentExpression") { - if (cursor.firstChild()) { - try { - for (let variable_node of get_variables_from_assignment(cursor)) { - let name = doc.sliceString(variable_node.from, variable_node.to) - scopestate.definitions.set(name, { - from: variable_node.from, - to: variable_node.to, - }) - } - // explore the right-hand side of the assignment - if (cursor.nextSibling()) { - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } - } finally { - cursor.parent() - } - } - } else if (cursor.name === "Identifier" || cursor.name === "MacroIdentifier") { - if (node_is_variable_usage(cursor.node)) { - let name = doc.sliceString(cursor.from, cursor.to) - if (scopestate.definitions.has(name)) { - scopestate.usages.add({ - usage: { - from: cursor.from, - to: cursor.to, - }, - definition: scopestate.definitions.get(name), - }) - } else { - scopestate.usages.add({ - usage: { - from: cursor.from, - to: cursor.to, - }, - definition: null, - }) - } - } - } else if (cursor.name === "ForClause" || cursor.name === "IfClause") { - // Nothing, this should be handled by ArrayComprehensionExpression - } else if (cursor.name === "ArrayComprehensionExpression" || cursor.name === "GeneratorExpression") { - let node = cursor.node - let for_binding = node.getChild("ForClause")?.getChild("ForBinding") - let binding = for_binding?.firstChild - let from = for_binding?.lastChild - let if_clause = node.getChild("IfClause") - - // Because of the weird way this is parsed, we need `sort = true` in the Decorations.set below - - if (binding != null || from != null) { - // Get usage for the generator - scopestate = merge_scope_state(scopestate, explore_variable_usage(from.cursor, doc, scopestate)) - - let nested_scope = { - usages: new Set(), - definitions: new Map(scopestate.definitions), - } - - // Add definition from the binding - for (let variable_node of get_variables_from_assignment(binding.cursor)) { - let name = doc.sliceString(variable_node.from, variable_node.to) - nested_scope.definitions.set(name, { - from: variable_node.from, - to: variable_node.to, - }) - } - - if (if_clause != null) { - do { - let if_clause_cursor = if_clause.cursor - if_clause_cursor.lastChild() - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(if_clause_cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - } - - if (cursor.firstChild()) { - try { - do { - nested_scope = merge_scope_state(nested_scope, explore_variable_usage(cursor, doc, nested_scope)) - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } - - scopestate = { - usages: new Set([...scopestate.usages, ...nested_scope.usages]), - definitions: scopestate.definitions, - } - } - - // cursor.nextSibling() - // // @ts-ignore - // if (cursor.name === "ForClause" && cursor.firstChild()) { - // do { - // if (cursor.name === "ForBinding" && cursor.firstChild()) { - // local_variables.push(...get_variables_from_assignment(cursor)) - // cursor.parent() - // } - // } while (cursor.nextSibling()) - // cursor.parent() - // } - } else { - // In most cases we "just" go through all the children separately - if (cursor.firstChild()) { - try { - do { - scopestate = merge_scope_state(scopestate, explore_variable_usage(cursor, doc, scopestate)) - } while (cursor.nextSibling()) - } finally { - cursor.parent() - } - } - } - - if (verbose) { - if (cursor.from !== start_node.from || cursor.to !== start_node.to) { - console.log(`start_node:`, start_node.toString(), doc.sliceString(start_node.from, start_node.to)) - console.log(`cursor:`, cursor.toString(), doc.sliceString(cursor.from, cursor.to)) - throw new Error("Cursor is at a different node at the end of explore_variable_usage :O") - } - } - - return scopestate - } finally { - verbose && console.groupEnd() - } -} - -let get_variable_marks = (state, { scopestate, used_variables }) => { +let get_variable_marks = (state, { scopestate, global_definitions }) => { return Decoration.set( - Array.from(scopestate.usages) - .map(({ definition, usage }) => { - let text = state.doc.sliceString(usage.from, usage.to) - + filter_non_null( + scopestate.usages.map(({ definition, usage, name }) => { if (definition == null) { // TODO variables_with_origin_cell should be notebook wide, not just in the current cell // .... Because now it will only show variables after it has run once - if (used_variables[text]) { + if (global_definitions[name]) { return Decoration.mark({ tagName: "a", attributes: { - "title": `${ctrl_or_cmd_name}-Click to jump to the definition of ${text}.`, - "data-pluto-variable": text, - "href": `#${text}`, + "title": `${ctrl_or_cmd_name}-Click to jump to the definition of ${name}.`, + "data-pluto-variable": name, + "href": `#${name}`, }, }).range(usage.from, usage.to) } else { @@ -738,45 +44,34 @@ let get_variable_marks = (state, { scopestate, used_variables }) => { return Decoration.mark({ tagName: "a", attributes: { - "title": `${ctrl_or_cmd_name}-Click to jump to the definition of ${text}.`, - "data-cell-variable": text, + "title": `${ctrl_or_cmd_name}-Click to jump to the definition of ${name}.`, + "data-cell-variable": name, "data-cell-variable-from": `${definition.from}`, "data-cell-variable-to": `${definition.to}`, "href": `#`, }, }).range(usage.from, usage.to) - return null } }) - .filter((x) => x != null), + ), true ) } -export const UsedVariablesFacet = Facet.define({ - combine: (values) => values[0], - compare: _.isEqual, -}) - /** - * @type {StateField} + * + * @argument {Array} xs + * @template T + * @return {Array} */ -export let ScopeStateField = StateField.define({ - create(state) { - let cursor = syntaxTree(state).cursor() - let scopestate = explore_variable_usage(cursor, state.doc) - return scopestate - }, +const filter_non_null = (xs) => /** @type {Array} */ (xs.filter((x) => x != null)) - update(value, tr) { - if (tr.docChanged) { - let cursor = syntaxTree(tr.state).cursor() - let scopestate = explore_variable_usage(cursor, tr.state.doc) - return scopestate - } else { - return value - } - }, +/** + * @type {Facet<{ [variable_name: string]: string }, { [variable_name: string]: string }>} + */ +export const GlobalDefinitionsFacet = Facet.define({ + combine: (values) => values[0], + compare: _.isEqual, }) export const go_to_definition_plugin = ViewPlugin.fromClass( @@ -785,20 +80,20 @@ export const go_to_definition_plugin = ViewPlugin.fromClass( * @param {EditorView} view */ constructor(view) { - let used_variables = view.state.facet(UsedVariablesFacet) + let global_definitions = view.state.facet(GlobalDefinitionsFacet) this.decorations = get_variable_marks(view.state, { scopestate: view.state.field(ScopeStateField), - used_variables, + global_definitions, }) } update(update) { - // My best take on getting this to update when UsedVariablesFacet does 🤷‍♀️ - let used_variables = update.state.facet(UsedVariablesFacet) - if (update.docChanged || update.viewportChanged || used_variables !== update.startState.facet(UsedVariablesFacet)) { + // My best take on getting this to update when GlobalDefinitionsFacet does 🤷‍♀️ + let global_definitions = update.state.facet(GlobalDefinitionsFacet) + if (update.docChanged || update.viewportChanged || global_definitions !== update.startState.facet(GlobalDefinitionsFacet)) { this.decorations = get_variable_marks(update.state, { scopestate: update.state.field(ScopeStateField), - used_variables, + global_definitions, }) } } @@ -807,15 +102,22 @@ export const go_to_definition_plugin = ViewPlugin.fromClass( decorations: (v) => v.decorations, eventHandlers: { - pointerdown: (event, view) => { - if (has_ctrl_or_cmd_pressed(event) && event.button === 0 && event.target instanceof Element) { + click: (event, view) => { + if (event.target instanceof Element) { let pluto_variable = event.target.closest("[data-pluto-variable]") if (pluto_variable) { let variable = pluto_variable.getAttribute("data-pluto-variable") + if (variable == null) { + return false + } + + if (!(has_ctrl_or_cmd_pressed(event) || view.state.readOnly)) { + return false + } event.preventDefault() let scrollto_selector = `[id='${encodeURI(variable)}']` - document.querySelector(scrollto_selector).scrollIntoView({ + document.querySelector(scrollto_selector)?.scrollIntoView({ behavior: "smooth", block: "center", }) @@ -825,15 +127,15 @@ export const go_to_definition_plugin = ViewPlugin.fromClass( // window.history.replaceState({ scrollTop: document.documentElement.scrollTop }, null) // window.history.pushState({ scrollTo: scrollto_selector }, null) - let used_variables = view.state.facet(UsedVariablesFacet) + let global_definitions = view.state.facet(GlobalDefinitionsFacet) // TODO Something fancy where we actually emit the identifier we are looking for, // .... and the cell then selects exactly that definition (using lezer and cool stuff) - if (used_variables[variable]) { + if (global_definitions[variable]) { window.dispatchEvent( new CustomEvent("cell_focus", { detail: { - cell_id: used_variables[variable], + cell_id: global_definitions[variable], line: 0, // 1-based to 0-based index definition_of: variable, }, @@ -849,7 +151,18 @@ export const go_to_definition_plugin = ViewPlugin.fromClass( let variable_from = Number(cell_variable.getAttribute("data-cell-variable-from")) let variable_to = Number(cell_variable.getAttribute("data-cell-variable-to")) + if (variable_name == null || variable_from == null || variable_to == null) { + return false + } + + if (!(has_ctrl_or_cmd_pressed(event) || view.state.readOnly)) { + return false + } + + event.preventDefault() + view.dispatch({ + scrollIntoView: true, selection: { anchor: variable_from, head: variable_to }, }) view.focus() diff --git a/frontend/components/CellInput/highlight_line.js b/frontend/components/CellInput/highlight_line.js new file mode 100644 index 0000000000..d5938350d4 --- /dev/null +++ b/frontend/components/CellInput/highlight_line.js @@ -0,0 +1,113 @@ +import { Decoration, ViewPlugin, EditorView, Facet, ViewUpdate } from "../../imports/CodemirrorPlutoSetup.js" + +const highlighted_line = Decoration.line({ + attributes: { class: "cm-highlighted-line" }, +}) + +const highlighted_range = Decoration.mark({ + attributes: { class: "cm-highlighted-range" }, +}) + +/** + * @param {EditorView} view + */ +function create_line_decorations(view) { + let line_number = view.state.facet(HighlightLineFacet) + if (line_number == null || line_number == undefined || line_number < 0 || line_number > view.state.doc.lines) { + return Decoration.set([]) + } + + let line = view.state.doc.line(line_number) + return Decoration.set([highlighted_line.range(line.from, line.from)]) +} + +/** + * @param {EditorView} view + */ +function create_range_decorations(view) { + let range = view.state.facet(HighlightRangeFacet) + if (range == null) { + return Decoration.set([]) + } + let { from, to } = range + if (from < 0 || from == to) { + return Decoration.set([]) + } + + return Decoration.set([highlighted_range.range(from, to)]) +} + +/** + * @type Facet + */ +export const HighlightLineFacet = Facet.define({ + combine: (values) => values[0], + compare: (a, b) => a === b, +}) + +/** + * @type Facet<{from: number, to: number}?, {from: number, to: number}?> + */ +export const HighlightRangeFacet = Facet.define({ + combine: (values) => values[0], + compare: (a, b) => a === b, +}) + +export const highlightLinePlugin = () => + ViewPlugin.fromClass( + class { + updateDecos(view) { + this.decorations = create_line_decorations(view) + } + + /** + * @param {EditorView} view + */ + constructor(view) { + this.decorations = Decoration.set([]) + this.updateDecos(view) + } + + /** + * @param {ViewUpdate} update + */ + update(update) { + if (update.docChanged || update.state.facet(HighlightLineFacet) !== update.startState.facet(HighlightLineFacet)) { + this.updateDecos(update.view) + } + } + }, + { + decorations: (v) => v.decorations, + } + ) + + +export const highlightRangePlugin = () => + ViewPlugin.fromClass( + class { + updateDecos(view) { + this.decorations = create_range_decorations(view) + } + + /** + * @param {EditorView} view + */ + constructor(view) { + this.decorations = Decoration.set([]) + this.updateDecos(view) + } + + /** + * @param {ViewUpdate} update + */ + update(update) { + if (update.docChanged || update.state.facet(HighlightRangeFacet) !== update.startState.facet(HighlightRangeFacet)) { + this.updateDecos(update.view) + } + } + }, + { + decorations: (v) => v.decorations, + } + ) diff --git a/frontend/components/CellInput/lezer_template.js b/frontend/components/CellInput/lezer_template.js new file mode 100644 index 0000000000..c034642452 --- /dev/null +++ b/frontend/components/CellInput/lezer_template.js @@ -0,0 +1,1089 @@ +import { julia_andrey, NodeProp, syntaxTree, Text } from "../../imports/CodemirrorPlutoSetup.js" +import lodash from "../../imports/lodash.js" + +// @ts-ignore +import ManyKeysWeakMap from "https://esm.sh/many-keys-weakmap@1.0.0?pin=v113&target=es2020" + +/** + * @param {string} julia_code + * @returns {SyntaxNode} + */ +export let julia_to_ast = (julia_code) => { + return /** @type {any} */ (julia_andrey().language.parser.parse(julia_code).topNode.firstChild) +} + +// When you get errors while creating the templates (stuff related to substitutions), +// turn this on, and you will get a lot of info you can debug with! +const TEMPLATE_CREATION_VERBOSE = false + +/** + * Settings this to `"VALIDITY"` will enable some (currently, one) slow validations. + * Might be useful to run set this to `"VALIDITY"` every so often to make sure there are no bugs. + * In production this should always to `"SPEED"` + * + * @type {"SPEED" | "VALIDITY"} + */ +const PERFORMANCE_MODE = /** @type {any} */ ("SPEED") + +const IS_IN_VALIDATION_MODE = PERFORMANCE_MODE === "VALIDITY" + +/** + * @template {Array} P + * @template {(...args: P) => any} T + * @param {T} fn + * @param {(...args: P) => any} cachekey_resolver + * @param {WeakMap} cache + * @returns {T} + */ +let memo = (fn, cachekey_resolver = /** @type {any} */ ((x) => x), cache = new Map()) => { + return /** @type {any} */ ( + (/** @type {P} */ ...args) => { + let cachekey = cachekey_resolver(...args) + let result = cache.get(cachekey) + if (result != null) { + return result + } else { + let result = fn(...args) + + if (result == undefined) { + throw new Error("Memoized function returned undefined") + } + cache.set(cachekey, result) + return result + } + } + ) +} + +/** + * @template {(...args: any) => any} T + * @param {T} fn + * @param {(...x: Parameters) => Array} cachekey_resolver + * @returns {T} + */ +let weak_memo = (fn, cachekey_resolver = (...x) => x) => memo(fn, cachekey_resolver, new ManyKeysWeakMap()) + +/** + * @template {(arg: any) => any} T + * @param {T} fn + * @returns {T} + */ +let weak_memo1 = (fn) => memo(fn, (x) => x, new WeakMap()) + +// Good luck figuring anything out from these types 💕 + +/** + * @typedef TreeCursor + * @type {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} + * + * @typedef SyntaxNode + * @type {TreeCursor["node"]} + */ + +/** + * @typedef LezerOffsetNode + * @type {{ + * name: string, + * from: number, + * to: number, + * node: SyntaxNode, + * }} + */ + +/** + * @typedef TemplateGenerator + * @type {Generator} + */ + +/** + * @typedef Substitution + * @type {() => TemplateGenerator} + */ + +/** + * @typedef Templatable + * @type {JuliaCodeObject | Substitution} + */ + +/** + * @typedef MatchResult + * @type {any} + */ + +/** + * @typedef Matcher + * @type {{ + * match: (haystack_cursor: TreeCursor | SyntaxNode, verbose?: boolean) => void | { [key: string]: MatchResult } + * }} + */ + +/** @param {TreeCursor} cursor */ +export let child_cursors = function* (cursor) { + if (cursor.firstChild()) { + try { + do { + yield cursor + } while (cursor.nextSibling()) + } finally { + cursor.parent() + } + } +} + +/** @param {SyntaxNode} node */ +export let child_nodes = function* (node) { + if (node.firstChild) { + /** @type {SyntaxNode?} */ + let child = node.firstChild + do { + yield child + } while ((child = child.nextSibling)) + } +} + +/** + * @typedef AstTemplate + * @type {{ + * name?: string, + * from?: number, + * to?: number, + * node: SyntaxNode, + * children: Array, + * } | { + * pattern: ( + * haystack: (TreeCursor | null), + * matches: { [key: string]: any }, + * verbose?: boolean + * ) => boolean, + * }} + */ + +/** + * @param {TreeCursor | null} haystack_cursor + * @param {AstTemplate} template + * @param {{ [name: string]: any }} matches + * @param {boolean} verbose + */ +export let match_template = (haystack_cursor, template, matches, verbose = false) => { + if (verbose) { + console.group("Current haystack:", !haystack_cursor ? null : haystack_cursor.node.name) + + console.groupCollapsed("Details") + try { + console.log(`template:`, template) + console.log(`haystack_cursor:`, !haystack_cursor ? null : haystack_cursor.node.toString()) + + if ("node" in template) { + console.log(`template.node:`, template.node) + console.log(`template.node.toString():`, template.node.toString()) + } else if ("pattern" in template) { + console.log(`template.pattern:`, template.pattern) + } + } finally { + console.groupEnd() + } + } + + try { + if ("pattern" in template) { + let pattern = template.pattern + if (typeof pattern !== "function") { + throw new Error(`Unknown pattern "${pattern}"`) + } + + let matches_before_matching = {} + if (verbose) { + matches_before_matching = { ...matches } + console.groupCollapsed(`Matching against pattern: ${template.pattern.name}()`) + } + + let did_match = null + try { + did_match = pattern(haystack_cursor, matches, verbose) + } finally { + if (verbose) { + console.groupEnd() + } + } + if (verbose) { + if (did_match) { + console.log(`✅ because the pattern was happy! All hail the pattern!`) + if (!lodash.isEqual(matches, matches_before_matching)) { + let new_matches = lodash.omit(matches, Object.keys(matches_before_matching)) + console.log(` WE EVEN GOT NEW MATCHES SAY WHAAAAAAT:`, new_matches) + } + } else { + console.log(`❌ because... well, you should ask the pattern that!`) + } + } + + return did_match + } else if ("node" in template) { + let { node, children } = template + + verbose && console.log(`Matching against node: ${template.node.name}`) + + if (!haystack_cursor) { + if (node.name === "end") { + verbose && console.log(`✅ No node left to match, but it was the end anyway`) + return true + } + verbose && console.log(`❌ because no cursor left to match against`) + return false + } + + if (haystack_cursor.type.isError) { + // Not sure about this yet but ehhhh + verbose && console.log(`✅ because ⚠`) + return true + } + + if (haystack_cursor.name !== node.name) { + verbose && console.log(`❌ because name mismatch "${haystack_cursor.name}" !== "${node.name}"`) + return false + } + + if (haystack_cursor.firstChild()) { + try { + let is_last_from_haystack = false + for (let template_child of children) { + if (is_last_from_haystack) { + verbose && console.log(`Haystack is empty, but there are more children in template... lets see`) + let child_does_match = match_template(null, template_child, matches, verbose) + if (!child_does_match) { + verbose && console.log(`❌ template child did not accept null for an answer`, template_child, haystack_cursor.toString()) + return false + } + verbose && console.log(`👌🏽 This template child was fine with null`) + continue + } + + // Skip comments + // TODO This is, I think, one of the few julia-only things right now..... + // .... Any sane way to factor this out? + while (haystack_cursor.name === "Comment" || haystack_cursor.name === "BlockComment") { + if (!haystack_cursor.nextSibling()) break + } + + let child_does_match = match_template(haystack_cursor, template_child, matches, verbose) + + if (!child_does_match) { + verbose && console.log(`❌ because a child mismatch`, template_child, haystack_cursor.toString()) + return false + } + + // This is where we actually move the haystack_cursor (in sync with the `template.children`) + // to give the nested match templates more freedom in move the cursor around between siblings. + is_last_from_haystack = !haystack_cursor.nextSibling() + } + + if (verbose && !is_last_from_haystack) { + let spare_children = [] + do { + spare_children.push(haystack_cursor.node) + } while (haystack_cursor.nextSibling()) + for (let child of spare_children) { + haystack_cursor.prevSibling() + } + + // prettier-ignore + console.warn("We did match all the children of the template, but there are more in the haystack... Might want to actually not match this?", spare_children, template) + } + + verbose && console.log(`✅ because all children match`) + return true + } finally { + haystack_cursor.parent() + } + } else { + if (template.children.length !== 0) { + verbose && console.log(`Haystack node is empty, but template has children... lets see`) + + for (let child of template.children) { + if (!match_template(null, child, matches, verbose)) { + verbose && console.log(`❌ because child template wasn't okay with having no children`, child) + return false + } + } + verbose && console.log(`✅ All template children we're fine with having no children to check on`) + return true + } else { + verbose && console.log(`✅ Template also has no children, yayyy`) + return true + } + } + } else { + console.log(`template:`, template) + throw new Error("waaaah") + } + } finally { + if (verbose) { + console.groupEnd() + } + } +} + +export class JuliaCodeObject { + /** + * @param {TemplateStringsArray} template + * @param {any[]} substitutions + * */ + constructor(template, substitutions) { + let flattened_template = [] + let flattened_substitutions = [] + + flattened_template.push(template[0]) + for (let [string_part, substitution] of lodash.zip(template.slice(1), substitutions)) { + if (substitution instanceof JuliaCodeObject) { + flattened_template[flattened_template.length - 1] += substitution.template[0] + for (let [sub_string_part, sub_substitution] of lodash.zip(substitution.template.slice(1), substitution.substitutions)) { + flattened_substitutions.push(sub_substitution) + flattened_template.push(sub_string_part) + } + flattened_template[flattened_template.length - 1] += string_part + } else { + flattened_substitutions.push(substitution) + flattened_template.push(string_part) + } + } + + this.template = flattened_template + this.substitutions = flattened_substitutions + } +} + +/** + * @param {SyntaxNode} ast + * @param {Array<{ generator: TemplateGenerator, from: number, to: number, used?: boolean }>} substitutions + * @returns {AstTemplate} + */ +let substitutions_to_template = (ast, substitutions) => { + for (let substitution of substitutions) { + if (ast.from === substitution.from && ast.to === substitution.to) { + // Hacky and weird, but it is only for validation + substitution.used = true + let result = substitution.generator.next({ + name: ast.name, + from: ast.from, + to: ast.to, + node: ast, + }) + + if (result.done) { + return result.value + } else { + throw new Error("Template generator not done providing ast node") + } + } + } + + return { + name: ast.name, + from: ast.from, + to: ast.to, + children: Array.from(child_nodes(ast)).map((node) => substitutions_to_template(node, substitutions)), + node: ast, + } +} + +let node_to_explorable = (cursor) => { + if ("cursor" in cursor) { + cursor = cursor.cursor() + } + + let children = [] + if (cursor.firstChild()) { + try { + do { + children.push(node_to_explorable(cursor)) + } while (cursor.nextSibling()) + } finally { + cursor.parent() + } + } + return { + name: cursor.name, + from: cursor.from, + to: cursor.to, + children, + } +} + +/** + * @param {Templatable} julia_code_object + * @returns {TemplateGenerator} + */ +export let to_template = function* (julia_code_object) { + TEMPLATE_CREATION_VERBOSE && console.group(`to_template(`, typeof julia_code_object === "function" ? julia_code_object.name + "()" : julia_code_object, `)`) + try { + if (julia_code_object instanceof JuliaCodeObject) { + let julia_code_to_parse = "" + + let subsitions = [] + for (let [string_part, substitution] of lodash.zip(julia_code_object.template, julia_code_object.substitutions)) { + julia_code_to_parse += string_part + + if (substitution) { + let substitution_generator = to_template(substitution) + + let substitution_code = intermediate_value(substitution_generator.next()) + + subsitions.push({ + from: julia_code_to_parse.length, + to: julia_code_to_parse.length + substitution_code.length, + generator: substitution_generator, + }) + julia_code_to_parse += substitution_code + } + } + + let template_node = yield julia_code_to_parse + + let substitution_with_proper_position = subsitions.map((substitution) => { + return { + from: substitution.from + template_node.from, + to: substitution.to + template_node.from, + generator: substitution.generator, + used: false, + } + }) + + if (TEMPLATE_CREATION_VERBOSE) { + console.log(`julia_code_to_parse:`, julia_code_to_parse) + console.log(`template_node:`, node_to_explorable(template_node.node.cursor())) + console.log(`subsitions:`, subsitions) + console.log(`substitution_with_proper_position:`, substitution_with_proper_position) + } + + let result = substitutions_to_template(template_node.node, substitution_with_proper_position) + let unused_substitutions = substitution_with_proper_position + .filter((substitution) => !substitution.used) + .map((x) => { + return { + text: julia_code_to_parse.slice(x.from, x.to), + from: x.from, + to: x.to, + } + }) + if (unused_substitutions.length > 0) { + throw new Error(`Some substitutions not applied, this means it couldn't be matched to a AST position: ${JSON.stringify(unused_substitutions)}`) + } + return result + } else if (typeof julia_code_object === "function") { + return yield* julia_code_object() + } else { + console.log(`julia_code_object:`, julia_code_object) + throw new Error("Unknown substition type") + } + } finally { + TEMPLATE_CREATION_VERBOSE && console.groupEnd() + } +} + +/** + * @param {TemplateStringsArray} template + * @param {any[]} substitutions + * */ +export let jl_dynamic = weak_memo((template, ...substitutions) => { + return new JuliaCodeObject(template, substitutions) +}) + +/** @type {WeakMap, result: JuliaCodeObject }>} */ +let template_cache = new WeakMap() +/** + * @param {TemplateStringsArray} template + * @param {Array} substitutions + */ +export let jl = (template, ...substitutions) => { + let cached = template_cache.get(template) + if (cached != null) { + let { input, result } = cached + if (IS_IN_VALIDATION_MODE) { + if (!lodash.isEqual(substitutions, input)) { + console.trace("Substitutions changed on `jl` template string.. change to `jl_dynamic` if you need this.") + } + } + return result + } else { + // Uncomment this if you want to check if the cache is working + // console.log("Creating template for", template, substitutions) + let result = new JuliaCodeObject(template, substitutions) + template_cache.set(template, { + input: substitutions, + result: result, + }) + return result + } +} + +/** + * Turns a ``` jl`` ``` (or substitution) into a template with a `.match(cursor)` method. + * + * @type {(code: Templatable) => Matcher} + */ +export let template = weak_memo1((julia_code_object) => { + let template_generator = to_template(julia_code_object) + let julia_to_parse = intermediate_value(template_generator.next()) + let template_ast = julia_to_ast(julia_to_parse) + + let template_description = return_value( + template_generator.next({ + from: 0, + to: julia_to_parse.length, + name: template_ast.name, + node: /** @type {any} */ (template_ast), + }) + ) + + return /** @type {Matcher} */ ({ + /** + * @param {TreeCursor | SyntaxNode} haystack_cursor + * @param {boolean} verbose? + **/ + template_description, + match(haystack_cursor, verbose = false) { + // Performance gain for not converting to `TreeCursor` possibly 🤷‍♀️ + if ("node" in template_description && template_description.node.name !== haystack_cursor.name) return + if (haystack_cursor.type.isError) return null + + if ("cursor" in haystack_cursor) haystack_cursor = haystack_cursor.cursor() + + let matches = /** @type {{ [key: string]: MatchResult }} */ ({}) + + verbose && console.groupCollapsed(`Starting a match at ${haystack_cursor.name}`) + try { + return match_template(haystack_cursor, template_description, matches, verbose) ? matches : null + } finally { + verbose && console.groupEnd() + } + }, + }) +}) + +export let as_string = weak_memo1((/** @type {JuliaCodeObject} */ julia_code_object) => { + let template_generator = to_template(julia_code_object) + let julia_to_parse = intermediate_value(template_generator.next()) + // @ts-ignore + template_generator.return() + return julia_to_parse +}) + +export let as_node = weak_memo1((/** @type {JuliaCodeObject} */ julia_code_object) => { + return julia_to_ast(as_string(julia_code_object)) +}) + +export let as_doc = weak_memo1((/** @type {JuliaCodeObject} */ julia_code_object) => { + return Text.of([as_string(julia_code_object)]) +}) + +/** + * @template {(name: string, other_arg: Object) => any} T + * @param {T} func + * @returns {T} + **/ +let memo_first_argument_weakmemo_second = (func) => { + let fake_weakmap_no_arg = {} + let per_name_memo = memo((name) => { + return weak_memo1((arg) => { + if (arg === fake_weakmap_no_arg) return func(name, undefined) + return func(name, arg) + }) + }) + + return /** @type {T} */ ( + (name, arg = fake_weakmap_no_arg) => { + let sub_memo = per_name_memo(name) + return sub_memo(arg) + } + ) +} + +/** @type {Substitution} */ +function* any() { + yield "expression" + return { + pattern: function expression(cursor, matches, verbose = false) { + if (!cursor) { + verbose && console.log("❌ I want anything!! YOU GIVE ME NULL???") + return false + } + if (cursor.type.is("keyword")) { + verbose && console.log("❌ Keywords are not allowed!") + return false + } + return true + }, + } +} + +/** + * @param {TemplateGenerator} template_generator + * @return {TemplateGenerator} + * */ +function* narrow_template(template_generator) { + let ast = yield intermediate_value(template_generator.next()) + + if (ast.node.firstChild && ast.node.from === ast.node.firstChild.from && ast.node.to === ast.node.firstChild.to) { + console.log("Narrowing!!!!", ast.node, ast.node.firstChild) + return { + node: ast.node, + from: ast.from, + to: ast.to, + children: [ + return_value( + template_generator.next({ + ...ast, + node: ast.node.firstChild, + }) + ), + ], + } + } else { + return return_value(template_generator.next(ast)) + } +} + +export const t = /** @type {const} */ ({ + any: any, + /** + * Match no, one, or multiple! Like `*` in regex. + * It stores it's matches as `{ [name]: Array<{ node: SyntaxNode, matches: MatchResult }> }` + * + * If name isn't provided it will not store any of the matches.. useful if you really really don't care about something. + * + * @type {(name?: string, what?: Templatable) => Substitution} + */ + many: memo_first_argument_weakmemo_second((name, of_what = any) => { + return function* many() { + let template_generator = to_template(of_what) + let ast = yield intermediate_value(template_generator.next()) + + // Ugly but it works + let narrowed_node = null + let sub_template = null + if (ast.node.firstChild && ast.node.from === ast.node.firstChild.from && ast.node.to === ast.node.firstChild.to) { + narrowed_node = ast.node + sub_template = return_value( + template_generator.next({ + ...ast, + node: ast.node.firstChild, + }) + ) + } else { + sub_template = return_value(template_generator.next(ast)) + } + + // let sub_template = yield* narrow_template(to_template(of_what)) + + return { + narrowed_node, + sub_template, + pattern: function many(cursor, matches, verbose = false) { + if (!cursor) { + verbose && console.log("✅ Nothing to see here... I'm fine with that - many") + return true + } + + if (narrowed_node) { + if (cursor.name !== narrowed_node.name) { + verbose && console.log("❌ Tried to go in, but she wasn't my type - many") + cursor.prevSibling() + return true + } + cursor.firstChild() + } + + try { + let matches_nodes = [] + while (true) { + // So, big oof here, but I think we shouldn't match error nodes in many + if (cursor.type.isError) { + cursor.prevSibling() + verbose && console.log("✋ I don't do errors - many") + return true // Still we did finish, lets just hope someone else cares about the error + } + + let local_match = {} + let did_match = match_template(cursor, sub_template, local_match, verbose) + if (!did_match) { + // Move back on child, as that is the child that DIDN'T match + // And we want to give the next template a change to maybe match it + cursor.prevSibling() + break + } + matches_nodes.push({ node: cursor.node, match: local_match }) + + if (!cursor.nextSibling()) break + } + + if (name != null) { + matches[name] = matches_nodes + } + return true + } finally { + if (narrowed_node) { + cursor.parent() + } + } + }, + } + } + }), + + /** + * Match either a single node or none. Like `?` in regex. + * @type {(what: Templatable) => Substitution} + */ + maybe: weak_memo1((what) => { + return function* maybe() { + let sub_template = yield* to_template(what) + return { + sub_template, + pattern: function maybe(cursor, matches, verbose = false) { + if (!cursor) return true + if (cursor.type.isError) return true + + let did_match = match_template(cursor, sub_template, matches, verbose) + + if (did_match === false) { + // Roll back position because we didn't match + cursor.prevSibling() + } + return true + }, + } + } + }), + + /** + * This is an escape hatch. + * Ideally I'd want to ask for multiple different templates to match, but I can't easily get that to work yet. + * So for now, you can ask templates to just match "Anything kinda like this", + * and then do further matching on the result manually. + * + * More technically, this says "match anything that will appear in my position in the AST". + * It does not care about the type. Don't use this recklessly! + * + * @type {(what: Templatable) => Substitution} + * */ + anything_that_fits: weak_memo1((what) => { + return function* anything_that_fits() { + // We send the template code upwards, but we fully ignore the output + yield* to_template(what) + return { + pattern: function anything_that_fits(cursor, matches, verbose = false) { + return true + }, + } + } + }), + /** + * This is an escape hatch, like {@linkcode anything_that_fits}, + * but it does also check for node type at least. + * + * @type {(what: Templatable) => Substitution} + * */ + something_with_the_same_type_as: weak_memo1((what) => { + return function* something_with_the_same_type_as() { + let template_generator = to_template(what) + let julia_to_parse = intermediate_value(template_generator.next()) + + let ast = yield julia_to_parse + + // @ts-ignore + template_generator.return() + + return { + pattern: function something_with_the_same_type_as(haystack, matches, verbose = false) { + return haystack != null && ast.name === haystack.name + }, + } + } + }), + + /** + * This "higher-order" template pattern is for adding their nodes to the matches. + * Without a pattern (e.g. `t.as("foo")`) it will default to `t.any` + * + * @type {(name: string, what?: Templatable) => Substitution} + */ + as: memo_first_argument_weakmemo_second((name, what = any) => { + return function* as() { + let sub_template = yield* to_template(what) + return { + sub_template, + pattern: function as(haystack, matches, verbose = false) { + let did_match = match_template(haystack, sub_template, matches, verbose) + if (did_match === true) { + matches[name] = haystack?.["node"] + } + return haystack != null && did_match + }, + } + } + }), + + /** @type {Substitution} */ + Identifier: function* Identifier() { + yield "identifier" + return { + pattern: function Identifier(haystack, matches, verbose = false) { + return haystack != null && narrow_name(haystack) === "Identifier" + }, + } + }, + /** @type {Substitution} */ + Number: function* Number() { + yield "69" + return { + pattern: function Number(haystack, matches, verbose = false) { + return haystack != null && narrow_name(haystack) === "Number" + }, + } + }, + /** @type {Substitution} */ + String: function* String() { + yield `"A113"` + return { + pattern: function String(haystack, matches, verbose = false) { + return ( + haystack != null && (narrow_name(haystack) === "StringWithoutInterpolation" || narrow_name(haystack) === "TripleStringWithoutInterpolation") + ) + }, + } + }, +}) + +/** + * Basically exists for {@linkcode create_specific_template_maker} + * + * @type {(template: Templatable, meta_template: Matcher) => Matcher} + */ +export let take_little_piece_of_template = weak_memo((template, meta_template) => { + let template_generator = to_template(template) + let julia_to_parse = intermediate_value(template_generator.next()) + + // Parse the AST from the template, but we don't send it back to the template_generator yet! + let template_ast = julia_to_ast(julia_to_parse) + + let match = null + // Match our created template code to the meta-template, which will yield us the part of the + // AST that falls inside the "content" in the meta-template. + if ((match = meta_template.match(template_ast))) { + let { content } = /** @type {{ content: SyntaxNode }} */ (match) + + let possible_parents = [] + while (content.firstChild && content.firstChild.from == content.from && content.firstChild.to == content.to) { + possible_parents.push(content.type) + content = content.firstChild + } + + if (content == null) { + console.log(`match:`, match) + throw new Error("No content match?") + } + + // Now we send just the `content` back to the template generator, which will happily accept it... + // (We do send the original from:to though, as these are the from:to's that are also in the template AST still) + let template_description = return_value( + template_generator.next({ + name: content.name, + node: content, + // Need to provide the original from:to range + from: template_ast.from, + to: template_ast.to, + }) + ) + + // And for some reason this works? + // Still feels like it shouldn't... it feels like I conjured some dark magic and I will be swiming in tartarus soon... + + return /** @type {Matcher} */ ({ + possible_parents, + template_description, + /** + * @param {TreeCursor | SyntaxNode} haystack_cursor + * @param {boolean} verbose? + * */ + match(haystack_cursor, verbose = false) { + if (haystack_cursor.type.isError) { + verbose && console.log(`❌ Short circuiting because haystack(${haystack_cursor.name}) is an error`) + return false + } + if ("cursor" in haystack_cursor) haystack_cursor = haystack_cursor.cursor() + + // Should possible parents be all-or-nothing? + // So either it matches all the possible parents, or it matches none? + let depth = 0 + for (let possible_parent of possible_parents) { + if (haystack_cursor.type === possible_parent) { + let parent_from = haystack_cursor.from + let parent_to = haystack_cursor.to + // Going in + if (haystack_cursor.firstChild()) { + if (haystack_cursor.from === parent_from && haystack_cursor.to === parent_to) { + verbose && console.log(`✅ Matched parent, going one level deeper (${possible_parent})`) + depth++ + } else { + haystack_cursor.parent() + verbose && + console.log( + `❌ Was matching possible parent (${possible_parent}), but it wasn't filling?! That's weird.... ${haystack_cursor.toString()}` + ) + for (let i = 0; i < depth; i++) { + haystack_cursor.parent() + } + return false + } + } + } else { + break + } + } + + // prettier-ignore + verbose && console.groupCollapsed(`Starting a specific at match haystack(${haystack_cursor.name}) vs. template(${"node" in template_description ? template_description.name : template_description.pattern.name})`) + + try { + let matches = {} + return match_template(haystack_cursor, template_description, matches, verbose) ? matches : null + } finally { + // ARE FOR LOOPS REALLY THE BEST I CAN DO HERE?? + for (let i = 0; i < depth; i++) { + haystack_cursor.parent() + } + + verbose && console.groupEnd() + } + }, + }) + } else { + console.log(`meta_template:`, meta_template) + console.log(`template:`, template) + throw new Error("Template passed into `take_little_piece_of_template` doesn't match meta_template") + } +}) + +/** + * Sometimes nodes are nested at the exact same position: + * `struct X end`, here `X` could be both a `Definition(Identifier)` or just the `Identifier`. + * This function will get you the deepest node, so in the above example, it would be `Identifier`. + * If the node has multiple children, or the child is offset, it will return the original node. + * + * @param {SyntaxNode} node + * @returns {SyntaxNode} + **/ +export let narrow = (node) => { + if (node.firstChild && node.firstChild.from === node.from && node.firstChild.to === node.to) { + return narrow(node.firstChild) + } else { + return node + } +} + +/** + * Effecient, cursor-based, version of `narrow(node)`, + * for if all you care about is the name. + * + * Which will be most of the time.. + * + * @param {TreeCursor} cursor + * @return {string} + */ +export let narrow_name = (cursor) => { + let from = cursor.from + let to = cursor.to + if (cursor.firstChild()) { + try { + if (cursor.from === from && cursor.to === to) { + return narrow_name(cursor) + } + } finally { + cursor.parent() + } + } + return cursor.name +} + +/** + * This allows for selecting the unselectable! + * By default templates need to match the topnode of their AST, but sometimes we want to match something on a special position. + * + * ```create_specific_template_maker(x => jl_dynamic`import X: ${x}`)``` will match specifiers that could occur specifically on the `${x}` position. + * + * NOTE: Inside `create_specific_template_maker` you'll have to use `jl_dynamic` not going to explain why. + * + * @param {(subtemplate: Templatable) => Templatable} fn + */ +export let create_specific_template_maker = (fn) => { + return (argument) => { + let meta_template = template(fn(t.as("content", argument))) + return take_little_piece_of_template(fn(argument), meta_template) + } +} + +/** + * Like Lezers `iterate`, but instead of `{ from, to, getNode() }` + * this will give `enter()` and `leave()` the `cursor` (which can be effeciently matches with lezer template) + * + * @param {{ + * tree: any, + * enter: (cursor: import("../../imports/CodemirrorPlutoSetup.js").TreeCursor) => (void | boolean), + * leave?: (cursor: import("../../imports/CodemirrorPlutoSetup.js").TreeCursor) => (void | boolean), + * from?: number, + * to?: number, + * }} options + */ +export function iterate_with_cursor({ tree, enter, leave, from = 0, to = tree.length }) { + let cursor = tree.cursor() + while (true) { + let mustLeave = false + if (cursor.from <= to && cursor.to >= from && (cursor.type.isAnonymous || enter(cursor) !== false)) { + if (cursor.firstChild()) continue + if (!cursor.type.isAnonymous) mustLeave = true + } + while (true) { + if (mustLeave && leave) leave(cursor) + mustLeave = cursor.type.isAnonymous + if (cursor.nextSibling()) break + if (!cursor.parent()) return + mustLeave = true + } + } +} + +/////////////////////////////////// +// FULL ON UTILITY FUNCTIONS +/////////////////////////////////// + +/** + * Not sure why typescript doesn't infer the `Generator` when I ask !iterater_result.done... + * Maybe it will bite me later 🤷‍♀️ + * + * @template T + * @param {IteratorResult} iterater_result + * @returns {T} iterater_result + */ +let intermediate_value = (iterater_result) => { + if (iterater_result.done) { + throw new Error("Expected `yield`-d value, but got `return`") + } else { + return /** @type {any} */ (iterater_result.value) + } +} + +/** + * Not sure why typescript doesn't infer the `Generator<_, T>` when I ask !iterater_result.done... + * Maybe it will bite me later 🤷‍♀️ + * + * @template T + * @param {IteratorResult} iterater_result + * @returns {T} iterater_result + */ +let return_value = (iterater_result) => { + if (iterater_result.done) { + return /** @type {any} */ (iterater_result.value) + } else { + throw new Error("Expected `yield`-d value, but got `return`") + } +} diff --git a/frontend/components/CellInput/mixedParsers.js b/frontend/components/CellInput/mixedParsers.js index a5ea41eb5a..da7e00ae7d 100644 --- a/frontend/components/CellInput/mixedParsers.js +++ b/frontend/components/CellInput/mixedParsers.js @@ -1,3 +1,5 @@ +import _ from "../../imports/lodash.js" + import { html, htmlLanguage, @@ -10,76 +12,117 @@ import { sql, javascript, python, - julia_andrey as julia_andrey_original, + julia_andrey, parseCode, } from "../../imports/CodemirrorPlutoSetup.js" const htmlParser = htmlLanguage.parser -const mdParser = markdownLanguage.parser +// @ts-ignore const mdParserExt = markdownLanguage.parser.configure(parseCode({ htmlParser })) const postgresParser = PostgreSQL.language.parser const sqlLang = sql({ dialect: PostgreSQL }) const pythonParser = pythonLanguage.parser -const MD_SIMPLE_TAGS = ["md", "mermaid"].flatMap((x) => [x, `@${x}`]) -const MD_EXTENDED_TAGS = ["cm", "markdown", "mdx", "mdl", "markdownliteral"].flatMap((x) => [x, `@${x}`]) +/** + * Markdown tags list; we create both `md""` and `@md("")` instances. + */ +const MD_TAGS = ["md", "mermaid", "cm", "markdown", "mdx", "mdl", "markdownliteral"].flatMap((x) => [x, `@${x}`]) +/** + * Julia strings are do not represent the exact code that is going to run + * for example the following julia string: + * + * ```julia + * """ + * const test = "five" + * const five = \${test} + * """ + * ``` + * + * is going to be executed as javascript, after escaping the \$ to $ + * + * ```javascript + * """ + * const test = "five" + * const five = ${test} + * """ + * ``` + * + * The overlays already remove the string interpolation parts of the julia string. + * This hack additionally removes the `\` from the overlay for common interpolations, so the underlaying parser + * will get the javascript version of the string, and not the julia version of the string (which is invalid js) + * + */ const overlayHack = (overlay, input) => { return overlay.flatMap(({ from, to }) => { const text = input.read(from, to) - const newlines = [...text.matchAll(/\\n/g)].map(({ index }) => ({ from: from + index, to: from + index + 2 })) - const escdollars = [...text.matchAll(/\\\$/g)].map(({ index }) => ({ from: from + index, to: from + index + 1 })) - const escjuliadollars = [...text.matchAll(/[^\\]\$/g)].map(({ index }) => ({ from: from + index, to: from + index + 2 })) - const extraOverlaysNegatives = _.sortBy([...newlines, ...escdollars, ...escjuliadollars], "from") + // const newlines = [...text.matchAll(/\\n/g)].map(({ index }) => ({ from: from + index, to: from + index + 2 })) + // const escdollars = [...text.matchAll(/\\\$/g)].map(({ index }) => ({ from: from + index, to: from + index + 1 })) + // const escjuliadollars = [...text.matchAll(/[^\\]\$/g)].map(({ index }) => ({ from: from + index, to: from + index + 2 })) + // const extraOverlaysNegatives = _.sortBy([...newlines, ...escdollars, ...escjuliadollars], "from") + + // For simplicity I removed the newlines stuff and just removed the \$ from the overlays + // Curious to see edge cases that this misses - DRAL const result = [] - let f = from, - t = to - extraOverlaysNegatives.forEach(({ from: newFrom, to: newTo }) => { - result.push({ from: f, to: newFrom }) - f = newTo - }) - result.push({ from: f, to: t }) - // console.log(result, { from, to }, result.map(({ from, to }) => input.read(from, to)).join(" - ")) + let last_content_start = from + for (let { index: relative_escape_start } of text.matchAll(/\\\$/g)) { + let next_escape_start = from + relative_escape_start + if (last_content_start !== next_escape_start) { + result.push({ from: last_content_start, to: next_escape_start }) + } + last_content_start = next_escape_start + 1 + } + if (last_content_start !== to) { + result.push({ from: last_content_start, to: to }) + } return result }) } +const STRING_NODE_NAMES = new Set([ + "TripleString", + "String", + "CommandString", + "TripleStringWithoutInterpolation", + "StringWithoutInterpolation", + "CommandStringWithoutInterpolation", +]) + const juliaWrapper = parseMixed((node, input) => { - if (!["TripleString", "String", "CommandString"].includes(node.type.name)) { + if (!STRING_NODE_NAMES.has(node.type.name)) { return null } - const offset = node.name === "TripleString" ? 3 : 1 - const defaultOverlay = [{ from: node.from + offset, to: Math.min(node.to - offset, input.length) }] - if (defaultOverlay[0].from >= defaultOverlay[0].to) { + let is_tripple_string = node.name === "TripleString" || node.name === "TripleStringWithoutInterpolation" + + const offset = is_tripple_string ? 3 : 1 + const string_content_from = node.from + offset + const string_content_to = Math.min(node.to - offset, input.length) + + if (string_content_from >= string_content_to) { return null } - //Looking for tag OR MacroIdentifier + // Looking for tag OR MacroIdentifier const tagNode = node.node?.prevSibling || node.node?.parent?.prevSibling - if (!tagNode) { + if (tagNode == null || (tagNode.name !== "MacroIdentifier" && tagNode.name !== "Prefix")) { // If you can't find a tag node, something is broken in the julia syntax, // so parse it as Julia. Probably wrong interpolation! return null } - const tag = input.read(tagNode.from, tagNode.to) - let parser, - overlay = [] - if (tag === "@htl") { - parser = htmlParser - } else if (tag === "html") { + const is_macro = tagNode.name === "MacroIdentifier" + + const tag = input.read(tagNode.from, tagNode.to) + let parser = null + if (tag === "@htl" || tag === "html") { parser = htmlParser - overlay = defaultOverlay - } else if (MD_SIMPLE_TAGS.includes(tag)) { - parser = mdParser - overlay = defaultOverlay - } else if (MD_EXTENDED_TAGS.includes(tag)) { + } else if (MD_TAGS.includes(tag)) { parser = mdParserExt - } else if (tag === "@javascript") { + } else if (tag === "@javascript" || tag === "@js" || tag === "js" || tag === "javascript") { parser = javascriptLanguage.parser - } else if (tag === "py" || tag === "pyr" || tag === "python") { + } else if (tag === "py" || tag === "pyr" || tag === "python" || tag === "@python") { parser = pythonParser } else if (tag === "sql") { parser = postgresParser @@ -87,45 +130,46 @@ const juliaWrapper = parseMixed((node, input) => { return null } - let from = node.from - for (let child = node.node.firstChild; overlay !== defaultOverlay && child !== null && child.to <= node.to; child = child?.nextSibling) { - overlay.push({ from, to: child.from }) - from = child.to - } - // If overlay is not the default and we haven't found anything (=interpolation) inside, use the default - if (overlay.length === 0 || node.node.firstChild === null) { - overlay = defaultOverlay - } else if ( - // If the overlay is the default, this fix is not needed, as it's already adjusted for limits - overlay !== defaultOverlay - ) { - overlay.push({ from, to: node.to }) - // Remove quotes from strings - if (node.type.name === "TripleString") { - // Triple Quote String - overlay[0].from += 3 - overlay[overlay.length - 1].to -= 3 - } else { - // Single quote string - overlay[0].from += 1 - overlay[overlay.length - 1].to -= 1 + let overlay = [] + if (node.node.firstChild != null) { + let last_content_start = string_content_from + let child = node.node.firstChild.cursor() + + do { + if (last_content_start !== child.from) { + overlay.push({ from: last_content_start, to: child.from }) + } + last_content_start = child.to + } while (child.nextSibling()) + if (last_content_start < string_content_to) { + overlay.push({ from: last_content_start, to: string_content_to }) } + } else { + overlay = [{ from: string_content_from, to: string_content_to }] } - // If javascript or markdown or htl, we want to unescape some characters - // Until the parser is smarter, we remove the selection from the syntax highlighting overlay. - if (["@htl", "@javascript", ...MD_EXTENDED_TAGS].includes(tag)) { + // If it is a macro, thus supports interpolations (prefixed strings only have faux-interpolations) but not raw strings (`\n` will be a newline, for the character `\n` you need to do `\\n`) + // we need to remove `\$` (which should just be `$` in the javascript) + if (is_macro) { overlay = overlayHack(overlay, input) } + + // No overlays for markdown yet + // (They sometimes work, but sometimes also randomly crash when adding an interpolation + // I guess this has something to do with the fact that markdown isn't parsed with lezer, + // but has some custom made thing that emulates lezer.) + if ([...MD_TAGS].includes(tag)) { + return { parser, overlay: [{ from: string_content_from, to: string_content_to }] } + } + return { parser, overlay } }) -const julia_andrey = (config) => { - const julia = julia_andrey_original(config) - /* We need to revert this due to https://github.com/fonsp/Pluto.jl/issues/1800 - fix is WIP - julia.language.parser = julia.language.parser.configure({ wrap: juliaWrapper }) - */ +const julia_mixed = (config) => { + const julia = julia_andrey(config) + // @ts-ignore + julia.language.parser = julia.language.parser.configure({ wrap: juliaWrapper }) return julia } -export { julia_andrey, sqlLang, pythonLanguage, javascript, htmlLanguage, javascriptLanguage, python, markdown, html } +export { julia_mixed, sqlLang, pythonLanguage, javascript, htmlLanguage, javascriptLanguage, python, markdown, html } diff --git a/frontend/components/CellInput/mod_d_command.js b/frontend/components/CellInput/mod_d_command.js new file mode 100644 index 0000000000..1363d572de --- /dev/null +++ b/frontend/components/CellInput/mod_d_command.js @@ -0,0 +1,65 @@ +import { EditorView, EditorSelection, selectNextOccurrence, syntaxTree } from "../../imports/CodemirrorPlutoSetup.js" + +let array_at = (array, pos) => { + return array.slice(pos, pos + 1)[0] +} + +export let mod_d_command = { + key: "Mod-d", + /** @param {EditorView} view */ + run: ({ state, dispatch }) => { + if (state.selection.main.empty) { + let nodes_that_i_like = ["Identifier", "FieldName"] + + // Expand to closest Identifier + let cursor_left = syntaxTree(state).cursorAt(state.selection.main.from, -1) + let cursor_right = syntaxTree(state).cursorAt(state.selection.main.from, 1) + + for (let node_i_like of nodes_that_i_like) { + let matching_node = cursor_left.name === node_i_like ? cursor_left : cursor_right.name === node_i_like ? cursor_right : null + if (matching_node) { + dispatch({ + selection: { anchor: matching_node.from, head: matching_node.to }, + }) + return true + } + } + + // If there is no cool syntax thing (say we are in a string), then just select the word. + let line = state.doc.lineAt(state.selection.main.from) + let position_relative_to_line = state.selection.main.from - line.from + let before_cursor = line.text.slice(0, position_relative_to_line) + let after_cursor = line.text.slice(position_relative_to_line) + + let word_before_cursor = before_cursor.match(/(\w+)$/)?.[0] ?? "" + let word_after_cursor = after_cursor.match(/^(\w+)/)?.[0] ?? "" + + dispatch({ + selection: { anchor: state.selection.main.from - word_before_cursor.length, head: state.selection.main.from + word_after_cursor.length }, + }) + } else { + selectNextOccurrence({ state, dispatch }) + } + return false + }, + /** @param {EditorView} view */ + shift: ({ state, dispatch }) => { + if (state.selection.ranges.length === 1) return false + + // So funny thing, the index "before" (might wrap around) the mainIndex is the one you just selected + // @ts-ignore + let just_selected = state.selection.ranges.at(state.selection.mainIndex - 1) + + let new_ranges = state.selection.ranges.filter((x) => x !== just_selected) + let new_main_index = new_ranges.indexOf(state.selection.main) + + let previous_selected = array_at(new_ranges, state.selection.mainIndex - 1) + + dispatch({ + selection: EditorSelection.create(new_ranges, new_main_index), + effects: previous_selected == null ? [] : EditorView.scrollIntoView(previous_selected.from), + }) + return true + }, + preventDefault: true, +} diff --git a/frontend/components/CellInput/pkg_bubble_plugin.js b/frontend/components/CellInput/pkg_bubble_plugin.js index 5f024dc545..fcab9e6a8a 100644 --- a/frontend/components/CellInput/pkg_bubble_plugin.js +++ b/frontend/components/CellInput/pkg_bubble_plugin.js @@ -3,10 +3,11 @@ import { EditorView, syntaxTree, Decoration, ViewUpdate, ViewPlugin, Facet } fro import { PkgStatusMark, PkgActivateMark } from "../PkgStatusMark.js" import { html } from "../../imports/Preact.js" import { ReactWidget } from "./ReactWidget.js" +import { create_specific_template_maker, iterate_with_cursor, jl, jl_dynamic, narrow, t, template } from "./lezer_template.js" /** * @typedef PkgstatusmarkWidgetProps - * @type {{ nbpkg: any, pluto_actions: any, notebook_id: string }} + * @type {{ nbpkg: import("../Editor.js").NotebookPkgData, pluto_actions: any, notebook_id: string }} */ // This list appears multiple times in our codebase. Be sure to match edits everywhere. @@ -22,167 +23,235 @@ export const pkg_disablers = [ "@quickactivate", ] -/** - * @param {EditorView} view - * @param {PkgstatusmarkWidgetProps} props - */ -function pkg_decorations(view, { pluto_actions, notebook_id, nbpkg }) { - let widgets = [] - let seen_packages = new Set() - - const add_widget = (package_name, target) => { - if (package_name !== "Base" && package_name !== "Core" && !seen_packages.has(package_name)) { - seen_packages.add(package_name) - let deco = Decoration.widget({ - widget: new ReactWidget(html` - <${PkgStatusMark} - key=${package_name} - package_name=${package_name} - pluto_actions=${pluto_actions} - notebook_id=${notebook_id} - nbpkg=${nbpkg} - /> - `), - side: 1, - }) - widgets.push(deco.range(target)) - } - } +function find_import_statements({ doc, tree, from, to }) { + // This quotelevel stuff is waaaay overengineered and precise... + // but I love making stuff like this SO LET ME OKAY + let quotelevel = 0 + let things_to_return = [] - for (let { from, to } of view.visibleRanges) { - let in_import = false - let in_selected_import = false - let is_inside_quote = false - - let is_inside_rename_import = false - let is_renamed_package_bubbled = false + iterate_with_cursor({ + tree, + from, + to, + enter: (cursor) => { + // `quote ... end` or `:(...)` + if (cursor.name === "QuoteExpression" || cursor.name === "QuoteStatement") { + quotelevel++ + } + // `$(...)` when inside quote + if (cursor.name === "InterpolationExpression") { + quotelevel-- + } + if (quotelevel !== 0) return - let is_inside_scoped_identifier = false + // Check for Pkg.activate() and friends + if (cursor.name === "CallExpression" || cursor.name === "MacroExpression") { + let node = cursor.node + let callee = node.firstChild + let callee_name = doc.sliceString(callee.from, callee.to) - syntaxTree(view.state).iterate({ - from, - to, - enter: (type, from, to, getNode) => { - // `quote ... end` or `:(...)` - if (type.name === "QuoteExpression" || type.name === "QuoteStatement") { - is_inside_quote = true - } - // `$(...)` when inside quote - if (type.name === "InterpolationExpression") { - is_inside_quote = false + if (pkg_disablers.includes(callee_name)) { + things_to_return.push({ + type: "package_disabler", + name: callee_name, + from: cursor.to, + to: cursor.to, + }) } - if (is_inside_quote) return - // Check for Pkg.activate() and friends - if (type.name === "CallExpression" || type.name === "MacroExpression") { - let node = getNode() - let callee = node.firstChild - let callee_name = view.state.sliceDoc(callee.from, callee.to) + return + } - if (pkg_disablers.includes(callee_name)) { - let deco = Decoration.widget({ - widget: new ReactWidget(html` <${PkgActivateMark} package_name=${callee_name} /> `), - side: 1, - }) - widgets.push(deco.range(to)) - } + let import_specifier_template = create_specific_template_maker((x) => jl_dynamic`import A, ${x}`) + // Because the templates can't really do recursive stuff, we need JavaScript™️! + let unwrap_scoped_import = (specifier) => { + let match = null + if ((match = import_specifier_template(jl`${t.as("package")}.${t.any}`).match(specifier))) { + return unwrap_scoped_import(match.package) + } else if ((match = import_specifier_template(jl`.${t.maybe(t.any)}`).match(specifier))) { + // Still trash! + return null + } else if ((match = import_specifier_template(jl`${t.Identifier}`).match(specifier))) { + return specifier + } else { + console.warn("Unknown nested import specifier: " + specifier.toString()) } + } - if (type.name === "ImportStatement") { - in_import = true - } - if (type.name === "SelectedImport") { - in_selected_import = true - } - if (type.name === "RenamedIdentifier") { - is_inside_rename_import = true - } - // Don't show a buble next to the name `B` in `import A as B` - if (is_inside_rename_import && is_renamed_package_bubbled) { - return + let match = null + if ( + // These templates might look funky... and they are! + // But they are necessary to force the matching to match as specific as possible. + // With just `import ${t.many("specifiers")}` it will match `import A, B, C`, but + // it will do so by giving back [`A, B, C`] as one big specifier! + (match = template(jl`import ${t.as("specifier")}: ${t.many()}`).match(cursor)) ?? + (match = template(jl`import ${t.as("specifier")}, ${t.many("specifiers")}`).match(cursor)) ?? + (match = template(jl`using ${t.as("specifier")}: ${t.many()}`).match(cursor)) ?? + (match = template(jl`using ${t.as("specifier")}, ${t.many("specifiers")}`).match(cursor)) + ) { + let { specifier, specifiers = [] } = match + + if (specifier) { + specifiers = [{ node: specifier }, ...specifiers] } - // `import .X` or `import ..X` or `import Flux.Zygote` - // handled when leaving the ScopedIdentifier - if (in_import && type.name === "ScopedIdentifier") { - is_inside_scoped_identifier = true + for (let { node: specifier } of specifiers) { + specifier = narrow(specifier) - if (is_inside_rename_import && !is_renamed_package_bubbled) { - is_renamed_package_bubbled = true + let match = null + if ((match = import_specifier_template(jl`${t.as("package")} as ${t.maybe(t.any)}`).match(specifier))) { + let node = unwrap_scoped_import(match.package) + if (node) { + things_to_return.push({ + type: "package", + name: doc.sliceString(node.from, node.to), + from: node.to, + to: node.to, + }) + } + } else if ((match = import_specifier_template(jl`${t.as("package")}.${t.any}`).match(specifier))) { + let node = unwrap_scoped_import(match.package) + if (node) { + things_to_return.push({ + type: "package", + name: doc.sliceString(node.from, node.to), + from: node.to, + to: node.to, + }) + } + } else if ((match = import_specifier_template(jl`.${t.as("scoped")}`).match(specifier))) { + // Trash! + } else if ((match = import_specifier_template(jl`${t.as("package")}`).match(specifier))) { + let node = unwrap_scoped_import(match.package) + if (node) { + things_to_return.push({ + type: "package", + name: doc.sliceString(node.from, node.to), + from: node.to, + to: node.to, + }) + } + } else { + console.warn("Unknown import specifier: " + specifier.toString()) } - - return } - if (in_import && type.name === "Identifier" && !is_inside_scoped_identifier) { - if (is_inside_rename_import && !is_renamed_package_bubbled) { - is_renamed_package_bubbled = true + match = null + if ((match = template(jl`using ${t.as("specifier")}, ${t.many("specifiers")}`).match(cursor))) { + let { specifier } = match + if (specifier) { + if (doc.sliceString(specifier.to, specifier.to + 1) === "\n" || doc.sliceString(specifier.to, specifier.to + 1) === "") { + things_to_return.push({ + type: "implicit_using", + name: doc.sliceString(specifier.from, specifier.to), + from: specifier.to, + to: specifier.to, + }) + } } + } - let package_name = view.state.doc.sliceString(from, to) - // console.warn(type) - // console.warn("Found", package_name) - add_widget(package_name, to) + return false + } else if (cursor.name === "ImportStatement") { + throw new Error("What") + } + }, + leave: (cursor) => { + if (cursor.name === "QuoteExpression" || cursor.name === "QuoteStatement") { + quotelevel-- + } + if (cursor.name === "InterpolationExpression") { + quotelevel++ + } + }, + }) - if (in_selected_import) { - in_import = false - } - } - }, - leave: (type, from, to, getNode) => { - if (type.name === "QuoteExpression" || type.name === "QuoteStatement") { - is_inside_quote = false - } - if (type.name === "InterpolationExpression") { - is_inside_quote = true - } - if (type.name === "RenamedIdentifier") { - is_inside_rename_import = false - is_renamed_package_bubbled = false - } - if (is_inside_quote) return + return things_to_return +} - // console.log("Leave", type.name) - if (type.name === "ImportStatement") { - in_import = false - } - if (type.name === "SelectedImport") { - in_selected_import = false - } - if (type.name === "ScopedIdentifier") { - let node = getNode() - if (node.parent.name === "Import" || node.parent.name === "SelectedImport") { - is_inside_scoped_identifier = false - let package_name = view.state.doc.sliceString(from, to) - - if (package_name.startsWith(".")) { - return - } +/** + * @param {EditorView} view + * @param {PkgstatusmarkWidgetProps} props + */ +function pkg_decorations(view, { pluto_actions, notebook_id, nbpkg }) { + let seen_packages = new Set() - package_name = package_name.split(".")[0] - add_widget(package_name, to) + let widgets = view.visibleRanges + .flatMap(({ from, to }) => { + let things_to_mark = find_import_statements({ + doc: view.state.doc, + tree: syntaxTree(view.state), + from: from, + to: to, + }) - if (in_selected_import) { - in_import = false - } + return things_to_mark.map((thing) => { + if (thing.type === "package") { + let { name: package_name } = thing + if (package_name !== "Base" && package_name !== "Core" && !seen_packages.has(package_name)) { + seen_packages.add(package_name) + + let deco = Decoration.widget({ + widget: new ReactWidget(html` + <${PkgStatusMark} + key=${package_name} + package_name=${package_name} + pluto_actions=${pluto_actions} + notebook_id=${notebook_id} + nbpkg=${nbpkg} + /> + `), + side: 1, + }) + return deco.range(thing.to) + } + } else if (thing.type === "package_disabler") { + let deco = Decoration.widget({ + widget: new ReactWidget(html` <${PkgActivateMark} package_name=${thing.name} /> `), + side: 1, + }) + return deco.range(thing.to) + } else if (thing.type === "implicit_using") { + if (thing.name === "HypertextLiteral") { + let deco = Decoration.widget({ + widget: new ReactWidget(html` +
+ : @htl, @htl_str +
+
`), + side: 1, + }) + return deco.range(thing.to) } } - }, + }) }) - } - return Decoration.set(widgets) + .filter((x) => x != null) + return Decoration.set(widgets, true) } +/** + * @type {Facet} + */ export const NotebookpackagesFacet = Facet.define({ combine: (values) => values[0], compare: _.isEqual, }) -export const pkgBubblePlugin = ({ pluto_actions, notebook_id }) => +export const pkgBubblePlugin = ({ pluto_actions, notebook_id_ref }) => ViewPlugin.fromClass( class { update_decos(view) { - const ds = pkg_decorations(view, { pluto_actions, notebook_id, nbpkg: view.state.facet(NotebookpackagesFacet) }) + const ds = pkg_decorations(view, { pluto_actions, notebook_id: notebook_id_ref.current, nbpkg: view.state.facet(NotebookpackagesFacet) }) this.decorations = ds } @@ -209,11 +278,5 @@ export const pkgBubblePlugin = ({ pluto_actions, notebook_id }) => }, { decorations: (v) => v.decorations, - - eventHandlers: { - pointerdown: (e, view) => { - let target = e.target - }, - }, } ) diff --git a/frontend/components/CellInput/pluto_autocomplete.js b/frontend/components/CellInput/pluto_autocomplete.js index 55b6de9bf0..7b9f5f8ad3 100644 --- a/frontend/components/CellInput/pluto_autocomplete.js +++ b/frontend/components/CellInput/pluto_autocomplete.js @@ -15,14 +15,21 @@ import { } from "../../imports/CodemirrorPlutoSetup.js" import { get_selected_doc_from_state } from "./LiveDocsFromCursor.js" import { cl } from "../../common/ClassTable.js" +import { ScopeStateField } from "./scopestate_statefield.js" +import { open_bottom_right_panel } from "../BottomRightPanel.js" -let { autocompletion, completionKeymap } = autocomplete +let { autocompletion, completionKeymap, completionStatus, acceptCompletion } = autocomplete -// These should be imported from @codemirror/autocomplete +// Option.source is now the source, we find to find the corresponding ActiveResult +// https://github.com/codemirror/autocomplete/commit/6d9f24115e9357dc31bc265cd3da7ce2287fdcbd +const getActiveResult = (view, source) => view.state.field(completionState).active.find((a) => a.source == source) + +// These should be imported from @codemirror/autocomplete, but they are not exported. let completionState = autocompletion()[0] -let acceptCompletion = (/** @type {EditorView} */ view, option) => { +let applyCompletion = (/** @type {EditorView} */ view, option) => { let apply = option.completion.apply || option.completion.label - let result = option.source + let result = getActiveResult(view, option.source) + if (!result?.from) return if (typeof apply == "string") { view.dispatch({ changes: { from: result.from, to: result.to, insert: apply }, @@ -63,9 +70,16 @@ const tabCompletionState = StateField.define({ /** @param {EditorView} cm */ const tab_completion_command = (cm) => { // This will return true if the autocomplete select popup is open - if (autocomplete.acceptCompletion(cm)) { + // To test the exception sink, uncomment these lines: + // if (Math.random() > 0.7) { + // throw "LETS CRASH THIS" + // } + if (acceptCompletion(cm)) { return true } + if (cm.state.readOnly) { + return false + } let selection = cm.state.selection.main let last_char = cm.state.sliceDoc(selection.from - 1, selection.from) @@ -85,15 +99,16 @@ const tab_completion_command = (cm) => { let open_docs_if_autocomplete_is_open_command = (cm) => { let autocompletion_open = cm.state.field(completionState, false)?.open ?? false if (autocompletion_open) { - window.dispatchEvent(new CustomEvent("open_live_docs")) + open_bottom_right_panel("docs") return true } + return false } /** @param {EditorView} cm */ let complete_and_also_type = (cm) => { // Possibly autocomplete - autocomplete.acceptCompletion(cm) + acceptCompletion(cm) // And then do nothing, in the hopes that codemirror will add whatever we typed return false } @@ -120,11 +135,21 @@ let update_docs_from_autocomplete_selection = (on_update_doc_query) => { let text_to_apply = selected_option.completion.apply ?? selected_option.completion.label if (typeof text_to_apply !== "string") return + const active_result = getActiveResult(update.view, selected_option.source) + if (!active_result?.from) return // not an ActiveResult instance + + const from = active_result.from, + to = Math.min(active_result.to, update.state.doc.length) + // Apply completion to state, which will yield us a `Transaction`. // The nice thing about this is that we can use the resulting state from the transaction, // without updating the actual state of the editor. let result_transaction = update.state.update({ - changes: { from: selected_option.source.from, to: selected_option.source.to, insert: text_to_apply }, + changes: { + from, + to, + insert: text_to_apply, + }, }) // So we can use `get_selected_doc_from_state` on our virtual state @@ -135,16 +160,31 @@ let update_docs_from_autocomplete_selection = (on_update_doc_query) => { }) } -let match_unicode_complete = (ctx) => ctx.matchBefore(/\\[^\s"'.`]*/) +/** Are we matching something like `\lambd...`? */ +let match_latex_complete = (ctx) => ctx.matchBefore(/\\[^\s"'.`]*/) +/** Are we matching something like `:writing_a_symbo...`? */ let match_symbol_complete = (ctx) => ctx.matchBefore(/\.\:[^\s"'`()\[\].]*/) +/** Are we matching exactly `~/`? */ let match_expanduser_complete = (ctx) => ctx.matchBefore(/~\//) +/** Are we matching inside a string */ +function match_string_complete(ctx) { + const tree = syntaxTree(ctx.state) + const node = tree.resolve(ctx.pos) + if (node == null || (node.name !== "TripleString" && node.name !== "String")) { + return false + } + return true +} -let unfiltered_julia_generator = (/** @type {PlutoRequestAutocomplete} */ request_autocomplete) => async (ctx) => { - let unicode_match = match_unicode_complete(ctx) || match_expanduser_complete(ctx) - if (unicode_match == null) return null - +/** Use the completion results from the Julia server to create CM completion objects, but only for path completions (TODO: broken) and latex completions. */ +let julia_special_completions_to_cm = (/** @type {PlutoRequestAutocomplete} */ request_autocomplete) => async (ctx) => { let to_complete = ctx.state.sliceDoc(0, ctx.pos) - let { start, stop, results } = await request_autocomplete({ text: to_complete }) + + let found = await request_autocomplete({ text: to_complete }) + if (!found) return null + let { start, stop, results } = found + + let should_apply_unicode_completion = !match_string_complete(ctx) return { from: start, @@ -152,11 +192,11 @@ let unfiltered_julia_generator = (/** @type {PlutoRequestAutocomplete} */ reques // This is an important one when you not only complete, but also replace something. // @codemirror/autocomplete automatically filters out results otherwise >:( filter: false, - // TODO Add "detail" that shows the unicode character - // TODO Add "apply" with the unicode character so it autocompletes that immediately - options: results.map(([text], i) => { + options: results.map(([text, _, __, ___, ____, detail]) => { return { label: text, + apply: detail && should_apply_unicode_completion ? detail : text, + detail: detail ?? undefined, } }), // TODO Do something docs_prefix ish when we also have the apply text @@ -167,7 +207,27 @@ let override_text_to_apply_in_field_expression = (text) => { return !/^[@a-zA-Z_][a-zA-Z0-9!_]*\"?$/.test(text) ? (text === ":" ? `:(${text})` : `:${text}`) : null } -const juliahints_cool_generator = (/** @type {PlutoRequestAutocomplete} */ request_autocomplete) => async (ctx) => { +/** + * @param {Map} definitions + * @param {Set} proposed + * @param {number} context_pos + */ +const generate_scopestate_completions = function* (definitions, proposed, context_pos) { + let i = 0 + for (let [name, { valid_from }] of definitions.entries()) { + if (!proposed.has(name) && valid_from < context_pos) { + yield { + label: name, + type: "c_Any", + boost: 99 - i, + } + i += 1 + } + } +} + +/** Use the completion results from the Julia server to create CM completion objects. */ +const julia_code_completions_to_cm = (/** @type {PlutoRequestAutocomplete} */ request_autocomplete) => async (ctx) => { let to_complete = ctx.state.sliceDoc(0, ctx.pos) // Another rough hack... If it detects a `.:`, we want to cut out the `:` so we get all results from julia, @@ -177,13 +237,18 @@ const juliahints_cool_generator = (/** @type {PlutoRequestAutocomplete} */ reque to_complete = to_complete.slice(0, is_symbol_completion.from + 1) + to_complete.slice(is_symbol_completion.from + 2) } - let { start, stop, results } = await request_autocomplete({ text: to_complete }) + let found = await request_autocomplete({ text: to_complete }) + if (!found) return null + let { start, stop, results } = found if (is_symbol_completion) { // If this is a symbol completion thing, we need to add the `:` back in by moving the end a bit furher stop = stop + 1 } + const definitions = ctx.state.field(ScopeStateField).definitions + const proposed = new Set() + let to_complete_onto = to_complete.slice(0, start) let is_field_expression = to_complete_onto.slice(-1) === "." return { @@ -201,16 +266,20 @@ const juliahints_cool_generator = (/** @type {PlutoRequestAutocomplete} */ reque // (quick) fix for identifiers that need to be escaped // Ideally this is done with Meta.isoperator on the julia side let text_to_apply = is_field_expression ? override_text_to_apply_in_field_expression(text) ?? text : text + + if (definitions.has(text)) proposed.add(text) + return { label: text, apply: text_to_apply, - type: cl({ - c_notexported: !is_exported, - [`c_${type_description}`]: type_description != null, - [`completion_${completion_type}`]: completion_type != null, - c_from_notebook: is_from_notebook, - }), - boost: 99 - i / results.length, + type: + cl({ + c_notexported: !is_exported, + [`c_${type_description}`]: type_description != null, + [`completion_${completion_type}`]: completion_type != null, + c_from_notebook: is_from_notebook, + }) ?? undefined, + boost: 50 - i / results.length, } }), // This is a small thing that I really want: @@ -221,7 +290,7 @@ const juliahints_cool_generator = (/** @type {PlutoRequestAutocomplete} */ reque ...results .filter(([text]) => is_field_expression && override_text_to_apply_in_field_expression(text) != null) .map(([text, type_description, is_exported], i) => { - let text_to_apply = override_text_to_apply_in_field_expression(text) + let text_to_apply = override_text_to_apply_in_field_expression(text) ?? "" return { label: text_to_apply, @@ -232,16 +301,74 @@ const juliahints_cool_generator = (/** @type {PlutoRequestAutocomplete} */ reque is_not_exported: !is_exported, } }), + + ...Array.from(generate_scopestate_completions(definitions, proposed, ctx.pos)), ], } } +const pluto_completion_fetcher = (request_autocomplete) => { + const unicode_completions = julia_special_completions_to_cm(request_autocomplete) + const code_completions = julia_code_completions_to_cm(request_autocomplete) + + return (ctx) => { + let unicode_match = match_latex_complete(ctx) || match_expanduser_complete(ctx) + if (unicode_match === null) { + return code_completions(ctx) + } else { + return unicode_completions(ctx) + } + } +} + +const complete_anyword = async (ctx) => { + const results_from_cm = await autocomplete.completeAnyWord(ctx) + if (results_from_cm === null) return null + + return { + from: results_from_cm.from, + options: results_from_cm.options.map(({ label }, i) => ({ + // See https://github.com/codemirror/codemirror.next/issues/788 about `type: null` + label, + apply: label, + type: undefined, + boost: 0 - i, + })), + } +} + +const local_variables_completion = (ctx) => { + let scopestate = ctx.state.field(ScopeStateField) + let unicode = ctx.tokenBefore(["Identifier"]) + + if (unicode === null) return null + + let { from, to, text } = unicode + + return { + from, + to, + options: scopestate.locals + .filter( + ({ validity, name }) => + name.startsWith(text) /** <- NOTE: A smarter matching strategy can be used here */ && from > validity.from && to <= validity.to + ) + .map(({ name }, i) => ({ + // See https://github.com/codemirror/codemirror.next/issues/788 about `type: null` + label: name, + apply: name, + type: undefined, + boost: 99 - i, + })), + } +} + /** * @typedef PlutoAutocompleteResults - * @type {{ start: number, stop: number, results: Array<[string, (string | null), boolean, boolean, (string | null)]> }} + * @type {{ start: number, stop: number, results: Array<[string, (string | null), boolean, boolean, (string | null), (string | null)]> }} * * @typedef PlutoRequestAutocomplete - * @type {(options: { text: string }) => Promise} + * @type {(options: { text: string }) => Promise} */ /** @@ -254,19 +381,20 @@ export let pluto_autocomplete = ({ request_autocomplete, on_update_doc_query }) let last_result = null /** * To make stuff a bit easier, we let all the generators fetch all the time and run their logic, but just do one request. - * Previously I had checks to make sure when `unicode_hint_generator` matches it wouldn't fetch in `juliahints_cool_generator`.. + * Previously I had checks to make sure when `unicode_hint_generator` matches it wouldn't fetch in `julia_code_completions_to_cm`.. * but that became cumbersome with `expanduser` autocomplete.. also because THERE MIGHT be a case where * `~/` actually needs a different completion? Idk, I decided to put this "memoize last" thing here deal with it. * @type {PlutoRequestAutocomplete} **/ let memoize_last_request_autocomplete = async (options) => { if (_.isEqual(options, last_query)) { - return await last_result - } else { - last_query = options - last_result = request_autocomplete(options) - return await last_result + let result = await last_result + if (result != null) return result } + + last_query = options + last_result = request_autocomplete(options) + return await last_result } return [ @@ -274,13 +402,16 @@ export let pluto_autocomplete = ({ request_autocomplete, on_update_doc_query }) autocompletion({ activateOnTyping: false, override: [ - unfiltered_julia_generator(memoize_last_request_autocomplete), - juliahints_cool_generator(memoize_last_request_autocomplete), - // TODO completion for local variables + pluto_completion_fetcher(memoize_last_request_autocomplete), + // julia_special_completions_to_cm(memoize_last_request_autocomplete), + // julia_code_completions_to_cm(memoize_last_request_autocomplete), + complete_anyword, + // TODO: Disabled because of performance problems, see https://github.com/fonsp/Pluto.jl/pull/1925. Remove `complete_anyword` once fixed. See https://github.com/fonsp/Pluto.jl/pull/2013 + // local_variables_completion, ], defaultKeymap: false, // We add these manually later, so we can override them if necessary maxRenderedOptions: 512, // fons's magic number - optionClass: (c) => c.type, + optionClass: (c) => c.type ?? "", }), // If there is just one autocomplete result, apply it directly @@ -290,8 +421,14 @@ export let pluto_autocomplete = ({ request_autocomplete, on_update_doc_query }) let autocompletion_state = update.state.field(completionState, false) let is_tab_completion = update.state.field(tabCompletionState, false) - if (autocompletion_state?.open != null && is_tab_completion && autocompletion_state.open.options.length === 1) { - acceptCompletion(update.view, autocompletion_state.open.options[0]) + if ( + autocompletion_state?.open != null && + is_tab_completion && + completionStatus(update.state) === "active" && + autocompletion_state.open.options.length === 1 + ) { + // We can't use `acceptCompletion` here because that function has a minimum delay of 75ms between creating the completion options and applying one. + applyCompletion(update.view, autocompletion_state.open.options[0]) } }), diff --git a/frontend/components/CellInput/pluto_paste_plugin.js b/frontend/components/CellInput/pluto_paste_plugin.js index 6dd8a11948..c38a9de720 100644 --- a/frontend/components/CellInput/pluto_paste_plugin.js +++ b/frontend/components/CellInput/pluto_paste_plugin.js @@ -14,7 +14,7 @@ export let pluto_paste_plugin = ({ pluto_actions, cell_id }) => { event.stopPropagation() const topaste = event.clipboardData.getData("text/plain") - const deserializer = detect_deserializer(topaste, false) + const deserializer = detect_deserializer(topaste) if (deserializer == null) { return false } diff --git a/frontend/components/CellInput/scopestate_statefield.js b/frontend/components/CellInput/scopestate_statefield.js new file mode 100644 index 0000000000..0a22b182ce --- /dev/null +++ b/frontend/components/CellInput/scopestate_statefield.js @@ -0,0 +1,1115 @@ +import { syntaxTree, StateField } from "../../imports/CodemirrorPlutoSetup.js" +import _ from "../../imports/lodash.js" +import { child_cursors, child_nodes, create_specific_template_maker, jl, jl_dynamic, narrow, t, template } from "./lezer_template.js" + +/** + * @typedef TreeCursor + * @type {import("../../imports/CodemirrorPlutoSetup.js").TreeCursor} + */ + +/** + * @typedef SyntaxNode + * @type {TreeCursor["node"]} + */ + +/** + * @typedef Range + * @property {number} from + * @property {number} to + * + * @typedef {Range & {valid_from: number}} Definition + * + * @typedef ScopeState + * @property {Array<{ + * usage: Range, + * definition: Range | null, + * name: string, + * }>} usages + * @property {Map} definitions + * @property {Array<{ definition: Range, validity: Range, name: string }>} locals + */ + +/** + * @param {ScopeState} a + * @param {ScopeState} b + * @returns {ScopeState} + */ +let merge_scope_state = (a, b) => { + if (a === b) return a + + let usages = [...a.usages, ...b.usages] + let definitions = new Map(a.definitions) + for (let [key, value] of b.definitions) { + definitions.set(key, value) + } + let locals = [...a.locals, ...b.locals] + return { usages, definitions, locals } +} + +/** @param {TreeCursor} cursor */ +let search_for_interpolations = function* (cursor) { + for (let child of child_cursors(cursor)) { + if (child.name === "InterpolationExpression") { + yield cursor + } else if (child.name === "QuoteExpression" || child.name === "QuoteStatement") { + for (let child_child of search_for_interpolations(child)) { + yield* search_for_interpolations(child_child) + } + } else { + yield* search_for_interpolations(child) + } + } +} +/** @param {TreeCursor} cursor */ +let go_through_quoted_expression_looking_for_interpolations = function* (cursor) { + if (cursor.name !== "QuoteExpression" && cursor.name !== "QuoteStatement") throw new Error("Expected QuotedExpression or QuoteStatement") + yield* search_for_interpolations(cursor) +} + +/** + * So this was a late addition, and it creates a bit crazy syntax... + * but I love it for that syntax! It really makes the patterns pop out, + * which it really needs, because the patterns are the most important part of this code.. + * @param {(subsitution: import("./lezer_template.js").Templatable) => import("./lezer_template.js").Matcher} template_fn + */ +let make_beautiful_matcher = (template_fn) => { + return function match(cursor, verbose = false) { + if (cursor == null) { + /** @type {(...args: Parameters) => any} */ + return (x, ...args) => { + return template_fn(jl(x, ...args)) + } + } + + /** @type {(...args: Parameters) => any} */ + return function jl_and_match(x, ...args) { + return template_fn(jl(x, ...args)).match(cursor, verbose) + } + } +} + +/** + * @param {Parameters[0]} template_creator + */ +let make_beautiful_specific_matcher = (template_creator) => { + let template_fn = create_specific_template_maker(template_creator) + return function match(cursor, verbose = false) { + if (cursor == null) { + /** @type {(...args: Parameters) => any} */ + return (x, ...args) => { + return template_fn(jl(x, ...args)) + } + } + + /** @type {(...args: Parameters) => any} */ + return function jl_and_match(x, ...args) { + return template_fn(jl(x, ...args)).match(cursor, verbose) + } + } +} + +let match_for_binding = make_beautiful_specific_matcher((x) => jl_dynamic`[i for i in i ${x}]`) +let match_assignee = make_beautiful_specific_matcher((x) => jl_dynamic`${x} = nothing`) +let match_function_definition_argument = make_beautiful_specific_matcher((x) => jl_dynamic`function f(${x}) end`) +let match_function_call_argument = make_beautiful_specific_matcher((x) => jl_dynamic`f(${x})`) +let match_function_call_named_argument = make_beautiful_specific_matcher((x) => jl_dynamic`f(; ${x})`) + +/** + * @param {TreeCursor | SyntaxNode} cursor + * @param {any} doc + * @param {ScopeState} scopestate + * @param {boolean} [verbose] + * @returns {ScopeState} + */ +let explorer_function_definition_argument = (cursor, doc, scopestate, verbose = false) => { + let match = null + + if ((match = match_function_call_argument(cursor)`; ${t.many("named_args")}`)) { + // "Parameters", the `y, z` in `function f(x; y, z) end` + let { named_args = [] } = match + for (let { node: named_arg } of named_args) { + scopestate = explorer_function_definition_argument(named_arg, doc, scopestate, verbose) + } + return scopestate + } else if ((match = match_function_definition_argument(cursor)`${t.Identifier}`)) { + return scopestate_add_definition(scopestate, doc, cursor) + } else if ((match = match_function_definition_argument(cursor)`${t.as("subject")}...`)) { + // `function f(x...)` => ["x"] + return explore_pattern(match.subject, doc, scopestate, null, verbose) + } else if ((match = match_function_definition_argument(cursor)`${t.as("name")} = ${t.as("value")}`)) { + // `function f(x = 10)` => ["x"] + let { name, value } = match + scopestate = explore_pattern(name, doc, scopestate, value.to, verbose) + scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + return scopestate + } else if ( + (match = match_function_definition_argument(cursor)`${t.as("name")}::${t.as("type")}`) ?? + (match = match_function_definition_argument(cursor)`${t.as("name")}:`) ?? + // (match = match_function_definition_argument(cursor)`${t.as("name")}::`) ?? + (match = match_function_definition_argument(cursor)`::${t.as("type")}`) + ) { + let { name, type } = match + if (name) scopestate = explore_pattern(name, doc, scopestate, type.to, verbose) + if (type) scopestate = explore_variable_usage(type.cursor(), doc, scopestate, verbose) + return scopestate + } else { + // Fall back to "just explore pattern"... + // There is more overlap between function arguments and patterns than I use now, I think + scopestate = explore_pattern(cursor, doc, scopestate) + + verbose && console.warn("UNKNOWN FUNCTION DEFINITION ARGUMENT:", cursor.toString()) + return scopestate + } +} + +/** + * @param {TreeCursor | SyntaxNode} node + * @param {any} doc + * @param {ScopeState} scopestate + * @param {number?} valid_from + * @param {boolean} [verbose] + * @returns {ScopeState} + */ +let explore_pattern = (node, doc, scopestate, valid_from = null, verbose = false) => { + let match = null + + verbose && console.group("Explorering pattern:", node.toString()) + try { + if ((match = match_assignee(node)`${t.Identifier}`)) { + verbose && console.log("It's an identifier, adding it to the scope") + return scopestate_add_definition(scopestate, doc, node, valid_from) + } else if ((match = match_assignee(node)`${t.as("object")}::${t.as("type")}`)) { + let { object, type } = match + scopestate = explore_variable_usage(type.cursor(), doc, scopestate, verbose) + scopestate = scopestate_add_definition(scopestate, doc, object) + return scopestate + } else if ((match = match_assignee(node)`${t.as("subject")}...`)) { + // `x... = [1,2,3]` => ["x"] + return explore_pattern(match.subject, doc, scopestate, valid_from, verbose) + } else if ((match = match_function_definition_argument(node)`${t.as("name")} = ${t.as("value")}`)) { + let { name, value } = match + scopestate = explore_pattern(name, doc, scopestate, value.from, verbose) + scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + return scopestate + } else if ((match = match_assignee(node)`(; ${t.many("named_tuples")})`)) { + // `(; x, y) = z` => ["x", "y"] + let { named_tuples } = match + for (let name of named_tuples) { + scopestate = explore_pattern(name.node.cursor(), doc, scopestate, valid_from, verbose) + } + return scopestate + } else if ( + (match = match_assignee(node)`${t.as("first")}, ${t.many("rest")}`) ?? + (match = match_assignee(node)`(${t.as("first")}, ${t.many("rest")})`) + ) { + // console.warn("Tuple assignment... but the bad one") + for (let { node: name } of [{ node: match.first }, ...(match.rest ?? [])]) { + scopestate = explore_pattern(name.cursor(), doc, scopestate, valid_from, verbose) + } + return scopestate + } else if ((match = match_julia(node)`${t.as("prefix")}${t.as("string", t.String)}`)) { + // This one is also a bit enigmatic, but `t.String` renders in the template as `"..."`, + // so the template with match things that look like `prefix"..."` + let { prefix, string } = match + let prefix_string = doc.sliceString(prefix.from, prefix.to) + + if (prefix_string === "var") { + let name = doc.sliceString(string.from + 1, string.to - 1) + if (name.length !== 0) { + scopestate.definitions.set(name, { + from: node.from, + to: node.to, + valid_from: node.to, + }) + } + } else { + scopestate = explore_variable_usage("cursor" in node ? node.cursor() : node, doc, scopestate, verbose) + } + return scopestate + } else if ((match = match_assignee(node)`${t.as("object")}[${t.as("property")}]`)) { + let { object, property } = match + scopestate = explore_variable_usage(object.cursor(), doc, scopestate, verbose) + if (property) scopestate = explore_variable_usage(property.cursor(), doc, scopestate, verbose) + return scopestate + } else if ((match = match_assignee(node)`${t.as("object")}.${t.as("property")}`)) { + let { object, property } = match + scopestate = explore_variable_usage(object.cursor(), doc, scopestate, verbose) + return scopestate + } else { + verbose && console.warn("UNKNOWN PATTERN:", node.toString(), doc.sliceString(node.from, node.to)) + return scopestate + } + } finally { + verbose && console.groupEnd() + } +} + +/** + * Explores the definition part of a struct or such. + * Takes care of defining that actual name, defining type parameters, + * and using all the types used. + * + * It returns an inner and an outer scope state. + * The inner scope state is for code "inside" the struct, which has access to the implicitly created types. + * Outer scope is only the actual defined name, so will always exist of just one definition and no usages. + * This distinction is so the created types don't escape outside the struct. + * Usages all go in the inner scope. + * + * @param {TreeCursor} cursor + * @param {any} doc + * @param {ScopeState} scopestate + * @param {boolean} [verbose] + * @returns {{ inner: ScopeState, outer: ScopeState }} + */ +let explore_definition = function (cursor, doc, scopestate, verbose = false) { + let match = null + + if (cursor.name === "Definition" && cursor.firstChild()) { + try { + return explore_definition(cursor, doc, scopestate) + } finally { + cursor.parent() + } + } else if (cursor.name === "Identifier") { + return { + inner: scopestate_add_definition(scopestate, doc, cursor), + outer: scopestate_add_definition(fresh_scope(), doc, cursor), + } + } else if ((match = match_julia(cursor)`${t.as("subject")}{ ${t.many("parameters")} }`)) { + // A{B} + let { subject, parameters } = match + let outer = fresh_scope() + if (subject) { + let subject_explored = explore_definition(subject.cursor(), doc, scopestate) + outer = subject_explored.outer + scopestate = subject_explored.inner + } + for (let { node: parameter } of parameters) { + // Yes, when there is a type parameter in the definition itself (so not after `::`), + // it implies a new type parameter being implicitly instanciated. + let { inner: parameter_inner } = explore_definition(parameter.cursor(), doc, scopestate) + scopestate = parameter_inner + } + return { inner: scopestate, outer: outer } + } else if ((match = match_julia(cursor)`${t.as("subject")} <: ${t.maybe(t.as("type"))}`)) { + let { subject, type } = match + let outer = fresh_scope() + if (subject) ({ outer, inner: scopestate } = explore_definition(subject.cursor(), doc, scopestate)) + if (type) scopestate = explore_variable_usage(type.cursor(), doc, scopestate) + return { inner: scopestate, outer: outer } + } else { + verbose && console.warn(`Unknown thing in definition: "${doc.sliceString(cursor.from, cursor.to)}", "${cursor.toString()}"`) + return { inner: scopestate, outer: fresh_scope() } + } +} + +let match_julia = make_beautiful_matcher(template) + +/** + * @param {TreeCursor} cursor + * @param {any} doc + * @param {ScopeState} scopestate + * @param {boolean} [verbose] + * @returns {ScopeState} + */ +let explore_macro_identifier = (cursor, doc, scopestate, verbose = false) => { + let match = null + + let match_macro_identifier = make_beautiful_specific_matcher((x) => jl_dynamic`${x} x y z`) + + if ((match = match_macro_identifier(cursor)`${t.as("macro", jl`@${t.any}`)}`)) { + let { macro } = match + let name = doc.sliceString(macro.from, macro.to) + scopestate.usages.push({ + usage: macro, + definition: scopestate.definitions.get(name) ?? null, + name: name, + }) + return scopestate + } else if ((match = match_macro_identifier(cursor)`${t.as("object")}.@${t.as("macro")}`)) { + let { object } = match + let name = doc.sliceString(object.from, object.to) + scopestate.usages.push({ + usage: object, + definition: scopestate.definitions.get(name) ?? null, + name: name, + }) + return scopestate + } else if ((match = match_macro_identifier(cursor)`@${t.as("object")}.${t.as("macro")}`)) { + let { object } = match + let name = doc.sliceString(object.from, object.to) + scopestate.usages.push({ + usage: object, + definition: scopestate.definitions.get(name) ?? null, + name: name, + }) + return scopestate + } else { + verbose && console.warn("Mwep mweeeep", cursor.toString()) + return scopestate + } +} + +/** + * @returns {ScopeState} + */ +let fresh_scope = () => { + return { + usages: [], + definitions: new Map(), + locals: [], + } +} + +/** + * Currently this clones a scope state, except for the usages. + * The reason is skips the usages is a premature optimisation. + * We don't need them in the inner scope, but we just as well could leave them on + * (as they won't do any harm either way) + * + * @param {ScopeState} scopestate + * @returns {ScopeState} + */ +let lower_scope = (scopestate) => { + return { + usages: [], + definitions: new Map(scopestate.definitions), + locals: [], + } +} + +/** + * For use in combination with `lower_scope`. + * This will take an inner scope and merge only the usages into the outer scope. + * So we see the usages of the inner scope, but the definitions don't exist in the outer scope. + * + * @param {ScopeState} nested_scope + * @param {ScopeState} scopestate + * @param {number} [nested_scope_validity] + * @returns {ScopeState} + */ +let raise_scope = (nested_scope, scopestate, nested_scope_validity = undefined) => { + return { + usages: [...scopestate.usages, ...nested_scope.usages], + definitions: scopestate.definitions, + locals: [ + // TODO: Disabled because of performance problems, see https://github.com/fonsp/Pluto.jl/pull/1925 + // ...(nested_scope_validity === null + // ? [] + // : Array.from(nested_scope.definitions) + // .filter(([name, _]) => !scopestate.definitions.has(name)) + // .map(([name, definition]) => ({ + // name, + // definition, + // validity: { + // from: definition.valid_from, + // to: nested_scope_validity, + // }, + // }))), + // ...nested_scope.locals, + // ...scopestate.locals, + ], + } +} + +/** + * @param {ScopeState} scopestate + * @param {any} doc + * @param {SyntaxNode | TreeCursor} node + * @param {number?} valid_from + */ +let scopestate_add_definition = (scopestate, doc, node, valid_from = null) => { + valid_from = valid_from === null ? node.to : valid_from + scopestate.definitions.set(doc.sliceString(node.from, node.to), { + from: node.from, + to: node.to, + valid_from, + }) + return scopestate +} + +/** + * @param {TreeCursor | SyntaxNode} cursor + * @param {any} doc + * @param {ScopeState} scopestate + * @param {boolean} [verbose] + * @returns {ScopeState} + */ +export let explore_variable_usage = ( + cursor, + doc, + scopestate = { + usages: [], + definitions: new Map(), + locals: [], + }, + verbose = false +) => { + if ("cursor" in cursor) { + // console.trace("`explore_variable_usage()` called with a SyntaxNode, not a TreeCursor") + cursor = cursor.cursor() + } + + let start_node = null + if (verbose) { + console.group(`Explorer: ${cursor.name}`) + + console.groupCollapsed("Details") + try { + console.log(`Full tree: ${cursor.toString()}`) + console.log("Full text:", doc.sliceString(cursor.from, cursor.to)) + console.log(`scopestate:`, scopestate) + } finally { + console.groupEnd() + } + start_node = cursor.node + } + try { + let match = null + + // Doing these checks in front seems to speed things up a bit. + if ( + cursor.type.is("keyword") || + cursor.name === "SourceFile" || + cursor.name === "BooleanLiteral" || + cursor.name === "Character" || + cursor.name === "String" || + cursor.name === "Number" || + cursor.name === "Comment" || + cursor.name === "BinaryExpression" || + cursor.name === "Operator" || + cursor.name === "MacroArgumentList" || + cursor.name === "ReturnStatement" || + cursor.name === "BareTupleExpression" || + cursor.name === "ParenthesizedExpression" || + cursor.name === "Type" || + cursor.name === "InterpolationExpression" || + cursor.name === "SpreadExpression" || + cursor.name === "CompoundExpression" || + cursor.name === "ParameterizedIdentifier" || + cursor.name === "TypeArgumentList" || + cursor.name === "TernaryExpression" || + cursor.name === "Coefficient" || + cursor.name === "TripleString" || + cursor.name === "RangeExpression" || + cursor.name === "SubscriptExpression" || + cursor.name === "UnaryExpression" || + cursor.name === "ConstStatement" || + cursor.name === "GlobalStatement" || + cursor.name === "ContinueStatement" || + cursor.name === "MatrixExpression" || + cursor.name === "MatrixRow" || + cursor.name === "ArrayExpression" + ) { + for (let subcursor of child_cursors(cursor)) { + scopestate = explore_variable_usage(subcursor, doc, scopestate, verbose) + } + return scopestate + } + + if (cursor.name === "Identifier" || cursor.name === "MacroIdentifier") { + let name = doc.sliceString(cursor.from, cursor.to) + scopestate.usages.push({ + name: name, + usage: { + from: cursor.from, + to: cursor.to, + }, + definition: scopestate.definitions.get(name) ?? null, + }) + return scopestate + } else if ((match = match_julia(cursor)`:${t.any}`)) { + // Nothing, ha! + return scopestate + } else if ((match = match_julia(cursor)`${t.Number}`)) { + // Nothing, ha! + return scopestate + } else if ((match = match_julia(cursor)`${t.String}`)) { + // Nothing, ha! + return scopestate + } else if ((match = match_julia(cursor)`${t.as("object")}.${t.as("property")}`)) { + let { object, property } = match + if (object) scopestate = explore_variable_usage(object.cursor(), doc, scopestate, verbose) + return scopestate + } else if ((match = match_julia(cursor)`${t.as("assignee")} = ${t.maybe(t.as("value"))}`)) { + let { assignee, value } = match + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + if (assignee) scopestate = explore_pattern(assignee.cursor(), doc, scopestate, value?.to ?? null, verbose) + return scopestate + } else if ( + (match = match_julia(cursor)` + ${t.as("macro", t.anything_that_fits(jl`@macro`))}(${t.many("args")}) ${t.maybe(jl`do ${t.maybe(t.many("do_args"))} + ${t.many("do_expressions")} + end`)}} + `) + ) { + let { macro, args = [], do_args, do_expressions } = match + if (macro) explore_macro_identifier(macro.cursor(), doc, scopestate, verbose) + + for (let { node: arg } of args) { + if ((match = match_function_call_argument(arg)`${t.as("name")} = ${t.as("value")}`)) { + let { name, value } = match + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + } else { + scopestate = explore_variable_usage(arg.cursor(), doc, scopestate, verbose) + } + } + + if (do_args && do_expressions) { + // Cheating because lezer-julia isn't up to this task yet + // TODO julia-lezer is up to the task now!! + let inner_scope = lower_scope(scopestate) + + // Don't ask me why, but currently `do (x, y)` is parsed as `DoClauseArguments(ArgumentList(x, y))` + // while an actual argumentslist, `do x, y` is parsed as `DoClauseArguments(BareTupleExpression(x, y))` + let do_args_actually = do_args.firstChild + if (do_args_actually.name === "Identifier") { + inner_scope = scopestate_add_definition(inner_scope, doc, do_args_actually) + } else if (do_args_actually.name === "ArgumentList") { + for (let child of child_nodes(do_args_actually)) { + inner_scope = explorer_function_definition_argument(child, doc, inner_scope) + } + } else if (do_args_actually.name === "BareTupleExpression") { + for (let child of child_nodes(do_args_actually)) { + inner_scope = explorer_function_definition_argument(child, doc, inner_scope) + } + } else { + verbose && console.warn("Unrecognized do args", do_args_actually.toString()) + } + + for (let { node: expression } of do_expressions) { + inner_scope = explore_variable_usage(expression.cursor(), doc, inner_scope, verbose) + } + return raise_scope(inner_scope, scopestate, cursor.to) + } + + return scopestate + } else if ((match = match_julia(cursor)`${t.as("macro", t.anything_that_fits(jl`@macro`))} ${t.many("args")}`)) { + let { macro, args = [] } = match + if (macro) explore_macro_identifier(macro.cursor(), doc, scopestate, verbose) + + for (let { node: arg } of args) { + scopestate = explore_variable_usage(arg.cursor(), doc, scopestate, verbose) + } + return scopestate + } else if ( + (match = match_julia(cursor)` + struct ${t.as("defined_as")} + ${t.many("expressions")} + end + `) ?? + (match = match_julia(cursor)` + mutable struct ${t.as("defined_as")} + ${t.many("expressions")} + end + `) + ) { + let { defined_as, expressions = [] } = match + defined_as = narrow(defined_as) + + let inner_scope = lower_scope(scopestate) + let outer_scope = fresh_scope() + + if (defined_as) ({ inner: inner_scope, outer: outer_scope } = explore_definition(defined_as.cursor(), doc, inner_scope)) + + // Struct body + for (let { node: expression } of expressions) { + if (cursor.name === "Identifier") { + // Nothing, this is just the name inside the struct blegh get it out of here + } else if ((match = match_julia(expression)`${t.as("subject")}::${t.as("type")}`)) { + // We're in X::Y, and Y is a reference + let { subject, type } = match + inner_scope = explore_variable_usage(type.cursor(), doc, inner_scope, verbose) + } else if ((match = match_julia(expression)`${t.as("assignee")} = ${t.as("value")}`)) { + let { assignee, value } = match + + // Yeah... we do the same `a::G` check again + if ((match = match_julia(assignee)`${t.as("subject")}::${t.as("type")}`)) { + let { subject, type } = match + inner_scope = explore_variable_usage(type.cursor(), doc, inner_scope, verbose) + } + inner_scope = explore_variable_usage(value.cursor(), doc, inner_scope, verbose) + } + } + + scopestate = raise_scope(inner_scope, scopestate, cursor.to) + scopestate = merge_scope_state(scopestate, outer_scope) + return scopestate + } else if ((match = match_julia(cursor)`abstract type ${t.as("name")} end`)) { + let { name } = match + if (name) { + let { outer } = explore_definition(name.cursor(), doc, scopestate) + scopestate = merge_scope_state(scopestate, outer) + } + return scopestate + } else if ((match = match_julia(cursor)`quote ${t.many("body")} end`) ?? (match = match_julia(cursor)`:(${t.many("body")})`)) { + // We don't use the match because I made `go_through_quoted_expression_looking_for_interpolations` + // to take a cursor at the quoted expression itself + for (let interpolation_cursor of go_through_quoted_expression_looking_for_interpolations(cursor)) { + scopestate = explore_variable_usage(interpolation_cursor, doc, scopestate, verbose) + } + return scopestate + } else if ( + (match = match_julia(cursor)` + module ${t.as("name")} + ${t.many("expressions")} + end + `) + ) { + let { name, expressions = [] } = match + + if (name) scopestate = scopestate_add_definition(scopestate, doc, name) + + let module_scope = fresh_scope() + for (let { node: expression } of expressions) { + module_scope = explore_variable_usage(expression.cursor(), doc, module_scope) + } + // We still merge the module scopestate with the global scopestate, but only the usages that don't escape. + // (Later we can have also shadowed definitions for the dimming of unused variables) + scopestate = merge_scope_state(scopestate, { + usages: Array.from(module_scope.usages).filter((x) => x.definition != null), + definitions: new Map(), + locals: [], + }) + + for (let { node: expression } of expressions) { + scopestate = explore_variable_usage(expression.cursor(), doc, scopestate) + } + return scopestate + } else if ((match = match_julia(cursor)`${t.as("prefix")}${t.as("string", t.String)}`)) { + // This one is also a bit enigmatic, but `t.String` renders in the template as `"..."`, + // so the template with match things that look like `prefix"..."` + let { prefix, string } = match + let prefix_string = doc.sliceString(prefix.from, prefix.to) + + if (prefix_string === "var") { + let name = doc.sliceString(string.from + 1, string.to - 1) + if (name.length !== 0) { + scopestate.usages.push({ + name: name, + usage: { + from: cursor.from, + to: cursor.to, + }, + definition: scopestate.definitions.get(name) ?? null, + }) + } + return scopestate + } else { + let name = `@${prefix_string}_str` + scopestate.usages.push({ + name: name, + usage: { + from: prefix.from, + to: prefix.to, + }, + definition: scopestate.definitions.get(name) ?? null, + }) + } + return scopestate + } else if ((match = match_julia(cursor)`${t.Number}${t.as("unit")}`)) { + // This isn't that useful, just wanted to test (and show off) the template + return explore_variable_usage(match.unit.cursor(), doc, scopestate, verbose) + } else if ( + (match = match_julia(cursor)`import ${t.any}: ${t.many("specifiers")}`) ?? + (match = match_julia(cursor)`using ${t.any}: ${t.many("specifiers")}`) + ) { + let { specifiers = [] } = match + let match_selected_import_specifier = make_beautiful_specific_matcher((x) => jl_dynamic`import X: ${x}`) + + for (let { node: specifier } of specifiers) { + if ((match = match_selected_import_specifier(specifier)`${t.as("name")} as ${t.as("alias")}`)) { + let { alias } = match + scopestate = scopestate_add_definition(scopestate, doc, alias) + } else if ((match = match_selected_import_specifier(specifier)`${t.as("name", t.Identifier)}`)) { + let { name } = match + scopestate = scopestate_add_definition(scopestate, doc, name) + } else if ((match = match_selected_import_specifier(specifier)`@${t.any}`)) { + scopestate = scopestate_add_definition(scopestate, doc, specifier) + } else { + verbose && console.warn("Hmmmm, I don't know what to do with this selected import specifier:", specifier.toString()) + } + } + return scopestate + } else if ((match = match_julia(cursor)`import ${t.many("specifiers")}`)) { + let { specifiers = [] } = match + + let match_import_specifier = make_beautiful_specific_matcher((x) => jl_dynamic`import ${x}`) + + for (let { node: specifier } of specifiers) { + if ((match = match_import_specifier(specifier)`${t.any} as ${t.as("alias")}`)) { + let { alias } = match + scopestate = scopestate_add_definition(scopestate, doc, alias) + } else if ((match = match_import_specifier(specifier)`${t.as("package")}.${t.as("name", t.Identifier)}`)) { + scopestate = scopestate_add_definition(scopestate, doc, match.name) + } else if ((match = match_import_specifier(specifier)`.${t.as("scoped")}`)) { + let scopedmatch = null + while ((scopedmatch = match_import_specifier(match.scoped)`.${t.as("scoped")}`)) { + match = scopedmatch + } + scopestate = scopestate_add_definition(scopestate, doc, match.scoped) + } else if ((match = match_import_specifier(specifier)`${t.as("name", t.Identifier)}`)) { + scopestate = scopestate_add_definition(scopestate, doc, match.name) + } else { + verbose && console.warn("Hmmm, I don't know what to do with this import specifier:", specifier) + } + } + return scopestate + } else if ((match = match_julia(cursor)`using ${t.many()}`)) { + // Can't care less + return scopestate + } else if ( + (match = match_julia(cursor)` + for ${t.many("bindings", t.something_with_the_same_type_as(jl`x in y`))}; + ${t.many("expressions")} + end + `) + ) { + let for_loop_binding_template = create_specific_template_maker((arg) => jl_dynamic`for ${arg}; x end`) + let for_loop_binding_match_julia = + (cursor) => + (...args) => { + // @ts-ignore + return for_loop_binding_template(jl(...args)).match(cursor) + } + + let { bindings, expressions } = match + let inner_scope = lower_scope(scopestate) + + for (let { node: binding } of bindings) { + let match = null + if ( + (match = for_loop_binding_match_julia(binding)`${t.as("name")} in ${t.as("range")}`) ?? + (match = for_loop_binding_match_julia(binding)`${t.as("name")} ∈ ${t.as("range")}`) ?? + (match = for_loop_binding_match_julia(binding)`${t.as("name")} = ${t.as("range")}`) + ) { + let { name, range } = match + if (range) inner_scope = explore_variable_usage(range.cursor(), doc, inner_scope, verbose) + if (name) inner_scope = explore_pattern(name, doc, inner_scope, range?.to ?? null, verbose) + } else { + verbose && console.warn("Unrecognized for loop binding", binding.toString()) + } + } + + for (let { node: expression } of expressions) { + inner_scope = explore_variable_usage(expression.cursor(), doc, inner_scope, verbose) + } + + return raise_scope(inner_scope, scopestate, cursor.to) + } else if ( + (match = match_julia(cursor)` + ${t.as("callee")}(${t.many("args")}) ${t.maybe(jl`do ${t.maybe(t.many("do_args"))} + ${t.many("do_expressions")} + end`)} + `) ?? + (match = match_julia(cursor)` + ${t.as("callee")}.(${t.many("args")}) + `) + ) { + let { callee, args = [], do_args = [], do_expressions = [] } = match + + scopestate = explore_variable_usage(callee.cursor(), doc, scopestate, verbose) + + for (let { node: arg } of args) { + let match = null + if ((match = match_function_call_argument(arg)`; ${t.many("named_args")}`)) { + // "Parameters", the part in `f(x; y, z)` after the `;` + let { named_args = [] } = match + for (let { node: named_arg } of named_args) { + let match = null + if ((match = match_function_call_named_argument(named_arg)`${t.as("name")} = ${t.as("value")}`)) { + let { name, value } = match + scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + } else { + scopestate = explore_variable_usage(named_arg.cursor(), doc, scopestate, verbose) + } + } + } else if ((match = match_function_call_argument(arg)`${t.as("name")} = ${t.as("value")}`)) { + let { name, value } = match + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + } else if ((match = match_function_call_argument(arg)`${t.as("result")} ${t.many("clauses", t.anything_that_fits(jl`for x = y`))}`)) { + let { result, clauses } = match + let nested_scope = lower_scope(scopestate) + // Because of the `t.anything_that_fits`, we can now match different `for x ? y`'s and `if x`s manually. + // There might be a way to express this in the template, but this keeps templates a lot simpler yet powerful. + for (let { node: for_binding } of clauses) { + let match = null + if ( + (match = match_for_binding(for_binding)`for ${t.as("variable")} = ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")} in ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")} ∈ ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")}`) + ) { + let { variable, value } = match + + if (value) nested_scope = explore_variable_usage(value.cursor(), doc, nested_scope, verbose) + if (variable) nested_scope = explore_pattern(variable, doc, nested_scope) + } else if ((match = match_for_binding(for_binding)`if ${t.maybe(t.as("if"))}`)) { + let { if: node } = match + if (node) nested_scope = explore_variable_usage(node.cursor(), doc, nested_scope, verbose) + } else { + verbose && console.log("Hmmm, can't parse for binding", for_binding) + } + } + + nested_scope = explore_variable_usage(result.cursor(), doc, nested_scope, verbose) + + return raise_scope(nested_scope, scopestate, cursor.to) + } else { + scopestate = explore_variable_usage(arg.cursor(), doc, scopestate, verbose) + } + } + + let inner_scope = lower_scope(scopestate) + + for (let { node: arg } of do_args) { + inner_scope = explorer_function_definition_argument(arg, doc, inner_scope) + } + for (let { node: expression } of do_expressions) { + inner_scope = explore_variable_usage(expression.cursor(), doc, inner_scope, verbose) + } + return raise_scope(inner_scope, scopestate, cursor.to) + } else if ((match = match_julia(cursor)`(${t.many("tuple_elements")},)`)) { + // TODO.. maybe? `(x, g = y)` is a "ParenthesizedExpression", but lezer parses it as a tuple... + // For now I fix it here hackily by checking if there is only NamedFields + + let { tuple_elements = [] } = match + + let match_tuple_element = make_beautiful_specific_matcher((arg) => jl_dynamic`(${arg},)`) + + let is_named_field = tuple_elements.map(({ node }) => match_tuple_element(cursor)`${t.Identifier} = ${t.any}` != null) + + if (is_named_field.every((x) => x === true) || is_named_field.every((x) => x === false)) { + // Valid tuple, either named or unnamed + for (let { node: element } of tuple_elements) { + let match = null + if ((match = match_tuple_element(cursor)`${t.as("name")} = ${t.as("value")}`)) { + let { name, value } = match + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + } else { + scopestate = explore_variable_usage(element.cursor(), doc, scopestate, verbose) + } + } + } else { + // Sneaky! Actually an expression list 😏 + for (let { node: element } of tuple_elements) { + let match = null + if ((match = match_tuple_element(cursor)`${t.as("name")} = ${t.as("value")}`)) { + // 🚨 actually an assignment 🚨 + let { name, value } = match + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + if (name) scopestate = scopestate_add_definition(scopestate, doc, name, value?.to ?? null) + } else { + scopestate = explore_variable_usage(element.cursor(), doc, scopestate, verbose) + } + } + } + return scopestate + } else if ( + (match = match_julia(cursor)`(${t.many("args")}) -> ${t.many("body")}`) ?? + (match = match_julia(cursor)`${t.as("arg")} -> ${t.many("body")}`) ?? + (match = match_julia(cursor)`${t.as("name")}(${t.many("args")})::${t.as("return_type")} = ${t.many("body")}`) ?? + (match = match_julia(cursor)`${t.as("name")}(${t.many("args")}) = ${t.many("body")}`) ?? + (match = match_julia(cursor)`${t.as("name")}(${t.many("args")}) = ${t.many("body", t.anything_that_fits(jl`x, y`))}`) ?? + (match = match_julia(cursor)` + function ${t.as("name")}(${t.many("args")})::${t.as("return_type")} where ${t.as("type_param")} + ${t.many("body")} + end + `) ?? + (match = match_julia(cursor)` + function ${t.as("name")}(${t.many("args")}) where ${t.as("type_param")} + ${t.many("body")} + end + `) ?? + (match = match_julia(cursor)` + function ${t.as("name")}(${t.many("args")})::${t.as("return_type")} + ${t.many("body")} + end + `) ?? + (match = match_julia(cursor)` + function ${t.as("name")}(${t.many("args")}) + ${t.many("body")} + end + `) ?? + (match = match_julia(cursor)` + function ${t.as("name", t.Identifier)} end + `) ?? + // Putting macro definitions here too because they are very similar + (match = match_julia(cursor)`macro ${t.as("macro_name")} end`) ?? + (match = match_julia(cursor)` + macro ${t.as("macro_name")}(${t.many("args")}) + ${t.many("body")} + end + `) + ) { + let { name, macro_name, arg, args = [], return_type, type_param, body = [] } = match + + if (arg) { + args.push({ node: arg }) + } + + if (name) { + scopestate = scopestate_add_definition(scopestate, doc, name) + } else if (macro_name) { + scopestate.definitions.set(`@${doc.sliceString(macro_name.from, macro_name.to)}`, { + from: macro_name.from, + to: macro_name.to, + valid_from: macro_name.to, + }) + } + + let inner_scope = lower_scope(scopestate) + if (type_param) { + let match_where_types = make_beautiful_specific_matcher((x) => jl_dynamic`function X() where ${x} end`) + let match_where_type = make_beautiful_specific_matcher((x) => jl_dynamic`function X() where {${x}} end`) + + let type_params = [{ node: type_param }] + let multiple_types_match = match_where_types(type_param)`{${t.many("type_params")}}` + if (multiple_types_match) { + type_params = multiple_types_match.type_params + } + + for (let { node: type_param } of type_params) { + let match = null + if ((match = match_where_type(type_param)`${t.as("defined", t.Identifier)} <: ${t.as("parent_type")}`)) { + let { defined, parent_type } = match + inner_scope = explore_variable_usage(parent_type, doc, inner_scope, verbose) + inner_scope = scopestate_add_definition(inner_scope, doc, defined) + } else if ((match = match_where_type(type_param)`${t.as("defined", t.Identifier)}`)) { + let { defined } = match + inner_scope = scopestate_add_definition(inner_scope, doc, defined) + } else { + verbose && console.warn(`Can't handle type param:`, type_param) + } + } + } + + if (return_type) { + inner_scope = explore_variable_usage(narrow(return_type).cursor(), doc, inner_scope, verbose) + } + for (let { node: arg } of args) { + inner_scope = explorer_function_definition_argument(arg.cursor(), doc, inner_scope, verbose) + } + for (let { node: expression } of body) { + inner_scope = explore_variable_usage(expression.cursor(), doc, inner_scope, verbose) + } + return raise_scope(inner_scope, scopestate, cursor.to) + } else if ( + (match = match_julia(cursor)` + let ${t.many("assignments", jl`${t.as("assignee")} = ${t.as("value")}`)} + ${t.many("body", t.any)} + end + `) + ) { + let { assignments = [], body = [] } = match + let innerscope = lower_scope(scopestate) + for (let { + match: { assignee, value }, + } of assignments) { + // Explorer lefthandside in inner scope + if (assignee) innerscope = explore_pattern(assignee, doc, innerscope, value?.to ?? null, verbose) + // Explorer righthandside in the outer scope + if (value) scopestate = explore_variable_usage(value.cursor(), doc, scopestate, verbose) + } + // Explorer body in innerscope + for (let { node: line } of body) { + innerscope = explore_variable_usage(line.cursor(), doc, innerscope, verbose) + } + return raise_scope(innerscope, scopestate, cursor.to) + } else if ( + // A bit hard to see from the template, but these are array (and generator) comprehensions + // e.g. [x for x in y] + (match = match_julia(cursor)`[ + ${t.as("result")} + ${t.many("clauses", t.anything_that_fits(jl`for x = y`))} + ]`) ?? + // Are there syntax differences between Array or Generator expressions? + // For now I treat them the same... + // (Also this is one line because lezer doesn't parse multiline generator expressions yet) + (match = match_julia(cursor)`(${t.as("result")} ${t.many("clauses", t.anything_that_fits(jl`for x = y`))})`) + ) { + let { result, clauses } = match + + let nested_scope = lower_scope(scopestate) + + // Because of the `t.anything_that_fits`, we can now match different `for x in/∈/= y`-s and `if x`-s manually. + // There might be a way to express this in the template, but this keeps templates a lot simpler yet powerful. + for (let { node: for_binding } of clauses) { + let match = null + if ( + (match = match_for_binding(for_binding)`for ${t.as("variable")} = ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")} in ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")} ∈ ${t.maybe(t.as("value"))}`) ?? + (match = match_for_binding(for_binding)`for ${t.as("variable")}`) + ) { + let { variable, value } = match + + if (value) nested_scope = explore_variable_usage(value.cursor(), doc, nested_scope, verbose) + if (variable) nested_scope = explore_pattern(variable, doc, nested_scope) + } else if ((match = match_for_binding(for_binding)`if ${t.maybe(t.as("if"))}`)) { + let { if: node } = match + if (node) nested_scope = explore_variable_usage(node.cursor(), doc, nested_scope, verbose) + } else { + verbose && console.warn("Hmmm, can't parse for binding", for_binding) + } + } + + nested_scope = explore_variable_usage(result.cursor(), doc, nested_scope, verbose) + + return raise_scope(nested_scope, scopestate, cursor.to) + } else { + if (verbose) { + console.groupCollapsed(`Cycling through all children of`, cursor.name) + console.log(`text:`, doc.sliceString(cursor.from, cursor.to)) + console.groupEnd() + } + + // In most cases we "just" go through all the children separately + for (let subcursor of child_cursors(cursor)) { + scopestate = explore_variable_usage(subcursor, doc, scopestate, verbose) + } + return scopestate + } + } finally { + verbose && console.groupEnd() + } +} + +/** + * @type {StateField} + */ +export let ScopeStateField = StateField.define({ + create(state) { + try { + let cursor = syntaxTree(state).cursor() + let scopestate = explore_variable_usage(cursor, state.doc, undefined) + return scopestate + } catch (error) { + console.error("Something went wrong while parsing variables...", error) + return { + usages: [], + definitions: new Map(), + locals: [], + } + } + }, + + update(value, tr) { + try { + if (syntaxTree(tr.state) != syntaxTree(tr.startState)) { + let cursor = syntaxTree(tr.state).cursor() + let scopestate = explore_variable_usage(cursor, tr.state.doc) + return scopestate + } else { + return value + } + } catch (error) { + console.error("Something went wrong while parsing variables...", error) + return { + usages: [], + definitions: new Map(), + locals: [], + } + } + }, +}) diff --git a/frontend/components/CellInput/tab_help_plugin.js b/frontend/components/CellInput/tab_help_plugin.js new file mode 100644 index 0000000000..a83368a481 --- /dev/null +++ b/frontend/components/CellInput/tab_help_plugin.js @@ -0,0 +1,78 @@ +import { open_pluto_popup } from "../../common/open_pluto_popup.js" +import { ViewPlugin, StateEffect, StateField } from "../../imports/CodemirrorPlutoSetup.js" +import _ from "../../imports/lodash.js" +import { html } from "../../imports/Preact.js" + +/** @type {any} */ +const TabHelpEffect = StateEffect.define() +const TabHelp = StateField.define({ + create() { + return false + }, + update(value, tr) { + for (let effect of tr.effects) { + if (effect.is(TabHelpEffect)) return effect.value + } + return value + }, +}) + +/** @type {any} */ +export const LastFocusWasForcedEffect = StateEffect.define() +const LastFocusWasForced = StateField.define({ + create() { + return false + }, + update(value, tr) { + for (let effect of tr.effects) { + if (effect.is(LastFocusWasForcedEffect)) return effect.value + } + return value + }, +}) + +export const tab_help_plugin = ViewPlugin.define( + (view) => ({ + setready: (x) => + requestIdleCallback(() => { + view.dispatch({ + effects: [TabHelpEffect.of(x)], + }) + }), + }), + { + provide: (p) => [TabHelp, LastFocusWasForced], + eventObservers: { + focus: function (event, view) { + // The next key should trigger the popup + this.setready(true) + }, + blur: function (event, view) { + this.setready(false) + requestIdleCallback(() => { + view.dispatch({ + effects: [LastFocusWasForcedEffect.of(false)], + }) + }) + }, + click: function (event, view) { + // This means you are not doing keyboard navigation :) + this.setready(false) + }, + keydown: function (event, view) { + if (event.key == "Tab") { + if (view.state.field(TabHelp) && !view.state.field(LastFocusWasForced) && !view.state.readOnly) { + open_pluto_popup({ + type: "info", + source_element: view.dom, + body: html`Press Esc and then Tab to continue navigation. skkrt!`, + }) + this.setready(false) + } + } else { + this.setready(false) + } + }, + }, + } +) diff --git a/frontend/components/CellInput/tests/.gitignore b/frontend/components/CellInput/tests/.gitignore new file mode 100644 index 0000000000..ed9f9cc128 --- /dev/null +++ b/frontend/components/CellInput/tests/.gitignore @@ -0,0 +1 @@ +coverage \ No newline at end of file diff --git a/frontend/components/CellInput/tests/README.md b/frontend/components/CellInput/tests/README.md new file mode 100644 index 0000000000..c8dd93eef5 --- /dev/null +++ b/frontend/components/CellInput/tests/README.md @@ -0,0 +1,14 @@ +# Deno unit tests + +Unit tests for the scopestate explorer (and maybe later more who knows) + +```shell +deno test --import-map=./import_map.json --allow-env +``` + +You can also do coverage, which looks fun but not sure how to interpret it: + +```shell +deno test --import-map=./import_map.json --allow-env --coverage=coverage +deno coverage coverage --include=../scopestate_statefield.js +``` \ No newline at end of file diff --git a/frontend/components/CellInput/tests/import_map.json b/frontend/components/CellInput/tests/import_map.json new file mode 100644 index 0000000000..57a87cf9b4 --- /dev/null +++ b/frontend/components/CellInput/tests/import_map.json @@ -0,0 +1,5 @@ +{ + "imports": { + "../../../imports/lodash.js": "https://deno.land/x/lodash@4.17.15-es/lodash.js" + } +} diff --git a/frontend/components/CellInput/tests/scopestate.test.js b/frontend/components/CellInput/tests/scopestate.test.js new file mode 100644 index 0000000000..5dc05e668c --- /dev/null +++ b/frontend/components/CellInput/tests/scopestate.test.js @@ -0,0 +1,151 @@ +import { jl } from "../lezer_template.js" +import { test_implicit } from "./scopestate_helpers.js" +// @ts-ignore +import chalk from "https://deno.land/x/chalk_deno@v4.1.1-deno/source/index.js" + +let broken = (fn) => { + try { + console.log() + fn() + console.log(chalk.green("BROKEN TEST PASSED???")) + } catch (error) { + console.log(chalk.blue("Broken test failed as expected")) + } +} + +Deno.test("Function call", () => { + test_implicit(jl`global_call(global_argument1, global_argument2...)`) +}) + +Deno.test("Simple definition", () => { + test_implicit(jl`defined = 10`) +}) + +Deno.test("Tuple destructuring", () => { + test_implicit(jl`(defined_1, defined_2, defined_3...) = global_call()`) +}) + +// Need to fix this later +Deno.test("BROKEN Named destructuring", () => { + broken(() => { + test_implicit(jl`(; irrelevant_1=defined_1, irrelevant_2=defined_2) = global_call()`) + }) +}) + +Deno.test("Array comprehension", () => { + test_implicit(jl`(local_x + global_const for local_x in global_xs)`) + test_implicit(jl`( + local_x + local_y + global_const + for local_x in global_xs + for local_y in [local_x, local_x * 2] + )`) + test_implicit(jl`(local_x for local_x in global_xs if local_x > global_const)`) +}) + +Deno.test("BROKEN Array comprehension with comma but VERY WEIRD", () => { + // So... `for x in xs, y in ys` does resolve the `_ in _`'s from right to left... + // Except..... it then specifically "unbinds" the defined variables..... + // So in this case, even though `irrelevant` might be globally defined, + // this will ALWAYS say `irrelevant is not defined`, because it is "overshadowed" by the `for irrelevant in global_ys`. + broken(() => { + test_implicit(jl`(local_x + global_const for local_x in irrelevant, for irrelevant in global_ys)`) + }) +}) + +Deno.test("BROKEN Array comprehension with comma", () => { + broken(() => { + test_implicit(jl`(local_x for global_array in global_array_array, for local_x in global_array)`) + }) +}) + +Deno.test("Function definition", () => { + test_implicit(jl` + function defined_function(local_argument1, local_argument2...; local_argument3, local_argument4...) + local_argument1, local_argument2, local_argument3, local_argument4 + global_var1, global_var2 + end + `) +}) + +Deno.test("Function definition", () => { + test_implicit(jl` + function defined_function(local_argument1 = global_default) + local_argument1 + end + `) +}) + +Deno.test("Function definition where", () => { + test_implicit(jl` + function defined_function(local_argument1) where {local_type} + local_argument1, local_type + end + `) +}) + +Deno.test("Function definition returntype", () => { + test_implicit(jl`begin + function defined_function(local_argument1)::global_type + local_argument1 + end + end`) +}) + +Deno.test("Function expression", () => { + test_implicit(jl`defined_fn = (local_argument1, local_argument2) -> (local_argument1, local_argument2, global_var1, global_var2)`) +}) + +Deno.test("Let block", () => { + test_implicit(jl`defined_outside = let local_let = global_let + local_inside = local_let + local_inside * global_inside + end`) +}) + +Deno.test("Imports", () => { + test_implicit(jl`import defined_module`) + test_implicit(jl`import X: defined_specific1, defined_specific2`) + test_implicit(jl`import X: defined_specific3, irrelevant as defined_alias`) + test_implicit(jl`import X.defined_specific4`) + test_implicit(jl`import X.irrelevant as defined_alias2`) +}) + +Deno.test("Typed struct", () => { + test_implicit(jl`begin + struct defined_struct{local_type} <: global_type{local_type, global_type2} + g + y::global_type3 + z = global_var + x::local_type = global_var2 + end + end`) +}) + +Deno.test("Quotes", () => { + test_implicit(jl`quote + irrelevant_1 = irrelevant_2 + irrelevant_3 = $(global_var) + end`) +}) + +Deno.test("Nested Quotes", () => { + test_implicit(jl`quote + :($irrelevant) + :($$global_var) + end + end`) +}) + +Deno.test("Macros", () => { + test_implicit(jl`global_used.@irrelevant`) + test_implicit(jl`@global_but_not_macro.irrelevant`) + test_implicit(jl`@macro_global`) +}) + +Deno.test("Lonely bare tuple", () => { + test_implicit(jl`defined, = (global_var,)`) +}) + +Deno.test("Very, very lonely arguments", () => { + test_implicit(jl`global_var(;)`) +}) diff --git a/frontend/components/CellInput/tests/scopestate_helpers.js b/frontend/components/CellInput/tests/scopestate_helpers.js new file mode 100644 index 0000000000..638e376f80 --- /dev/null +++ b/frontend/components/CellInput/tests/scopestate_helpers.js @@ -0,0 +1,69 @@ +import { assertEquals as untyped_assertEquals } from "https://deno.land/std@0.123.0/testing/asserts.ts" +import { jl, as_node, as_doc, JuliaCodeObject, as_string } from "../lezer_template.js" +import { explore_variable_usage } from "../scopestate_statefield.js" + +/** + * @template T + * @param {T} a + * @param {T} b + **/ +export let assertEquals = (a, b) => untyped_assertEquals(a, b) + +/** + * @param {import("../scopestate_statefield.js").ScopeState} scopestate + */ +let simplify_scopestate = (scopestate) => { + let { definitions, usages } = scopestate + return { + defined: new Set(Array.from(definitions.keys())), + local_used: new Set(usages.filter((x) => x.definition != null).map((x) => x.name)), + global_used: new Set(usages.filter((x) => x.definition == null).map((x) => x.name)), + } +} + +/** + * @param {import("../lezer_template.js").JuliaCodeObject} input + * @param {{ + * defined?: Array, + * local_used?: Array, + * global_used?: Array, + * }} expected + */ +export let test_scopestate = (input, expected) => { + let scopestate = { + defined: [], + local_used: [], + global_used: [], + } + assertEquals(simplify_scopestate(explore_variable_usage(as_node(input).cursor(), as_doc(input), undefined, false)), { + defined: new Set(expected.defined), + local_used: new Set(expected.local_used), + global_used: new Set(expected.global_used), + }) +} + +/** + * @param {JuliaCodeObject} code + */ +export function test_implicit(code) { + let expected_scopestate = { defined: [], local_used: [], global_used: [] } + + for (let variable of as_string(code).matchAll(/(macro_)?(global|local|defined)(_[a-z0-9_]+)?/g)) { + let [variable_name, is_macro, usage_type] = variable + + if (is_macro != null) { + variable_name = `@${variable_name}` + } + + let index = variable.index + if (usage_type === "global") { + expected_scopestate.global_used.push(variable_name) + } else if (usage_type === "local") { + expected_scopestate.local_used.push(variable_name) + } else if (usage_type === "defined") { + expected_scopestate.defined.push(variable_name) + } + } + + return test_scopestate(code, expected_scopestate) +} diff --git a/frontend/components/CellOutput.js b/frontend/components/CellOutput.js index 5b49ac2daf..8f18417bcb 100644 --- a/frontend/components/CellOutput.js +++ b/frontend/components/CellOutput.js @@ -1,28 +1,41 @@ -import { html, Component, useRef, useLayoutEffect, useContext, useEffect, useMemo } from "../imports/Preact.js" +import { html, Component, useRef, useLayoutEffect, useContext } from "../imports/Preact.js" -import { ErrorMessage } from "./ErrorMessage.js" +import DOMPurify from "../imports/DOMPurify.js" + +import { ErrorMessage, ParseError } from "./ErrorMessage.js" import { TreeView, TableView, DivElement } from "./TreeView.js" -import { add_bonds_listener, set_bound_elements_to_their_value } from "../common/Bond.js" +import { + add_bonds_disabled_message_handler, + add_bonds_listener, + set_bound_elements_to_their_value, + get_input_value, + set_input_value, + eventof, +} from "../common/Bond.js" import { cl } from "../common/ClassTable.js" import { observablehq_for_cells } from "../common/SetupCellEnvironment.js" -import { PlutoBondsContext, PlutoContext, PlutoJSInitializingContext } from "../common/PlutoContext.js" +import { PlutoBondsContext, PlutoActionsContext, PlutoJSInitializingContext } from "../common/PlutoContext.js" import register from "../imports/PreactCustomElement.js" -import { EditorState, EditorView, defaultHighlightStyle } from "../imports/CodemirrorPlutoSetup.js" +import { EditorState, EditorView, defaultHighlightStyle, syntaxHighlighting } from "../imports/CodemirrorPlutoSetup.js" -import { pluto_syntax_colors } from "./CellInput.js" -import { useState } from "../imports/Preact.js" +import { pluto_syntax_colors, ENABLE_CM_MIXED_PARSER } from "./CellInput.js" import hljs from "../imports/highlightjs.js" -import { julia_andrey } from "./CellInput/mixedParsers.js" +import { julia_mixed } from "./CellInput/mixedParsers.js" +import { julia_andrey } from "../imports/CodemirrorPlutoSetup.js" +import { SafePreviewSanitizeMessage } from "./SafePreviewUI.js" + +const prettyAssignee = (assignee) => + assignee && assignee.startsWith("const ") ? html`const ${assignee.slice(6)}` : assignee export class CellOutput extends Component { constructor() { super() this.state = { - error: null, + output_changed_once: false, } this.old_height = 0 @@ -34,8 +47,8 @@ export class CellOutput extends Component { if (document.body.querySelector("pluto-cell:focus-within")) { const cell_outputs_after_focused = document.body.querySelectorAll("pluto-cell:focus-within ~ pluto-cell > pluto-output") // CSS wizardry ✨ if ( - !(document.activeElement.tagName == "SUMMARY") && - (cell_outputs_after_focused.length == 0 || !Array.from(cell_outputs_after_focused).includes(this.base)) + !(document.activeElement?.tagName === "SUMMARY") && + (cell_outputs_after_focused.length === 0 || !Array.from(cell_outputs_after_focused).includes(this.base)) ) { window.scrollBy(0, new_height - this.old_height) } @@ -45,8 +58,14 @@ export class CellOutput extends Component { }) } - shouldComponentUpdate({ last_run_timestamp }) { - return last_run_timestamp !== this.props.last_run_timestamp + shouldComponentUpdate({ last_run_timestamp, sanitize_html }) { + return last_run_timestamp !== this.props.last_run_timestamp || sanitize_html !== this.props.sanitize_html + } + + componentDidUpdate(old_props) { + if (this.props.last_run_timestamp !== old_props.last_run_timestamp) { + this.setState({ output_changed_once: true }) + } } componentDidMount() { @@ -73,9 +92,13 @@ export class CellOutput extends Component { })} translate=${allow_translate} mime=${this.props.mime} + aria-live=${this.state.output_changed_once ? "polite" : "off"} + aria-atomic="true" + aria-relevant="all" + aria-label=${this.props.rootassignee == null ? "Result of unlabeled cell:" : `Result of variable ${this.props.rootassignee}:`} > - ${this.props.rootassignee} - ${this.state.error ? html`
${this.state.error.message}
` : html`<${OutputBody} ...${this.props} />`} + + <${OutputBody} ...${this.props} /> ` } @@ -108,7 +131,7 @@ export let PlutoImage = ({ body, mime }) => { return html`` } -export const OutputBody = ({ mime, body, cell_id, persist_js_state = false, last_run_timestamp }) => { +export const OutputBody = ({ mime, body, cell_id, persist_js_state = false, last_run_timestamp, sanitize_html = true }) => { switch (mime) { case "image/png": case "image/jpg": @@ -125,30 +148,33 @@ export const OutputBody = ({ mime, body, cell_id, persist_js_state = false, last // NOTE: Jupyter doesn't do this, jupyter renders everything directly in pages DOM. // -DRAL if (body.startsWith("` + return sanitize_html ? null : html`<${IframeContainer} body=${body} />` } else { return html`<${RawHTMLContainer} cell_id=${cell_id} body=${body} persist_js_state=${persist_js_state} last_run_timestamp=${last_run_timestamp} + sanitize_html=${sanitize_html} />` } break case "application/vnd.pluto.tree+object": return html`
- <${TreeView} cell_id=${cell_id} body=${body} persist_js_state=${persist_js_state} /> + <${TreeView} cell_id=${cell_id} body=${body} persist_js_state=${persist_js_state} sanitize_html=${sanitize_html} />
` break case "application/vnd.pluto.table+object": - return html` <${TableView} cell_id=${cell_id} body=${body} persist_js_state=${persist_js_state} />` + return html`<${TableView} cell_id=${cell_id} body=${body} persist_js_state=${persist_js_state} sanitize_html=${sanitize_html} />` + break + case "application/vnd.pluto.parseerror+object": + return html`
<${ParseError} cell_id=${cell_id} ...${body} />
` break case "application/vnd.pluto.stacktrace+object": return html`
<${ErrorMessage} cell_id=${cell_id} ...${body} />
` break - body.cell_id case "application/vnd.pluto.divelement+object": - return DivElement({ cell_id, ...body }) + return DivElement({ cell_id, ...body, persist_js_state, sanitize_html }) break case "text/plain": if (body) { @@ -159,13 +185,18 @@ export const OutputBody = ({ mime, body, cell_id, persist_js_state = false, last return html`
` } break - default: + case null: + case undefined: + case "": return html`` break + default: + return html`
🛑
` + break } } -register(OutputBody, "pluto-display", ["mime", "body", "cell_id", "persist_js_state", "last_run_timestamp"]) +register(OutputBody, "pluto-display", ["mime", "body", "cell_id", "persist_js_state", "last_run_timestamp", "sanitize_html"]) let IframeContainer = ({ body }) => { let iframeref = useRef() @@ -174,13 +205,12 @@ let IframeContainer = ({ body }) => { iframeref.current.src = url run(async () => { - await new Promise((resolve) => iframeref.current.addEventListener("load", () => resolve())) + await new Promise((resolve) => iframeref.current.addEventListener("load", () => resolve(null))) /** @type {Document} */ let iframeDocument = iframeref.current.contentWindow.document - /** Grab the - + + + + + + + - - - - + @@ -36,16 +37,20 @@ - - - + + - - + + - - + +
+ +
+ + + \ No newline at end of file diff --git a/frontend/editor.js b/frontend/editor.js index 2d34473896..cb2748f464 100644 --- a/frontend/editor.js +++ b/frontend/editor.js @@ -1,13 +1,227 @@ -import { html, render } from "./imports/Preact.js" +import { html, render, useEffect, useRef, useState } from "./imports/Preact.js" import "./common/NodejsCompatibilityPolyfill.js" -import { Editor } from "./components/Editor.js" +import { Editor, default_path } from "./components/Editor.js" import { available as vscode_available } from "./common/VSCodeApi.js" // remove default stylesheet inserted by VS Code if (vscode_available) { document.head.querySelector("style#_defaultStyles").remove() } +import { FetchProgress, read_Uint8Array_with_progress } from "./components/FetchProgress.js" +import { unpack } from "./common/MsgPack.js" +import { RawHTMLContainer } from "./components/CellOutput.js" +import { ProcessStatus } from "./common/ProcessStatus.js" -// it's like a Rube Goldberg machine -render(html`<${Editor} />`, document.body) +const url_params = new URLSearchParams(window.location.search) + +////////////// +// utils: + +const set_attribute_if_needed = (element, attr, value) => { + if (element.getAttribute(attr) !== value) { + element.setAttribute(attr, value) + } +} +export const set_disable_ui_css = (val) => { + document.body.classList.toggle("disable_ui", val) + set_attribute_if_needed(document.head.querySelector("link[data-pluto-file='hide-ui']"), "media", val ? "all" : "print") +} + +///////////// +// the rest: + +/** + * + * @type {import("./components/Editor.js").LaunchParameters} + */ +const launch_params = { + //@ts-ignore + notebook_id: url_params.get("id") ?? window.pluto_notebook_id, + //@ts-ignore + statefile: url_params.get("statefile") ?? window.pluto_statefile, + //@ts-ignore + statefile_integrity: url_params.get("statefile_integrity") ?? window.pluto_statefile_integrity, + //@ts-ignore + notebookfile: url_params.get("notebookfile") ?? window.pluto_notebookfile, + //@ts-ignore + notebookfile_integrity: url_params.get("notebookfile_integrity") ?? window.pluto_notebookfile_integrity, + //@ts-ignore + disable_ui: !!(url_params.get("disable_ui") ?? window.pluto_disable_ui), + //@ts-ignore + preamble_html: url_params.get("preamble_html") ?? window.pluto_preamble_html, + //@ts-ignore + isolated_cell_ids: url_params.has("isolated_cell_id") ? url_params.getAll("isolated_cell_id") : window.pluto_isolated_cell_ids, + //@ts-ignore + binder_url: url_params.get("binder_url") ?? window.pluto_binder_url, + //@ts-ignore + pluto_server_url: url_params.get("pluto_server_url") ?? window.pluto_pluto_server_url, + //@ts-ignore + slider_server_url: url_params.get("slider_server_url") ?? window.pluto_slider_server_url, + //@ts-ignore + recording_url: url_params.get("recording_url") ?? window.pluto_recording_url, + //@ts-ignore + recording_url_integrity: url_params.get("recording_url_integrity") ?? window.pluto_recording_url_integrity, + //@ts-ignore + recording_audio_url: url_params.get("recording_audio_url") ?? window.pluto_recording_audio_url, +} + +const truthy = (x) => x === "" || x === "true" +const falsey = (x) => x === "false" + +const from_attribute = (element, name) => { + const val = element.getAttribute(name) + if (name === "disable_ui") { + return truthy(val) ? true : falsey(val) ? false : null + } else if (name === "isolated_cell_id") { + return val == null ? null : val.split(",") + } else { + return val + } +} + +const preamble_html_comes_from_url_params = url_params.has("preamble_url") + +/** + * + * @returns {import("./components/Editor.js").NotebookData} + */ +export const empty_notebook_state = ({ notebook_id }) => ({ + metadata: {}, + notebook_id: notebook_id, + path: default_path, + shortpath: "", + in_temp_dir: true, + process_status: ProcessStatus.starting, + last_save_time: 0.0, + last_hot_reload_time: 0.0, + cell_inputs: {}, + cell_results: {}, + cell_dependencies: {}, + cell_order: [], + cell_execution_order: [], + published_objects: {}, + bonds: {}, + nbpkg: null, + status_tree: null, +}) + +/** + * + * @param {import("./components/Editor.js").NotebookData} state + * @returns {import("./components/Editor.js").NotebookData} + */ +const without_path_entries = (state) => ({ ...state, path: default_path, shortpath: "" }) + +/** + * Fetches the statefile (usually a async resource) in launch_params.statefile + * and makes it available for consuming by `pluto-editor` + * To add custom logic instead, see use Environment.js + * + * @param {import("./components/Editor.js").LaunchParameters} launch_params + * @param {{current: import("./components/Editor.js").EditorState}} initial_notebook_state_ref + * @param {Function} set_ready_for_editor + * @param {Function} set_statefile_download_progress + */ + +const get_statefile = + // @ts-ignore + window?.pluto_injected_environment?.custom_get_statefile?.(read_Uint8Array_with_progress, without_path_entries, unpack) ?? + (async (launch_params, set_statefile_download_progress) => { + const r = await fetch(new Request(launch_params.statefile, { integrity: launch_params.statefile_integrity ?? undefined })) + const data = await read_Uint8Array_with_progress(r, set_statefile_download_progress) + const state = without_path_entries(unpack(data)) + return state + }) +/** + * + * @param {{ + * launch_params: import("./components/Editor.js").LaunchParameters, + * }} props + */ +const EditorLoader = ({ launch_params }) => { + const { statefile, statefile_integrity } = launch_params + const static_preview = statefile != null + + const [statefile_download_progress, set_statefile_download_progress] = useState(null) + + const initial_notebook_state_ref = useRef(empty_notebook_state(launch_params)) + const [error_banner, set_error_banner] = useState(/** @type {import("./imports/Preact.js").ReactElement?} */ (null)) + const [ready_for_editor, set_ready_for_editor] = useState(!static_preview) + + useEffect(() => { + if (!ready_for_editor && static_preview) { + get_statefile(launch_params, set_statefile_download_progress) + .then((state) => { + console.log({ state }) + initial_notebook_state_ref.current = state + set_ready_for_editor(true) + }) + .catch((e) => { + console.error(e) + set_error_banner(html` +
+

Failed to load notebook

+

The statefile failed to download. Original error message:

+
${e.toString()}
+

Launch parameters:

+
${JSON.stringify(launch_params, null, 2)}
+
+ `) + }) + } + }, [ready_for_editor, static_preview, statefile]) + + useEffect(() => { + set_disable_ui_css(launch_params.disable_ui) + }, [launch_params.disable_ui]) + + const preamble_element = launch_params.preamble_html + ? html`<${RawHTMLContainer} body=${launch_params.preamble_html} className=${"preamble"} sanitize_html=${preamble_html_comes_from_url_params} />` + : null + + return error_banner != null + ? error_banner + : ready_for_editor + ? html`<${Editor} initial_notebook_state=${initial_notebook_state_ref.current} launch_params=${launch_params} preamble_element=${preamble_element} />` + : // todo: show preamble html + html` + ${preamble_element} + <${FetchProgress} progress=${statefile_download_progress} /> + ` +} + +// Create a web component for EditorLoader that takes in additional launch parameters as attributes +// possible attribute names are `Object.keys(launch_params)` + +// This means that you can do stuff like: +/* + + + +*/ + +// or: + +/* + + + + +TODO: Make this self-contained (currently depends on various stuff being on window.*, e.g. observablehq library, lodash etc) +*/ + +class PlutoEditorComponent extends HTMLElement { + constructor() { + super() + } + + connectedCallback() { + /** Web components only support text attributes. We deserialize into js here */ + const new_launch_params = Object.fromEntries(Object.entries(launch_params).map(([k, v]) => [k, from_attribute(this, k) ?? v])) + console.log("Launch parameters: ", new_launch_params) + + render(html`<${EditorLoader} launch_params=${new_launch_params} />`, this) + } +} +customElements.define("pluto-editor", PlutoEditorComponent) diff --git a/frontend/error.css b/frontend/error.css new file mode 100644 index 0000000000..26b5fee8c6 --- /dev/null +++ b/frontend/error.css @@ -0,0 +1,71 @@ +* { + box-sizing: border-box; +} + +:root { + --inter-ui-font-stack: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Helvetica, Arial, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", system-ui, sans-serif; + --system-fonts-mono: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + + color-scheme: light dark; + font-family: var(--inter-ui-font-stack); + font-size: 17px; + + --black: black; + --gray1: gray; + --white: white; +} + +@media (prefers-color-scheme: dark) { + :root { + --black: white; + --gray1: #c7c7c7; + --white: black; + } +} + +body { + max-width: 700px; + margin: 0 auto; + margin-top: 3rem; + padding: 1rem; +} + +code, +pre { + font-family: var(--system-fonts-mono); + color: var(--gray1); +} +pre code { + color: inherit; +} +code { + font-size: 0.9rem; +} + +pre { + /* white-space: pre-wrap; */ + overflow: auto; + + border-left: 8px solid #ff002d42; + padding-left: 1rem; +} + +pre:first-line { + font-weight: bolder; + line-height: 2em; + /* font-style: italic; */ + color: var(--black); + + /* padding: 6em; */ + /* display: block; */ +} + +a { + font-weight: bolder; + color: unset; +} + +a:visited { + /* color: red; */ +} diff --git a/frontend/error.jl.html b/frontend/error.jl.html index ade78d481d..434f5c8927 100644 --- a/frontend/error.jl.html +++ b/frontend/error.jl.html @@ -3,35 +3,27 @@ - ⚡ Pluto.jl ⚡ - - - - - - - + + $TITLE + + - + $STYLE - -
-

$TITLE

-
-

$ADVICE

-
-

Go back

-
-

$BODYTITLE

-
$BODY
-
-
+ +

$TITLE

+
+

$ADVICE

+
+

Go back

+
+

$BODYTITLE

+
$BODY
+
\ No newline at end of file diff --git a/frontend/featured-card.css b/frontend/featured-card.css new file mode 100644 index 0000000000..83222b6252 --- /dev/null +++ b/frontend/featured-card.css @@ -0,0 +1,139 @@ +:root { + --card-width: 15rem; +} + +featured-card { + --card-color: hsl(var(--card-color-hue), 77%, 82%); + --card-border-radius: 10px; + --card-border-width: 3px; + + display: block; + /* width: var(--card-width); */ + border: var(--card-border-width) solid var(--card-color); + border-radius: var(--card-border-radius); + margin: 10px; + padding-bottom: 0.3rem; + box-shadow: 0px 2px 6px 0px #00000014; + font-family: var(--inter-ui-font-stack); + position: relative; + word-break: break-word; + hyphens: auto; + background: var(--index-card-bg); + max-width: var(--card-width); +} + +featured-card .banner img { + --zz: calc(var(--card-border-radius) - var(--card-border-width)); + width: 100%; + /* height: 8rem; */ + aspect-ratio: 3/2; + object-fit: cover; + /* background-color: hsl(16deg 100% 66%); */ + background: var(--card-color); + border-radius: var(--zz) var(--zz) 0 0; + flex: 1 1 200px; + min-width: 0; +} + +featured-card a { + text-decoration: none; + /* font-weight: 800; */ +} + +featured-card a.banner { + display: flex; +} + +featured-card .author { + font-weight: 600; +} + +featured-card .author { + position: absolute; + top: 0.3em; + right: 0.3em; + background: var(--welcome-card-author-backdrop); + /* background: hsl(var(--card-color-hue) 34% 46% / 59%); */ + backdrop-filter: blur(15px); + color: var(--index-light-text-color); + border-radius: 117px; + /* height: 2.5em; */ + padding: 0.3em; + padding-right: 0.8em; + display: flex; + align-items: center; + gap: 0.4ch; + margin-left: 0.3rem; +} + +featured-card .author img { + --size: 1.6em; + /* margin: 0.4em 0.4em; */ + /* margin-bottom: -0.4em; */ + width: var(--size); + height: var(--size); + object-fit: cover; + border-radius: 100%; + background: #b6b6b6; + display: inline-block; + overflow: hidden; + flex: 0 0 auto; +} + +featured-card h3 a { + padding: 0.6em; + padding-bottom: 0; + -webkit-line-clamp: 2; + display: inline-block; + display: -webkit-inline-box; + -webkit-box-orient: vertical; + overflow: hidden; + background: var(--index-card-bg); + border-radius: 0.6em; + /* border-top-left-radius: 0; */ +} + +featured-card p { + margin: 0.3rem 0.8rem; + /* padding-top: 0; */ + /* margin-block: 0; */ + color: var(--index-light-text-color); + -webkit-line-clamp: 4; + display: inline-block; + display: -webkit-inline-box; + -webkit-box-orient: vertical; + overflow: hidden; +} + +featured-card h3 { + margin: -1.1rem 0rem 0rem 0rem; +} + +featured-card.big { + grid-column-end: span 2; + grid-row-end: span 2; + /* width: 2000px; */ +} + +featured-card.big .banner img { + height: 16rem; +} + +featured-card.special::before { + content: "New!"; + font-size: 1.4rem; + font-weight: 700; + text-transform: uppercase; + font-style: italic; + display: block; + background: #fcf492; + color: #833bc6; + text-shadow: 0 0 1px #ff6767; + position: absolute; + transform: translateY(calc(-100% - -15px)) rotate(-5deg); + padding: 2px 19px; + left: -9px; + /* right: 51px; */ + /* border: 2px solid #ffca62; */ + pointer-events: none; +} diff --git a/frontend/featured_sources.js b/frontend/featured_sources.js new file mode 100644 index 0000000000..dd013debbc --- /dev/null +++ b/frontend/featured_sources.js @@ -0,0 +1,16 @@ +export default { + // check out https://github.com/JuliaPluto/pluto-developer-instructions/blob/main/How%20to%20update%20the%20featured%20notebooks.md to learn more + sources: [ + { + url: "https://featured.plutojl.org/pluto_export.json", + // this is one month before the expiry date of our domain registration at njal.la + valid_until: "2025-10", + id: "featured pluto", + }, + { + id: "featured pluto", + url: "https://cdn.jsdelivr.net/gh/JuliaPluto/featured@v4/pluto_export.json", + integrity: "sha256-YT5Msj4Iy4cJIuHQi09h3+AwxzreK46WS6EySbPPmJM=", + }, + ], +} diff --git a/frontend/hide-ui.css b/frontend/hide-ui.css index 45ecd273cf..4927d0a95b 100644 --- a/frontend/hide-ui.css +++ b/frontend/hide-ui.css @@ -1,9 +1,11 @@ +/* This CSS file will be loaded when you print the notebook (@media print), or when the disable_ui frontend parameter is set (in a static HTML export). */ + main { margin-top: 20px; cursor: auto; } -body > header, +body header#pluto-nav, preamble > button, pluto-cell > button, pluto-input > button, @@ -13,3 +15,63 @@ pluto-runarea, #helpbox-wrapper { display: none !important; } + +/* These next rules only apply to @media print, i.e. the PDF export. We want to hide these items in the PDF, but not in a static HTML. */ +@media print { + .pluto-frontmatter, + .edit_or_run, + .loading-bar, + .floating_back_button, + .outline-frame, + .outline-frame-actions-container, + pkg-status-mark, + .MJX_ToolTip, + .MJX_HoverRegion, + .MJX_LiveRegion, + nav#undo_delete { + display: none !important; + } + main { + padding-bottom: 0; + } + pluto-input .cm-editor { + border-left: 1px solid var(--normal-cell-color); + border-radius: 4px !important; + } + + pluto-cell { + break-inside: avoid; + } + /* Cells with simple prose content should be allowed to break. Here is a hearistic for that: (we could check for the `.markdown` class generated by the Markdown stdlib but we also want to fully support alternatives) */ + pluto-cell.code_folded:has(p) { + break-inside: auto; + } + + /* When printing, hr should act like a page break */ + pluto-output > div > div.markdown > hr, + pluto-output > div > div > hr { + height: 0; + margin: 0; + visibility: hidden; + break-after: page; + } + + pluto-output h1 { + break-before: page; + } + pluto-cell:first-of-type pluto-output h1 { + break-before: avoid; + } + + /* pluto-cell:has(h1) + pluto-cell { + break-inside: auto; + } */ + + pluto-output :is(h1, h2, h3, h4) { + break-after: avoid; + } +} + +@page { + widows: 2; +} diff --git a/frontend/highlightjs.css b/frontend/highlightjs.css new file mode 100644 index 0000000000..922c4cdd0c --- /dev/null +++ b/frontend/highlightjs.css @@ -0,0 +1,75 @@ +pre code.hljs { + display: block; + overflow-x: auto; + padding: 1em; +} +code.hljs { + padding: 3px 5px; +} +.hljs { + color: var(--cm-editor-text-color); +} +.hljs-comment, +.hljs-quote { + color: var(--cm-comment-color); + font-style: italic; +} +.hljs-doctag, +.hljs-formula, +.hljs-keyword { + color: var(--cm-keyword-color); +} +.hljs-deletion, +.hljs-name, +.hljs-section, +.hljs-selector-tag, +.hljs-subst { + color: var(--cm-var2-color); +} +.hljs-literal { + color: var(--cm-builtin-color); +} +.hljs-addition, +.hljs-attribute, +.hljs-meta .hljs-string, +.hljs-regexp, +.hljs-string { + color: var(--cm-string-color); +} +.hljs-attr, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-pseudo, +.hljs-template-variable, +.hljs-type, +.hljs-variable { + color: var(--cm-var-color); +} +.hljs-number { + color: var(--cm-number-color); +} +.hljs-bullet, +.hljs-link, +.hljs-selector-id, +.hljs-symbol, +.hljs-title { + color: var(--cm-link-color); +} +.hljs-meta { + color: var(--cm-macro-color); + font-weight: 700; +} +.hljs-built_in, +.hljs-class .hljs-title, +.hljs-title.class_ { + color: var(--cm-var2-color); +} +.hljs-emphasis { + font-style: italic; +} +.hljs-strong { + font-weight: 700; +} +.hljs-link { + text-decoration: underline; +} diff --git a/frontend/img/favicon_unsaturated_bg.svg b/frontend/img/favicon_unsaturated_bg.svg new file mode 100755 index 0000000000..1adc29e099 --- /dev/null +++ b/frontend/img/favicon_unsaturated_bg.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/imports/AnsiUp.js b/frontend/imports/AnsiUp.js index e7f6abb905..b85fc8f296 100644 --- a/frontend/imports/AnsiUp.js +++ b/frontend/imports/AnsiUp.js @@ -1,3 +1,2 @@ // @ts-ignore -export default AnsiUp = new window.AnsiUp() -// export default window.AnsiUp +export default AnsiUp = window.AnsiUp diff --git a/frontend/imports/CodemirrorPlutoSetup.d.ts b/frontend/imports/CodemirrorPlutoSetup.d.ts index 0e8dbf47be..b2af50ea68 100644 --- a/frontend/imports/CodemirrorPlutoSetup.d.ts +++ b/frontend/imports/CodemirrorPlutoSetup.d.ts @@ -1,6 +1,6 @@ /** A text iterator iterates over a sequence of strings. When -iterating over a [`Text`](https://codemirror.net/6/docs/ref/#text.Text) document, result values will +iterating over a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) document, result values will either be lines or line breaks. */ interface TextIterator extends Iterator, Iterable { @@ -26,7 +26,7 @@ interface TextIterator extends Iterator, Iterable { lineBreak: boolean; } /** -The data structure for documents. +The data structure for documents. @nonabstract */ declare abstract class Text implements Iterable { /** @@ -68,8 +68,7 @@ declare abstract class Text implements Iterable { /** Iterate over the text. When `dir` is `-1`, iteration happens from end to start. This will return lines and the breaks between - them as separate strings, and for long lines, might split lines - themselves into multiple chunks as well. + them as separate strings. */ iter(dir?: 1 | -1): TextIterator; /** @@ -86,8 +85,13 @@ declare abstract class Text implements Iterable { */ iterLines(from?: number, to?: number): TextIterator; /** + Return the document as a string, using newline characters to + separate lines. + */ + toString(): string; + /** Convert the document to an array of lines (which can be - deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#text.Text^of)). + deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)). */ toJSON(): string[]; /** @@ -107,7 +111,7 @@ declare abstract class Text implements Iterable { } /** This type describes a line in the document. It is created -on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#text.Text.lineAt). +on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt). */ declare class Line$1 { /** @@ -174,13 +178,18 @@ declare class ChangeDesc { */ get empty(): boolean; /** - Iterate over the unchanged parts left by these changes. + Iterate over the unchanged parts left by these changes. `posA` + provides the position of the range in the old document, `posB` + the new position in the changed document. */ iterGaps(f: (posA: number, posB: number, length: number) => void): void; /** Iterate over the ranges changed by these changes. (See [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a variant that also provides you with the inserted text.) + `fromA`/`toA` provides the extent of the change in the starting + document, `fromB`/`toB` the extent of the replacement in the + changed document. When `individual` is true, adjacent changes (which are kept separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are @@ -248,7 +257,7 @@ plain object describing a change (a deletion, insertion, or replacement, depending on which fields are present), a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet), or an array of change specs. */ -declare type ChangeSpec = { +type ChangeSpec = { from: number; to?: number; insert?: string | Text; @@ -259,6 +268,7 @@ stores the document length, and can only be applied to documents with exactly that length. */ declare class ChangeSet extends ChangeDesc { + private constructor(); /** Apply the changes to a document, returning the modified document. @@ -295,7 +305,9 @@ declare class ChangeSet extends ChangeDesc { map(other: ChangeDesc, before?: boolean): ChangeSet; /** Iterate over the changed ranges in the document, calling `f` for - each. + each, with the range in the original document (`fromA`-`toA`) + and the range that replaces it in the new document + (`fromB`-`toB`). When `individual` is true, adjacent changes are reported separately. @@ -342,6 +354,7 @@ declare class SelectionRange { */ readonly to: number; private flags; + private constructor(); /** The anchor of the range—the side that doesn't move when you extend it. @@ -412,6 +425,7 @@ declare class EditorSelection { usually the range that was added last). */ readonly mainIndex: number; + private constructor(); /** Map a selection through a change. Used to adjust the selection position for changes. @@ -467,16 +481,16 @@ declare class EditorSelection { /** Create a selection range. */ - static range(anchor: number, head: number, goalColumn?: number): SelectionRange; + static range(anchor: number, head: number, goalColumn?: number, bidiLevel?: number): SelectionRange; } -declare type FacetConfig = { +type FacetConfig = { /** How to combine the input values into a single output value. When not given, the array of input values becomes the output. This - will immediately be called on creating the facet, with an empty - array, to compute the facet's default value when no inputs are - present. + function will immediately be called on creating the facet, with + an empty array, to compute the facet's default value when no + inputs are present. */ combine?: (value: readonly Input[]) => Output; /** @@ -492,37 +506,46 @@ declare type FacetConfig = { */ compareInput?: (a: Input, b: Input) => boolean; /** - Static facets can not contain dynamic inputs. + Forbids dynamic inputs to this facet. */ static?: boolean; /** - If given, these extension(s) will be added to any state where - this facet is provided. (Note that, while a facet's default - value can be read from a state even if the facet wasn't present - in the state at all, these extensions won't be added in that + If given, these extension(s) (or the result of calling the given + function with the facet) will be added to any state where this + facet is provided. (Note that, while a facet's default value can + be read from a state even if the facet wasn't present in the + state at all, these extensions won't be added in that situation.) */ - enables?: Extension; + enables?: Extension | ((self: Facet) => Extension); }; /** A facet is a labeled value that is associated with an editor state. It takes inputs from any number of extensions, and combines those into a single output value. -Examples of facets are the [theme](https://codemirror.net/6/docs/ref/#view.EditorView^theme) styles -associated with an editor or the [tab -size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) (which is reduced to a single -value, using the input with the hightest precedence). +Examples of uses of facets are the [tab +size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor +attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update +listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener). + +Note that `Facet` instances can be used anywhere where +[`FacetReader`](https://codemirror.net/6/docs/ref/#state.FacetReader) is expected. */ -declare class Facet { +declare class Facet implements FacetReader { private isStatic; private constructor(); /** + Returns a facet reader for this facet, which can be used to + [read](https://codemirror.net/6/docs/ref/#state.EditorState.facet) it but not to define values for it. + */ + get reader(): FacetReader; + /** Define a new facet. */ static define(config?: FacetConfig): Facet; /** - Returns an extension that adds the given value for this facet. + Returns an extension that adds the given value to this facet. */ of(value: Input): Extension; /** @@ -531,9 +554,8 @@ declare class Facet { this value depends on, since your function is only called again for a new state when one of those parts changed. - In most cases, you'll want to use the - [`provide`](https://codemirror.net/6/docs/ref/#state.StateField^define^config.provide) option when - defining a field instead. + In cases where your value depends only on a single field, you'll + want to use the [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method instead. */ compute(deps: readonly Slot[], get: (state: EditorState) => Input): Extension; /** @@ -547,11 +569,26 @@ declare class Facet { input type, the getter function can be omitted. If given, it will be used to retrieve the input from the field value. */ - from(field: StateField): Extension; + from(field: StateField): Extension; from(field: StateField, get: (value: T) => Input): Extension; + tag: Output; } -declare type Slot = Facet | StateField | "doc" | "selection"; -declare type StateFieldSpec = { +/** +A facet reader can be used to fetch the value of a facet, though +[`EditorState.facet`](https://codemirror.net/6/docs/ref/#state.EditorState.facet) or as a dependency +in [`Facet.compute`](https://codemirror.net/6/docs/ref/#state.Facet.compute), but not to define new +values for the facet. +*/ +type FacetReader = { + /** + Dummy tag that makes sure TypeScript doesn't consider all object + types as conforming to this type. Not actually present on the + object. + */ + tag: Output; +}; +type Slot = FacetReader | StateField | "doc" | "selection"; +type StateFieldSpec = { /** Creates the initial value for the field when a state is created. */ @@ -569,12 +606,12 @@ declare type StateFieldSpec = { */ compare?: (a: Value, b: Value) => boolean; /** - Provide values for facets based on the value of this field. The - given function will be called once with the initialized field. It - will usually want to call some facet's - [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method to create facet inputs from - this field, but can also return other extensions that should be - enabled by this field. + Provide extensions based on this field. The given function will + be called once with the initialized field. It will usually want + to call some facet's [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method to + create facet inputs from this field, but can also return other + extensions that should be enabled when the field is present in a + configuration. */ provide?: (field: StateField) => Extension; /** @@ -626,7 +663,7 @@ providers](https://codemirror.net/6/docs/ref/#state.Facet.of), or objects with a `extension` property. Extensions can be nested in arrays arbitrarily deep—they will be flattened when processed. */ -declare type Extension = { +type Extension = { extension: Extension; } | readonly Extension[]; /** @@ -735,7 +772,10 @@ declare class StateEffect { is(type: StateEffectType): this is StateEffect; /** Define a new effect type. The type parameter indicates the type - of values that his effect holds. + of values that his effect holds. It should be a type that + doesn't include `undefined`, since that is used in + [mapping](https://codemirror.net/6/docs/ref/#state.StateEffect.map) to indicate that an effect is + removed. */ static define(spec?: StateEffectSpec): StateEffectType; /** @@ -785,7 +825,7 @@ interface TransactionSpec { */ annotations?: Annotation | readonly Annotation[]; /** - Shorthand for `annotations: `[`Transaction.userEvent`](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)[`.of(...)`. + Shorthand for `annotations:` [`Transaction.userEvent`](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)`.of(...)`. */ userEvent?: string; /** @@ -797,7 +837,9 @@ interface TransactionSpec { By default, transactions can be modified by [change filters](https://codemirror.net/6/docs/ref/#state.EditorState^changeFilter) and [transaction filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter). You can set this - to `false` to disable that. + to `false` to disable that. This can be necessary for + transactions that, for example, include annotations that must be + kept consistent with their changes. */ filter?: boolean; /** @@ -815,7 +857,9 @@ Changes to the editor state are grouped into transactions. Typically, a user action creates a single transaction, which may contain any number of document changes, may change the selection, or have other effects. Create a transaction by calling -[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). +[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update), or immediately +dispatch one by calling +[`EditorView.dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch). */ declare class Transaction { /** @@ -840,6 +884,7 @@ declare class Transaction { transaction is dispatched. */ readonly scrollIntoView: boolean; + private constructor(); /** The new document produced by the transaction. Contrary to [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't @@ -858,7 +903,7 @@ declare class Transaction { get newSelection(): EditorSelection; /** The new state created by the transaction. Computed on demand - (but retained for subsequent access), so itis recommended not to + (but retained for subsequent access), so it is recommended not to access it in [transaction filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible. */ @@ -887,7 +932,8 @@ declare class Transaction { */ isUserEvent(event: string): boolean; /** - Annotation used to store transaction timestamps. + Annotation used to store transaction timestamps. Automatically + added to every transaction, holding `Date.now()`. */ static time: AnnotationType; /** @@ -961,7 +1007,7 @@ interface EditorStateConfig { provided either as a plain string (which will be split into lines according to the value of the [`lineSeparator` facet](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)), or an instance of - the [`Text`](https://codemirror.net/6/docs/ref/#text.Text) class (which is what the state will use + the [`Text`](https://codemirror.net/6/docs/ref/#state.Text) class (which is what the state will use to represent the document). */ doc?: string | Text; @@ -996,6 +1042,7 @@ declare class EditorState { The current selection. */ readonly selection: EditorSelection; + private constructor(); /** Retrieve the value of a [state field](https://codemirror.net/6/docs/ref/#state.StateField). Throws an error when the state doesn't have that field, unless you pass @@ -1023,11 +1070,7 @@ declare class EditorState { Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that replaces every selection range with the given content. */ - replaceSelection(text: string | Text): { - changes: ChangeSet; - selection: EditorSelection; - effects: readonly StateEffect[]; - }; + replaceSelection(text: string | Text): TransactionSpec; /** Create a set of changes and a new selection by running the given function for each range in the active selection. The function @@ -1057,7 +1100,7 @@ declare class EditorState { /** Using the state's [line separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a - [`Text`](https://codemirror.net/6/docs/ref/#text.Text) instance from the given string. + [`Text`](https://codemirror.net/6/docs/ref/#state.Text) instance from the given string. */ toText(string: string): Text; /** @@ -1067,7 +1110,7 @@ declare class EditorState { /** Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet). */ - facet(facet: Facet): Output; + facet(facet: FacetReader): Output; /** Convert this state to a JSON-serializable object. When custom fields should be serialized, you can pass them in as an object @@ -1161,8 +1204,13 @@ declare class EditorState { Look up a translation for the given phrase (via the [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the original string if no translation is found. + + If additional arguments are passed, they will be inserted in + place of markers like `$1` (for the first value) and `$2`, etc. + A single `$` is equivalent to `$1`, and `$$` will produce a + literal dollar sign. */ - phrase(phrase: string): string; + phrase(phrase: string, ...insert: any[]): string; /** A facet used to register [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers. @@ -1175,11 +1223,23 @@ declare class EditorState { /** Find the values for a given language data field, provided by the the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet. + + Examples of language data fields are... + + - [`"commentTokens"`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) for specifying + comment syntax. + - [`"autocomplete"`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.override) + for providing language-specific completion sources. + - [`"wordChars"`](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) for adding + characters that should be considered part of words in this + language. + - [`"closeBrackets"`](https://codemirror.net/6/docs/ref/#autocomplete.CloseBracketConfig) controls + bracket closing behavior. */ languageDataAt(name: string, pos: number, side?: -1 | 0 | 1): readonly T[]; /** Return a function that can categorize strings (expected to - represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak)) + represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak)) into one of: - Word (contains an alphanumeric character or a character @@ -1206,7 +1266,7 @@ declare class EditorState { want to do anything, `false` to completely stop the changes in the transaction, or a set of ranges in which changes should be suppressed. Such ranges are represented as an array of numbers, - with each pair of two number indicating the start and end of a + with each pair of two numbers indicating the start and end of a range. So for example `[10, 20, 100, 110]` suppresses changes between 10 and 20, and between 100 and 110. */ @@ -1237,12 +1297,12 @@ declare class EditorState { which can only add [annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type - of filter runs even the transaction has disabled regular + of filter runs even if the transaction has disabled regular [filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable for effects that don't need to touch the changes or selection, but do want to process every transaction. - Extenders run _after_ filters, when both are applied. + Extenders run _after_ filters, when both are present. */ static transactionExtender: Facet<(tr: Transaction) => Pick | null, readonly ((tr: Transaction) => Pick | null)[]>; } @@ -1252,437 +1312,153 @@ Subtype of [`Command`](https://codemirror.net/6/docs/ref/#view.Command) that doe to the actual editor view. Mostly useful to define commands that can be run and tested outside of a browser environment. */ -declare type StateCommand = (target: { +type StateCommand = (target: { state: EditorState; dispatch: (transaction: Transaction) => void; }) => boolean; /** Utility function for combining behaviors to fill in a config -object from an array of provided configs. Will, by default, error +object from an array of provided configs. `defaults` should hold +default values for all optional fields in `Config`. + +The function will, by default, error when a field gets two values that aren't `===`-equal, but you can provide combine functions per field to do something else. */ -declare function combineConfig(configs: readonly Partial[], defaults: Partial, // Should hold only the optional properties of Config, but I haven't managed to express that +declare function combineConfig(configs: readonly Partial[], defaults: Partial, // Should hold only the optional properties of Config, but I haven't managed to express that combine?: { [P in keyof Config]?: (first: Config[P], second: Config[P]) => Config[P]; }): Config; -interface ChangedRange { - fromA: number; - toA: number; - fromB: number; - toB: number; +/** +Each range is associated with a value, which must inherit from +this class. +*/ +declare abstract class RangeValue { + /** + Compare this value with another value. Used when comparing + rangesets. The default implementation compares by identity. + Unless you are only creating a fixed number of unique instances + of your value type, it is a good idea to implement this + properly. + */ + eq(other: RangeValue): boolean; + /** + The bias value at the start of the range. Determines how the + range is positioned relative to other ranges starting at this + position. Defaults to 0. + */ + startSide: number; + /** + The bias value at the end of the range. Defaults to 0. + */ + endSide: number; + /** + The mode with which the location of the range should be mapped + when its `from` and `to` are the same, to decide whether a + change deletes the range. Defaults to `MapMode.TrackDel`. + */ + mapMode: MapMode; + /** + Determines whether this value marks a point range. Regular + ranges affect the part of the document they cover, and are + meaningless when empty. Point ranges have a meaning on their + own. When non-empty, a point range is treated as atomic and + shadows any ranges contained in it. + */ + point: boolean; + /** + Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value. + */ + range(from: number, to?: number): Range; } -declare class TreeFragment { +/** +A range associates a value with a range of positions. +*/ +declare class Range { + /** + The range's start position. + */ readonly from: number; + /** + Its end position. + */ readonly to: number; - readonly tree: Tree; - readonly offset: number; - constructor(from: number, to: number, tree: Tree, offset: number, openStart?: boolean, openEnd?: boolean); - get openStart(): boolean; - get openEnd(): boolean; - static addTree(tree: Tree, fragments?: readonly TreeFragment[], partial?: boolean): TreeFragment[]; - static applyChanges(fragments: readonly TreeFragment[], changes: readonly ChangedRange[], minGap?: number): readonly TreeFragment[]; -} -interface PartialParse { - advance(): Tree | null; - readonly parsedPos: number; - stopAt(pos: number): void; - readonly stoppedAt: number | null; + /** + The value associated with this range. + */ + readonly value: T; + private constructor(); } -declare abstract class Parser { - abstract createParse(input: Input, fragments: readonly TreeFragment[], ranges: readonly { - from: number; - to: number; - }[]): PartialParse; - startParse(input: Input | string, fragments?: readonly TreeFragment[], ranges?: readonly { - from: number; - to: number; - }[]): PartialParse; - parse(input: Input | string, fragments?: readonly TreeFragment[], ranges?: readonly { - from: number; - to: number; - }[]): Tree; +/** +Collection of methods used when comparing range sets. +*/ +interface RangeComparator { + /** + Notifies the comparator that a range (in positions in the new + document) has the given sets of values associated with it, which + are different in the old (A) and new (B) sets. + */ + compareRange(from: number, to: number, activeA: T[], activeB: T[]): void; + /** + Notification for a changed (or inserted, or deleted) point range. + */ + comparePoint(from: number, to: number, pointA: T | null, pointB: T | null): void; } -interface Input { - readonly length: number; - chunk(from: number): string; - readonly lineChunks: boolean; - read(from: number, to: number): string; +/** +Methods used when iterating over the spans created by a set of +ranges. The entire iterated range will be covered with either +`span` or `point` calls. +*/ +interface SpanIterator { + /** + Called for any ranges not covered by point decorations. `active` + holds the values that the range is marked with (and may be + empty). `openStart` indicates how many of those ranges are open + (continued) at the start of the span. + */ + span(from: number, to: number, active: readonly T[], openStart: number): void; + /** + Called when going over a point decoration. The active range + decorations that cover the point and have a higher precedence + are provided in `active`. The open count in `openStart` counts + the number of those ranges that started before the point and. If + the point started before the iterated range, `openStart` will be + `active.length + 1` to signal this. + */ + point(from: number, to: number, value: T, active: readonly T[], openStart: number, index: number): void; } -declare type ParseWrapper = (inner: PartialParse, input: Input, fragments: readonly TreeFragment[], ranges: readonly { +/** +A range cursor is an object that moves to the next range every +time you call `next` on it. Note that, unlike ES6 iterators, these +start out pointing at the first element, so you should call `next` +only after reading the first range (if any). +*/ +interface RangeCursor { + /** + Move the iterator forward. + */ + next: () => void; + /** + The next range's value. Holds `null` when the cursor has reached + its end. + */ + value: T | null; + /** + The next range's start position. + */ from: number; + /** + The next end position. + */ to: number; -}[]) => PartialParse; - -declare class NodeProp { - perNode: boolean; - deserialize: (str: string) => T; - constructor(config?: { - deserialize?: (str: string) => T; - perNode?: boolean; - }); - add(match: { - [selector: string]: T; - } | ((type: NodeType) => T | undefined)): NodePropSource; - static closedBy: NodeProp; - static openedBy: NodeProp; - static group: NodeProp; - static contextHash: NodeProp; - static lookAhead: NodeProp; - static mounted: NodeProp; -} -declare class MountedTree { - readonly tree: Tree; - readonly overlay: readonly { - from: number; - to: number; - }[] | null; - readonly parser: Parser; - constructor(tree: Tree, overlay: readonly { - from: number; - to: number; - }[] | null, parser: Parser); -} -declare type NodePropSource = (type: NodeType) => null | [NodeProp, any]; -declare class NodeType { - readonly name: string; - readonly id: number; - static define(spec: { - id: number; - name?: string; - props?: readonly ([NodeProp, any] | NodePropSource)[]; - top?: boolean; - error?: boolean; - skipped?: boolean; - }): NodeType; - prop(prop: NodeProp): T | undefined; - get isTop(): boolean; - get isSkipped(): boolean; - get isError(): boolean; - get isAnonymous(): boolean; - is(name: string | number): boolean; - static none: NodeType; - static match(map: { - [selector: string]: T; - }): (node: NodeType) => T | undefined; -} -declare class NodeSet { - readonly types: readonly NodeType[]; - constructor(types: readonly NodeType[]); - extend(...props: NodePropSource[]): NodeSet; -} -declare class Tree { - readonly type: NodeType; - readonly children: readonly (Tree | TreeBuffer)[]; - readonly positions: readonly number[]; - readonly length: number; - constructor(type: NodeType, children: readonly (Tree | TreeBuffer)[], positions: readonly number[], length: number, props?: readonly [NodeProp | number, any][]); - static empty: Tree; - cursor(pos?: number, side?: -1 | 0 | 1): TreeCursor; - fullCursor(): TreeCursor; - get topNode(): SyntaxNode; - resolve(pos: number, side?: -1 | 0 | 1): any; - resolveInner(pos: number, side?: -1 | 0 | 1): any; - iterate(spec: { - enter(type: NodeType, from: number, to: number, get: () => SyntaxNode): false | void; - leave?(type: NodeType, from: number, to: number, get: () => SyntaxNode): void; - from?: number; - to?: number; - }): void; - prop(prop: NodeProp): T | undefined; - get propValues(): readonly [NodeProp | number, any][]; - balance(config?: { - makeTree?: (children: readonly (Tree | TreeBuffer)[], positions: readonly number[], length: number) => Tree; - }): Tree; - static build(data: BuildData): Tree; -} -declare type BuildData = { - buffer: BufferCursor | readonly number[]; - nodeSet: NodeSet; - topID: number; - start?: number; - bufferStart?: number; - length?: number; - maxBufferLength?: number; - reused?: readonly Tree[]; - minRepeatType?: number; -}; -interface BufferCursor { - pos: number; - id: number; - start: number; - end: number; - size: number; - next(): void; - fork(): BufferCursor; -} -declare class TreeBuffer { - readonly buffer: Uint16Array; - readonly length: number; - readonly set: NodeSet; - constructor(buffer: Uint16Array, length: number, set: NodeSet); } -interface SyntaxNode { - type: NodeType; - name: string; - from: number; - to: number; - parent: SyntaxNode | null; - firstChild: SyntaxNode | null; - lastChild: SyntaxNode | null; - childAfter(pos: number): SyntaxNode | null; - childBefore(pos: number): SyntaxNode | null; - enter(pos: number, side: -1 | 0 | 1, overlays?: boolean, buffers?: boolean): SyntaxNode | null; - nextSibling: SyntaxNode | null; - prevSibling: SyntaxNode | null; - cursor: TreeCursor; - resolve(pos: number, side?: -1 | 0 | 1): SyntaxNode; - resolveInner(pos: number, side?: -1 | 0 | 1): SyntaxNode; - enterUnfinishedNodesBefore(pos: number): SyntaxNode; - tree: Tree | null; - toTree(): Tree; - getChild(type: string | number, before?: string | number | null, after?: string | number | null): SyntaxNode | null; - getChildren(type: string | number, before?: string | number | null, after?: string | number | null): SyntaxNode[]; -} -declare class TreeCursor { - type: NodeType; - get name(): string; - from: number; - to: number; - private buffer; - private stack; - private index; - private bufferNode; - private yieldNode; - private yieldBuf; - private yield; - firstChild(): boolean; - lastChild(): boolean; - childAfter(pos: number): boolean; - childBefore(pos: number): boolean; - enter(pos: number, side: -1 | 0 | 1, overlays?: boolean, buffers?: boolean): boolean; - parent(): boolean; - nextSibling(): boolean; - prevSibling(): boolean; - private atLastNode; - private move; - next(enter?: boolean): boolean; - prev(enter?: boolean): boolean; - moveTo(pos: number, side?: -1 | 0 | 1): this; - get node(): SyntaxNode; - get tree(): Tree | null; -} - -interface NestedParse { - parser: Parser; - overlay?: readonly { - from: number; - to: number; - }[] | ((node: TreeCursor) => { - from: number; - to: number; - } | boolean); -} -declare function parseMixed(nest: (node: TreeCursor, input: Input) => NestedParse | null): ParseWrapper; - -declare class Stack { - pos: number; - get context(): any; - canShift(term: number): boolean; - get parser(): LRParser; - dialectEnabled(dialectID: number): boolean; - private shiftContext; - private reduceContext; - private updateContext; -} - -declare class InputStream { - private chunk2; - private chunk2Pos; - next: number; - pos: number; - private rangeIndex; - private range; - resolveOffset(offset: number, assoc: -1 | 1): number; - peek(offset: number): any; - acceptToken(token: number, endOffset?: number): void; - private getChunk; - private readNext; - advance(n?: number): number; - private setDone; -} -interface Tokenizer { -} -interface ExternalOptions { - contextual?: boolean; - fallback?: boolean; - extend?: boolean; -} -declare class ExternalTokenizer implements Tokenizer { - constructor(token: (input: InputStream, stack: Stack) => void, options?: ExternalOptions); -} - -declare class ContextTracker { - constructor(spec: { - start: T; - shift?(context: T, term: number, stack: Stack, input: InputStream): T; - reduce?(context: T, term: number, stack: Stack, input: InputStream): T; - reuse?(context: T, node: Tree, stack: Stack, input: InputStream): T; - hash?(context: T): number; - strict?: boolean; - }); -} -interface ParserConfig { - props?: readonly NodePropSource[]; - top?: string; - dialect?: string; - tokenizers?: { - from: ExternalTokenizer; - to: ExternalTokenizer; - }[]; - contextTracker?: ContextTracker; - strict?: boolean; - wrap?: ParseWrapper; - bufferLength?: number; -} -declare class LRParser extends Parser { - readonly nodeSet: NodeSet; - createParse(input: Input, fragments: readonly TreeFragment[], ranges: readonly { - from: number; - to: number; - }[]): PartialParse; - configure(config: ParserConfig): LRParser; - getName(term: number): string; - get topNode(): NodeType; -} - -/** -Each range is associated with a value, which must inherit from -this class. -*/ -declare abstract class RangeValue { - /** - Compare this value with another value. The default - implementation compares by identity. - */ - eq(other: RangeValue): boolean; - /** - The bias value at the start of the range. Determines how the - range is positioned relative to other ranges starting at this - position. Defaults to 0. - */ - startSide: number; - /** - The bias value at the end of the range. Defaults to 0. - */ - endSide: number; - /** - The mode with which the location of the range should be mapped - when its `from` and `to` are the same, to decide whether a - change deletes the range. Defaults to `MapMode.TrackDel`. - */ - mapMode: MapMode; - /** - Whether this value marks a point range, which is treated as - atomic and shadows the ranges contained in it. - */ - point: boolean; - /** - Create a [range](https://codemirror.net/6/docs/ref/#rangeset.Range) with this value. - */ - range(from: number, to?: number): Range; -} -/** -A range associates a value with a range of positions. -*/ -declare class Range { - /** - The range's start position. - */ - readonly from: number; - /** - Its end position. - */ - readonly to: number; - /** - The value associated with this range. - */ - readonly value: T; -} -/** -Collection of methods used when comparing range sets. -*/ -interface RangeComparator { - /** - Notifies the comparator that the given range has the given set - of values associated with it. - */ - compareRange(from: number, to: number, activeA: T[], activeB: T[]): void; - /** - Notification for a point range. - */ - comparePoint(from: number, to: number, byA: T | null, byB: T | null): void; -} -/** -Methods used when iterating over the spans created by a set of -ranges. The entire iterated range will be covered with either -`span` or `point` calls. -*/ -interface SpanIterator { - /** - Called for any ranges not covered by point decorations. `active` - holds the values that the range is marked with (and may be - empty). `openStart` indicates how many of those ranges are open - (continued) at the start of the span. - */ - span(from: number, to: number, active: readonly T[], openStart: number): void; - /** - Called when going over a point decoration. The active range - decorations that cover the point and have a higher precedence - are provided in `active`. The open count in `openStart` counts - the number of those ranges that started before the point and. If - the point started before the iterated range, `openStart` will be - `active.length + 1` to signal this. - */ - point(from: number, to: number, value: T, active: readonly T[], openStart: number): void; - /** - When provided, this will be called for each point processed, - causing the ones for which it returns false to be ignored. - */ - filterPoint?(from: number, to: number, value: T, index: number): boolean; -} -/** -A range cursor is an object that moves to the next range every -time you call `next` on it. Note that, unlike ES6 iterators, these -start out pointing at the first element, so you should call `next` -only after reading the first range (if any). -*/ -interface RangeCursor { - /** - Move the iterator forward. - */ - next: () => void; - /** - The next range's value. Holds `null` when the cursor has reached - its end. - */ - value: T | null; - /** - The next range's start position. - */ - from: number; - /** - The next end position. - */ - to: number; -} -declare type RangeSetUpdate = { +type RangeSetUpdate = { /** An array of ranges to add. If given, this should be sorted by `from` position and `startSide` unless - [`sort`](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.update^updateSpec.sort) is given as + [`sort`](https://codemirror.net/6/docs/ref/#state.RangeSet.update^updateSpec.sort) is given as `true`. */ add?: readonly Range[]; @@ -1708,12 +1484,13 @@ declare type RangeSetUpdate = { filterTo?: number; }; /** -A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#rangeset.Range) in a -way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.map) and -[update](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.update). This is an immutable data +A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#state.Range) in a +way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#state.RangeSet.map) and +[update](https://codemirror.net/6/docs/ref/#state.RangeSet.update). This is an immutable data structure. */ declare class RangeSet { + private constructor(); /** The number of ranges in the set. */ @@ -1722,7 +1499,7 @@ declare class RangeSet { Update the range set, optionally adding new ranges or filtering out existing ones. - (The extra type parameter is just there as a kludge to work + (Note: The type parameter is just there as a kludge to work around TypeScript variance issues that prevented `RangeSet` from being a subtype of `RangeSet` when `X` is a subtype of `Y`.) @@ -1756,8 +1533,7 @@ declare class RangeSet { static compare(oldSets: readonly RangeSet[], newSets: readonly RangeSet[], /** This indicates how the underlying data changed between these - ranges, and is needed to synchronize the iteration. `from` and - `to` are coordinates in the _new_ space, after these changes. + ranges, and is needed to synchronize the iteration. */ textDiff: ChangeDesc, comparator: RangeComparator, /** @@ -1774,7 +1550,7 @@ declare class RangeSet { Iterate over a group of range sets at the same time, notifying the iterator about the ranges covering every given piece of content. Returns the open count (see - [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#rangeset.SpanIterator.span)) at the end + [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#state.SpanIterator.span)) at the end of the iteration. */ static spans(sets: readonly RangeSet[], from: number, to: number, iterator: SpanIterator, @@ -1797,1874 +1573,2990 @@ declare class RangeSet { static empty: RangeSet; } -declare class StyleModule { - constructor(spec: {[selector: string]: StyleSpec}, options?: { - finish?(sel: string): string - }) - getRules(): string - static mount(root: Document | ShadowRoot | DocumentOrShadowRoot, module: StyleModule | ReadonlyArray): void - static newName(): string -} - -type StyleSpec = { - [propOrSelector: string]: string | number | StyleSpec | null -} - -declare type Attrs = { - [name: string]: string; -}; - -interface MarkDecorationSpec { +/** +The [`TreeFragment.applyChanges`](#common.TreeFragment^applyChanges) +method expects changed ranges in this format. +*/ +interface ChangedRange { /** - Whether the mark covers its start and end position or not. This - influences whether content inserted at those positions becomes - part of the mark. Defaults to false. + The start of the change in the start document */ - inclusive?: boolean; + fromA: number; /** - Specify whether the start position of the marked range should be - inclusive. Overrides `inclusive`, when both are present. + The end of the change in the start document */ - inclusiveStart?: boolean; + toA: number; /** - Whether the end should be inclusive. + The start of the replacement in the new document */ - inclusiveEnd?: boolean; + fromB: number; /** - Add attributes to the DOM elements that hold the text in the - marked range. + The end of the replacement in the new document */ - attributes?: { - [key: string]: string; - }; + toB: number; +} +/** +Tree fragments are used during [incremental +parsing](#common.Parser.startParse) to track parts of old trees +that can be reused in a new parse. An array of fragments is used +to track regions of an old tree whose nodes might be reused in new +parses. Use the static +[`applyChanges`](#common.TreeFragment^applyChanges) method to +update fragments for document changes. +*/ +declare class TreeFragment { /** - Shorthand for `{attributes: {class: value}}`. + The start of the unchanged range pointed to by this fragment. + This refers to an offset in the _updated_ document (as opposed + to the original tree). */ - class?: string; + readonly from: number; /** - Add a wrapping element around the text in the marked range. Note - that there will not be a single element covering the entire - range—content is split on mark starts and ends, and each piece - gets its own element. + The end of the unchanged range. */ - tagName?: string; + readonly to: number; /** - Decoration specs allow extra properties, which can be retrieved - through the decoration's [`spec`](https://codemirror.net/6/docs/ref/#view.Decoration.spec) - property. + The tree that this fragment is based on. */ - [other: string]: any; -} -interface WidgetDecorationSpec { + readonly tree: Tree; /** - The type of widget to draw here. + The offset between the fragment's tree and the document that + this fragment can be used against. Add this when going from + document to tree positions, subtract it to go from tree to + document positions. */ - widget: WidgetType; + readonly offset: number; /** - Which side of the given position the widget is on. When this is - positive, the widget will be drawn after the cursor if the - cursor is on the same position. Otherwise, it'll be drawn before - it. When multiple widgets sit at the same position, their `side` - values will determine their ordering—those with a lower value - come first. Defaults to 0. + Construct a tree fragment. You'll usually want to use + [`addTree`](#common.TreeFragment^addTree) and + [`applyChanges`](#common.TreeFragment^applyChanges) instead of + calling this directly. */ - side?: number; + constructor( /** - Determines whether this is a block widgets, which will be drawn - between lines, or an inline widget (the default) which is drawn - between the surrounding text. - - Note that block-level decorations should not have vertical - margins, and if you dynamically change their height, you should - make sure to call - [`requestMeasure`](https://codemirror.net/6/docs/ref/#view.EditorView.requestMeasure), so that the - editor can update its information about its vertical layout. + The start of the unchanged range pointed to by this fragment. + This refers to an offset in the _updated_ document (as opposed + to the original tree). */ - block?: boolean; + from: number, /** - Other properties are allowed. + The end of the unchanged range. */ - [other: string]: any; -} -interface ReplaceDecorationSpec { + to: number, /** - An optional widget to drawn in the place of the replaced - content. + The tree that this fragment is based on. */ - widget?: WidgetType; + tree: Tree, /** - Whether this range covers the positions on its sides. This - influences whether new content becomes part of the range and - whether the cursor can be drawn on its sides. Defaults to false - for inline replacements, and true for block replacements. + The offset between the fragment's tree and the document that + this fragment can be used against. Add this when going from + document to tree positions, subtract it to go from tree to + document positions. */ - inclusive?: boolean; + offset: number, openStart?: boolean, openEnd?: boolean); /** - Set inclusivity at the start. + Whether the start of the fragment represents the start of a + parse, or the end of a change. (In the second case, it may not + be safe to reuse some nodes at the start, depending on the + parsing algorithm.) */ - inclusiveStart?: boolean; + get openStart(): boolean; /** - Set inclusivity at the end. + Whether the end of the fragment represents the end of a + full-document parse, or the start of a change. */ - inclusiveEnd?: boolean; + get openEnd(): boolean; /** - Whether this is a block-level decoration. Defaults to false. + Create a set of fragments from a freshly parsed tree, or update + an existing set of fragments by replacing the ones that overlap + with a tree with content from the new tree. When `partial` is + true, the parse is treated as incomplete, and the resulting + fragment has [`openEnd`](#common.TreeFragment.openEnd) set to + true. */ - block?: boolean; + static addTree(tree: Tree, fragments?: readonly TreeFragment[], partial?: boolean): readonly TreeFragment[]; /** - Other properties are allowed. + Apply a set of edits to an array of fragments, removing or + splitting fragments as necessary to remove edited ranges, and + adjusting offsets for fragments that moved. */ - [other: string]: any; + static applyChanges(fragments: readonly TreeFragment[], changes: readonly ChangedRange[], minGap?: number): readonly TreeFragment[]; } -interface LineDecorationSpec { +/** +Interface used to represent an in-progress parse, which can be +moved forward piece-by-piece. +*/ +interface PartialParse { /** - DOM attributes to add to the element wrapping the line. + Advance the parse state by some amount. Will return the finished + syntax tree when the parse completes. */ - attributes?: { - [key: string]: string; - }; + advance(): Tree | null; /** - Shorthand for `{attributes: {class: value}}`. + The position up to which the document has been parsed. Note + that, in multi-pass parsers, this will stay back until the last + pass has moved past a given position. */ - class?: string; + readonly parsedPos: number; /** - Other properties are allowed. + Tell the parse to not advance beyond the given position. + `advance` will return a tree when the parse has reached the + position. Note that, depending on the parser algorithm and the + state of the parse when `stopAt` was called, that tree may + contain nodes beyond the position. It is an error to call + `stopAt` with a higher position than it's [current + value](#common.PartialParse.stoppedAt). */ - [other: string]: any; + stopAt(pos: number): void; + /** + Reports whether `stopAt` has been called on this parse. + */ + readonly stoppedAt: number | null; } /** -Widgets added to the content are described by subclasses of this -class. Using a description object like that makes it possible to -delay creating of the DOM structure for a widget until it is -needed, and to avoid redrawing widgets even when the decorations -that define them are recreated. +A superclass that parsers should extend. */ -declare abstract class WidgetType { +declare abstract class Parser { /** - Build the DOM structure for this widget instance. + Start a parse for a single tree. This is the method concrete + parser implementations must implement. Called by `startParse`, + with the optional arguments resolved. */ - abstract toDOM(view: EditorView): HTMLElement; + abstract createParse(input: Input, fragments: readonly TreeFragment[], ranges: readonly { + from: number; + to: number; + }[]): PartialParse; /** - Compare this instance to another instance of the same type. - (TypeScript can't express this, but only instances of the same - specific class will be passed to this method.) This is used to - avoid redrawing widgets when they are replaced by a new - decoration of the same type. The default implementation just - returns `false`, which will cause new instances of the widget to - always be redrawn. + Start a parse, returning a [partial parse](#common.PartialParse) + object. [`fragments`](#common.TreeFragment) can be passed in to + make the parse incremental. + + By default, the entire input is parsed. You can pass `ranges`, + which should be a sorted array of non-empty, non-overlapping + ranges, to parse only those ranges. The tree returned in that + case will start at `ranges[0].from`. */ - eq(_widget: WidgetType): boolean; + startParse(input: Input | string, fragments?: readonly TreeFragment[], ranges?: readonly { + from: number; + to: number; + }[]): PartialParse; /** - Update a DOM element created by a widget of the same type (but - different, non-`eq` content) to reflect this widget. May return - true to indicate that it could update, false to indicate it - couldn't (in which case the widget will be redrawn). The default - implementation just returns false. + Run a full parse, returning the resulting tree. */ - updateDOM(_dom: HTMLElement): boolean; + parse(input: Input | string, fragments?: readonly TreeFragment[], ranges?: readonly { + from: number; + to: number; + }[]): Tree; +} +/** +This is the interface parsers use to access the document. To run +Lezer directly on your own document data structure, you have to +write an implementation of it. +*/ +interface Input { /** - The estimated height this widget will have, to be used when - estimating the height of content that hasn't been drawn. May - return -1 to indicate you don't know. The default implementation - returns -1. + The length of the document. */ - get estimatedHeight(): number; + readonly length: number; /** - Can be used to configure which kinds of events inside the widget - should be ignored by the editor. The default is to ignore all - events. + Get the chunk after the given position. The returned string + should start at `from` and, if that isn't the end of the + document, may be of any length greater than zero. */ - ignoreEvent(_event: Event): boolean; + chunk(from: number): string; /** - This is called when the an instance of the widget is removed - from the editor view. + Indicates whether the chunks already end at line breaks, so that + client code that wants to work by-line can avoid re-scanning + them for line breaks. When this is true, the result of `chunk()` + should either be a single line break, or the content between + `from` and the next line break. + */ + readonly lineChunks: boolean; + /** + Read the part of the document between the given positions. */ - destroy(_dom: HTMLElement): void; + read(from: number, to: number): string; } /** -A decoration set represents a collection of decorated ranges, -organized for efficient access and mapping. See -[`RangeSet`](https://codemirror.net/6/docs/ref/#rangeset.RangeSet) for its methods. +Parse wrapper functions are supported by some parsers to inject +additional parsing logic. */ -declare type DecorationSet = RangeSet; +type ParseWrapper = (inner: PartialParse, input: Input, fragments: readonly TreeFragment[], ranges: readonly { + from: number; + to: number; +}[]) => PartialParse; /** -The different types of blocks that can occur in an editor view. +Each [node type](#common.NodeType) or [individual tree](#common.Tree) +can have metadata associated with it in props. Instances of this +class represent prop names. */ -declare enum BlockType { - /** - A line of text. - */ - Text = 0, +declare class NodeProp { /** - A block widget associated with the position after it. + Indicates whether this prop is stored per [node + type](#common.NodeType) or per [tree node](#common.Tree). */ - WidgetBefore = 1, + perNode: boolean; /** - A block widget associated with the position before it. + A method that deserializes a value of this prop from a string. + Can be used to allow a prop to be directly written in a grammar + file. */ - WidgetAfter = 2, + deserialize: (str: string) => T; /** - A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content. + Create a new node prop type. */ - WidgetRange = 3 -} -/** -A decoration provides information on how to draw or style a piece -of content. You'll usually use it wrapped in a -[`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range), which adds a start and end position. -*/ -declare abstract class Decoration extends RangeValue { + constructor(config?: { + /** + The [deserialize](#common.NodeProp.deserialize) function to + use for this prop, used for example when directly providing + the prop from a grammar file. Defaults to a function that + raises an error. + */ + deserialize?: (str: string) => T; + /** + By default, node props are stored in the [node + type](#common.NodeType). It can sometimes be useful to directly + store information (usually related to the parsing algorithm) + in [nodes](#common.Tree) themselves. Set this to true to enable + that for this prop. + */ + perNode?: boolean; + }); /** - The config object used to create this decoration. You can - include additional properties in there to store metadata about - your decoration. + This is meant to be used with + [`NodeSet.extend`](#common.NodeSet.extend) or + [`LRParser.configure`](#lr.ParserConfig.props) to compute + prop values for each node type in the set. Takes a [match + object](#common.NodeType^match) or function that returns undefined + if the node type doesn't get this prop, and the prop's value if + it does. */ - readonly spec: any; - abstract eq(other: Decoration): boolean; + add(match: { + [selector: string]: T; + } | ((type: NodeType) => T | undefined)): NodePropSource; /** - Create a mark decoration, which influences the styling of the - content in its range. Nested mark decorations will cause nested - DOM elements to be created. Nesting order is determined by - precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or - (below the facet-provided decorations) [view - plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split - on line boundaries and on the boundaries of higher-precedence - decorations. + Prop that is used to describe matching delimiters. For opening + delimiters, this holds an array of node names (written as a + space-separated string when declaring this prop in a grammar) + for the node types of closing delimiters that match it. */ - static mark(spec: MarkDecorationSpec): Decoration; + static closedBy: NodeProp; /** - Create a widget decoration, which adds an element at the given - position. + The inverse of [`closedBy`](#common.NodeProp^closedBy). This is + attached to closing delimiters, holding an array of node names + of types of matching opening delimiters. */ - static widget(spec: WidgetDecorationSpec): Decoration; + static openedBy: NodeProp; /** - Create a replace decoration which replaces the given range with - a widget, or simply hides it. + Used to assign node types to groups (for example, all node + types that represent an expression could be tagged with an + `"Expression"` group). */ - static replace(spec: ReplaceDecorationSpec): Decoration; + static group: NodeProp; /** - Create a line decoration, which can add DOM attributes to the - line starting at the given position. + The hash of the [context](#lr.ContextTracker.constructor) + that the node was parsed in, if any. Used to limit reuse of + contextual nodes. */ - static line(spec: LineDecorationSpec): Decoration; + static contextHash: NodeProp; /** - Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given - decorated range or ranges. If the ranges aren't already sorted, - pass `true` for `sort` to make the library sort them for you. + The distance beyond the end of the node that the tokenizer + looked ahead for any of the tokens inside the node. (The LR + parser only stores this when it is larger than 25, for + efficiency reasons.) */ - static set(of: Range | readonly Range[], sort?: boolean): DecorationSet; + static lookAhead: NodeProp; /** - The empty set of decorations. + This per-node prop is used to replace a given node, or part of a + node, with another tree. This is useful to include trees from + different languages in mixed-language parsers. */ - static none: DecorationSet; -} - -/** -Basic rectangle type. -*/ -interface Rect { - readonly left: number; - readonly right: number; - readonly top: number; - readonly bottom: number; + static mounted: NodeProp; } -declare type ScrollStrategy = "nearest" | "start" | "end" | "center"; - -/** -Command functions are used in key bindings and other types of user -actions. Given an editor view, they check whether their effect can -apply to the editor, and if it can, perform it as a side effect -(which usually means [dispatching](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) a -transaction) and return `true`. -*/ -declare type Command = (target: EditorView) => boolean; /** -This is the interface plugin objects conform to. +A mounted tree, which can be [stored](#common.NodeProp^mounted) on +a tree node to indicate that parts of its content are +represented by another tree. */ -interface PluginValue { +declare class MountedTree { /** - Notifies the plugin of an update that happened in the view. This - is called _before_ the view updates its own DOM. It is - responsible for updating the plugin's internal state (including - any state that may be read by plugin fields) and _writing_ to - the DOM for the changes in the update. To avoid unnecessary - layout recomputations, it should _not_ read the DOM layout—use - [`requestMeasure`](https://codemirror.net/6/docs/ref/#view.EditorView.requestMeasure) to schedule - your code in a DOM reading phase if you need to. + The inner tree. */ - update?(_update: ViewUpdate): void; + readonly tree: Tree; /** - Called when the plugin is no longer going to be used. Should - revert any changes the plugin made to the DOM. + If this is null, this tree replaces the entire node (it will + be included in the regular iteration instead of its host + node). If not, only the given ranges are considered to be + covered by this tree. This is used for trees that are mixed in + a way that isn't strictly hierarchical. Such mounted trees are + only entered by [`resolveInner`](#common.Tree.resolveInner) + and [`enter`](#common.SyntaxNode.enter). */ - destroy?(): void; + readonly overlay: readonly { + from: number; + to: number; + }[] | null; + /** + The parser used to create this subtree. + */ + readonly parser: Parser; + constructor( + /** + The inner tree. + */ + tree: Tree, + /** + If this is null, this tree replaces the entire node (it will + be included in the regular iteration instead of its host + node). If not, only the given ranges are considered to be + covered by this tree. This is used for trees that are mixed in + a way that isn't strictly hierarchical. Such mounted trees are + only entered by [`resolveInner`](#common.Tree.resolveInner) + and [`enter`](#common.SyntaxNode.enter). + */ + overlay: readonly { + from: number; + to: number; + }[] | null, + /** + The parser used to create this subtree. + */ + parser: Parser); } -declare const isFieldProvider: unique symbol; /** -Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which -[fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin) -provides. +Type returned by [`NodeProp.add`](#common.NodeProp.add). Describes +whether a prop should be added to a given node type in a node set, +and what value it should have. */ -declare class PluginFieldProvider { - private [isFieldProvider]; -} +type NodePropSource = (type: NodeType) => null | [NodeProp, any]; /** -Plugin fields are a mechanism for allowing plugins to provide -values that can be retrieved through the -[`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method. +Each node in a syntax tree has a node type associated with it. */ -declare class PluginField { +declare class NodeType { /** - Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field, - to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) - option. + The name of the node type. Not necessarily unique, but if the + grammar was written properly, different node types with the + same name within a node set should play the same semantic + role. */ - from(get: (value: V) => T): PluginFieldProvider; + readonly name: string; /** - Define a new plugin field. + The id of this node in its set. Corresponds to the term ids + used in the parser. */ - static define(): PluginField; + readonly id: number; /** - This field can be used by plugins to provide - [decorations](https://codemirror.net/6/docs/ref/#view.Decoration). - - **Note**: For reasons of data flow (plugins are only updated - after the viewport is computed), decorations produced by plugins - are _not_ taken into account when predicting the vertical layout - structure of the editor. They **must not** introduce block - widgets (that will raise an error) or replacing decorations that - cover line breaks (these will be ignored if they occur). Such - decorations, or others that cause a large amount of vertical - size shift compared to the undecorated content, should be - provided through the state-level [`decorations` - facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead. - */ - static decorations: PluginField; + Define a node type. + */ + static define(spec: { + /** + The ID of the node type. When this type is used in a + [set](#common.NodeSet), the ID must correspond to its index in + the type array. + */ + id: number; + /** + The name of the node type. Leave empty to define an anonymous + node. + */ + name?: string; + /** + [Node props](#common.NodeProp) to assign to the type. The value + given for any given prop should correspond to the prop's type. + */ + props?: readonly ([NodeProp, any] | NodePropSource)[]; + /** + Whether this is a [top node](#common.NodeType.isTop). + */ + top?: boolean; + /** + Whether this node counts as an [error + node](#common.NodeType.isError). + */ + error?: boolean; + /** + Whether this node is a [skipped](#common.NodeType.isSkipped) + node. + */ + skipped?: boolean; + }): NodeType; /** - Used to provide ranges that should be treated as atoms as far as - cursor motion is concerned. This causes methods like - [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and - [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the - commands built on top of them) to skip across such regions when - a selection endpoint would enter them. This does _not_ prevent - direct programmatic [selection - updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such - regions. + Retrieves a node prop for this type. Will return `undefined` if + the prop isn't present on this node. + */ + prop(prop: NodeProp): T | undefined; + /** + True when this is the top node of a grammar. */ - static atomicRanges: PluginField>; + get isTop(): boolean; /** - Plugins can provide additional scroll margins (space around the - sides of the scrolling element that should be considered - invisible) through this field. This can be useful when the - plugin introduces elements that cover part of that element (for - example a horizontally fixed gutter). + True when this node is produced by a skip rule. */ - static scrollMargins: PluginField | null>; -} -/** -Provides additional information when defining a [view -plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin). -*/ -interface PluginSpec { + get isSkipped(): boolean; /** - Register the given [event - handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers) for the plugin. - When called, these will have their `this` bound to the plugin - value. + Indicates whether this is an error node. */ - eventHandlers?: DOMEventHandlers; + get isError(): boolean; /** - Allow the plugin to provide decorations. When given, this should - a function that take the plugin value and return a [decoration - set](https://codemirror.net/6/docs/ref/#view.DecorationSet). See also the caveat about - [layout-changing decorations](https://codemirror.net/6/docs/ref/#view.PluginField^decorations) - from plugins. + When true, this node type doesn't correspond to a user-declared + named node, for example because it is used to cache repetition. */ - decorations?: (value: V) => DecorationSet; + get isAnonymous(): boolean; + /** + Returns true when this node's name or one of its + [groups](#common.NodeProp^group) matches the given string. + */ + is(name: string | number): boolean; /** - Specify that the plugin provides [plugin - field](https://codemirror.net/6/docs/ref/#view.PluginField) values. Use a field's - [`from`](https://codemirror.net/6/docs/ref/#view.PluginField.from) method to create these - providers. + An empty dummy node type to use when no actual type is available. */ - provide?: PluginFieldProvider | readonly PluginFieldProvider[]; + static none: NodeType; + /** + Create a function from node types to arbitrary values by + specifying an object whose property names are node or + [group](#common.NodeProp^group) names. Often useful with + [`NodeProp.add`](#common.NodeProp.add). You can put multiple + names, separated by spaces, in a single property name to map + multiple node names to a single value. + */ + static match(map: { + [selector: string]: T; + }): (node: NodeType) => T | undefined; } /** -View plugins associate stateful values with a view. They can -influence the way the content is drawn, and are notified of things -that happen in the view. +A node set holds a collection of node types. It is used to +compactly represent trees by storing their type ids, rather than a +full pointer to the type object, in a numeric array. Each parser +[has](#lr.LRParser.nodeSet) a node set, and [tree +buffers](#common.TreeBuffer) can only store collections of nodes +from the same set. A set can have a maximum of 2**16 (65536) node +types in it, so that the ids fit into 16-bit typed array slots. */ -declare class ViewPlugin { +declare class NodeSet { /** - Instances of this class act as extensions. + The node types in this set, by id. */ - extension: Extension; - private constructor(); + readonly types: readonly NodeType[]; /** - Define a plugin from a constructor function that creates the - plugin's value, given an editor view. + Create a set with the given types. The `id` property of each + type should correspond to its position within the array. */ - static define(create: (view: EditorView) => V, spec?: PluginSpec): ViewPlugin; + constructor( /** - Create a plugin for a class whose constructor takes a single - editor view as argument. + The node types in this set, by id. */ - static fromClass(cls: { - new (view: EditorView): V; - }, spec?: PluginSpec): ViewPlugin; + types: readonly NodeType[]); + /** + Create a copy of this set with some node properties added. The + arguments to this method can be created with + [`NodeProp.add`](#common.NodeProp.add). + */ + extend(...props: NodePropSource[]): NodeSet; } -interface MeasureRequest { +/** +Options that control iteration. Can be combined with the `|` +operator to enable multiple ones. +*/ +declare enum IterMode { /** - Called in a DOM read phase to gather information that requires - DOM layout. Should _not_ mutate the document. + When enabled, iteration will only visit [`Tree`](#common.Tree) + objects, not nodes packed into + [`TreeBuffer`](#common.TreeBuffer)s. */ - read(view: EditorView): T; + ExcludeBuffers = 1, /** - Called in a DOM write phase to update the document. Should _not_ - do anything that triggers DOM layout. + Enable this to make iteration include anonymous nodes (such as + the nodes that wrap repeated grammar constructs into a balanced + tree). */ - write?(measure: T, view: EditorView): void; + IncludeAnonymous = 2, /** - When multiple requests with the same key are scheduled, only the - last one will actually be ran. + By default, regular [mounted](#common.NodeProp^mounted) nodes + replace their base node in iteration. Enable this to ignore them + instead. */ - key?: any; + IgnoreMounts = 4, + /** + This option only applies in + [`enter`](#common.SyntaxNode.enter)-style methods. It tells the + library to not enter mounted overlays if one covers the given + position. + */ + IgnoreOverlays = 8 } -declare type AttrSource = Attrs | ((view: EditorView) => Attrs | null); /** -View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this -class, which describe what happened, whenever the view is updated. +A piece of syntax tree. There are two ways to approach these +trees: the way they are actually stored in memory, and the +convenient way. + +Syntax trees are stored as a tree of `Tree` and `TreeBuffer` +objects. By packing detail information into `TreeBuffer` leaf +nodes, the representation is made a lot more memory-efficient. + +However, when you want to actually work with tree nodes, this +representation is very awkward, so most client code will want to +use the [`TreeCursor`](#common.TreeCursor) or +[`SyntaxNode`](#common.SyntaxNode) interface instead, which provides +a view on some part of this data structure, and can be used to +move around to adjacent nodes. */ -declare class ViewUpdate { +declare class Tree { /** - The editor view that the update is associated with. + The type of the top node. */ - readonly view: EditorView; + readonly type: NodeType; /** - The new editor state. + This node's child nodes. */ - readonly state: EditorState; + readonly children: readonly (Tree | TreeBuffer)[]; /** - The transactions involved in the update. May be empty. + The positions (offsets relative to the start of this tree) of + the children. */ - readonly transactions: readonly Transaction[]; + readonly positions: readonly number[]; /** - The changes made to the document by this update. + The total length of this tree */ - readonly changes: ChangeSet; + readonly length: number; /** - The previous editor state. + Construct a new tree. See also [`Tree.build`](#common.Tree^build). */ - readonly startState: EditorState; + constructor( /** - Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or - [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this - update. + The type of the top node. */ - get viewportChanged(): boolean; + type: NodeType, /** - Indicates whether the height of an element in the editor changed - in this update. + This node's child nodes. */ - get heightChanged(): boolean; + children: readonly (Tree | TreeBuffer)[], /** - Returns true when the document was modified or the size of the - editor, or elements within the editor, changed. + The positions (offsets relative to the start of this tree) of + the children. */ - get geometryChanged(): boolean; + positions: readonly number[], /** - True when this update indicates a focus change. + The total length of this tree */ - get focusChanged(): boolean; + length: number, /** - Whether the document changed in this update. + Per-node [node props](#common.NodeProp) to associate with this node. */ - get docChanged(): boolean; + props?: readonly [NodeProp | number, any][]); /** - Whether the selection was explicitly set in this update. + The empty tree */ - get selectionSet(): boolean; -} - -/** -Interface that objects registered with -[`EditorView.mouseSelectionStyle`](https://codemirror.net/6/docs/ref/#view.EditorView^mouseSelectionStyle) -must conform to. -*/ -interface MouseSelectionStyle { + static empty: Tree; /** - Return a new selection for the mouse gesture that starts with - the event that was originally given to the constructor, and ends - with the event passed here. In case of a plain click, those may - both be the `mousedown` event, in case of a drag gesture, the - latest `mousemove` event will be passed. - - When `extend` is true, that means the new selection should, if - possible, extend the start selection. If `multiple` is true, the - new selection should be added to the original selection. + Get a [tree cursor](#common.TreeCursor) positioned at the top of + the tree. Mode can be used to [control](#common.IterMode) which + nodes the cursor visits. */ - get: (curEvent: MouseEvent, extend: boolean, multiple: boolean) => EditorSelection; + cursor(mode?: IterMode): TreeCursor; /** - Called when the view is updated while the gesture is in - progress. When the document changes, it may be necessary to map - some data (like the original selection or start position) - through the changes. + Get a [tree cursor](#common.TreeCursor) pointing into this tree + at the given position and side (see + [`moveTo`](#common.TreeCursor.moveTo). + */ + cursorAt(pos: number, side?: -1 | 0 | 1, mode?: IterMode): TreeCursor; + /** + Get a [syntax node](#common.SyntaxNode) object for the top of the + tree. + */ + get topNode(): SyntaxNode; + /** + Get the [syntax node](#common.SyntaxNode) at the given position. + If `side` is -1, this will move into nodes that end at the + position. If 1, it'll move into nodes that start at the + position. With 0, it'll only enter nodes that cover the position + from both sides. - This may return `true` to indicate that the `get` method should - get queried again after the update, because something in the - update could change its result. Be wary of infinite loops when - using this (where `get` returns a new selection, which will - trigger `update`, which schedules another `get` in response). + Note that this will not enter + [overlays](#common.MountedTree.overlay), and you often want + [`resolveInner`](#common.Tree.resolveInner) instead. */ - update: (update: ViewUpdate) => boolean | void; -} -declare type MakeSelectionStyle = (view: EditorView, event: MouseEvent) => MouseSelectionStyle | null; - -/** -Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). -*/ -declare enum Direction { + resolve(pos: number, side?: -1 | 0 | 1): SyntaxNode; /** - Left-to-right. + Like [`resolve`](#common.Tree.resolve), but will enter + [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node + pointing into the innermost overlaid tree at the given position + (with parent links going through all parent structure, including + the host trees). */ - LTR = 0, + resolveInner(pos: number, side?: -1 | 0 | 1): SyntaxNode; /** - Right-to-left. + In some situations, it can be useful to iterate through all + nodes around a position, including those in overlays that don't + directly cover the position. This method gives you an iterator + that will produce all nodes, from small to big, around the given + position. */ - RTL = 1 -} -/** -Represents a contiguous range of text that has a single direction -(as in left-to-right or right-to-left). -*/ -declare class BidiSpan { + resolveStack(pos: number, side?: -1 | 0 | 1): NodeIterator; /** - The start of the span (relative to the start of the line). + Iterate over the tree and its children, calling `enter` for any + node that touches the `from`/`to` region (if given) before + running over such a node's children, and `leave` (if given) when + leaving the node. When `enter` returns `false`, that node will + not have its children iterated over (or `leave` called). */ - readonly from: number; + iterate(spec: { + enter(node: SyntaxNodeRef): boolean | void; + leave?(node: SyntaxNodeRef): void; + from?: number; + to?: number; + mode?: IterMode; + }): void; /** - The end of the span. + Get the value of the given [node prop](#common.NodeProp) for this + node. Works with both per-node and per-type props. */ - readonly to: number; + prop(prop: NodeProp): T | undefined; /** - The ["bidi - level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) - of the span (in this context, 0 means - left-to-right, 1 means right-to-left, 2 means left-to-right - number inside right-to-left text). + Returns the node's [per-node props](#common.NodeProp.perNode) in a + format that can be passed to the [`Tree`](#common.Tree) + constructor. */ - readonly level: number; + get propValues(): readonly [NodeProp | number, any][]; /** - The direction of this span. + Balance the direct children of this tree, producing a copy of + which may have children grouped into subtrees with type + [`NodeType.none`](#common.NodeType^none). */ - get dir(): Direction; + balance(config?: { + /** + Function to create the newly balanced subtrees. + */ + makeTree?: (children: readonly (Tree | TreeBuffer)[], positions: readonly number[], length: number) => Tree; + }): Tree; + /** + Build a tree from a postfix-ordered buffer of node information, + or a cursor over such a buffer. + */ + static build(data: BuildData): Tree; } - /** -Record used to represent information about a block-level element -in the editor view. +Represents a sequence of nodes. */ -declare class BlockInfo { - /** - The start of the element in the document. - */ - readonly from: number; +type NodeIterator = { + node: SyntaxNode; + next: NodeIterator | null; +}; +type BuildData = { /** - The length of the element. + The buffer or buffer cursor to read the node data from. + + When this is an array, it should contain four values for every + node in the tree. + + - The first holds the node's type, as a node ID pointing into + the given `NodeSet`. + - The second holds the node's start offset. + - The third the end offset. + - The fourth the amount of space taken up in the array by this + node and its children. Since there's four values per node, + this is the total number of nodes inside this node (children + and transitive children) plus one for the node itself, times + four. + + Parent nodes should appear _after_ child nodes in the array. As + an example, a node of type 10 spanning positions 0 to 4, with + two children, of type 11 and 12, might look like this: + + [11, 0, 1, 4, 12, 2, 4, 4, 10, 0, 4, 12] */ - readonly length: number; + buffer: BufferCursor | readonly number[]; /** - The top position of the element (relative to the top of the - document). + The node types to use. */ - readonly top: number; + nodeSet: NodeSet; /** - Its height. + The id of the top node type. */ - readonly height: number; + topID: number; /** - The type of element this is. When querying lines, this may be - an array of all the blocks that make up the line. + The position the tree should start at. Defaults to 0. */ - readonly type: BlockType | readonly BlockInfo[]; + start?: number; /** - The end of the element as a document position. + The position in the buffer where the function should stop + reading. Defaults to 0. */ - get to(): number; + bufferStart?: number; /** - The bottom position of the element. + The length of the wrapping node. The end offset of the last + child is used when not provided. */ - get bottom(): number; -} - -interface EditorConfig { + length?: number; /** - The view's initial state. Defaults to an extension-less state - with an empty document. + The maximum buffer length to use. Defaults to + [`DefaultBufferLength`](#common.DefaultBufferLength). */ - state?: EditorState; + maxBufferLength?: number; /** - If the view is going to be mounted in a shadow root or document - other than the one held by the global variable `document` (the - default), you should pass it here. If you provide `parent`, but - not this option, the editor will automatically look up a root - from the parent. + An optional array holding reused nodes that the buffer can refer + to. */ - root?: Document | ShadowRoot; + reused?: readonly Tree[]; /** - Override the transaction [dispatch - function](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) for this editor view, which - is the way updates get routed to the view. Your implementation, - if provided, should probably call the view's [`update` - method](https://codemirror.net/6/docs/ref/#view.EditorView.update). + The first node type that indicates repeat constructs in this + grammar. */ - dispatch?: (tr: Transaction) => void; - /** - When given, the editor is immediately appended to the given - element on creation. (Otherwise, you'll have to place the view's - [`dom`](https://codemirror.net/6/docs/ref/#view.EditorView.dom) element in the document yourself.) - */ - parent?: Element | DocumentFragment; -} + minRepeatType?: number; +}; /** -An editor view represents the editor's user interface. It holds -the editable DOM surface, and possibly other elements such as the -line number gutter. It handles events and dispatches state -transactions for editing actions. +This is used by `Tree.build` as an abstraction for iterating over +a tree buffer. A cursor initially points at the very last element +in the buffer. Every time `next()` is called it moves on to the +previous one. */ -declare class EditorView { +interface BufferCursor { /** - The current editor state. + The current buffer position (four times the number of nodes + remaining). */ - get state(): EditorState; + pos: number; /** - To be able to display large documents without consuming too much - memory or overloading the browser, CodeMirror only draws the - code that is visible (plus a margin around it) to the DOM. This - property tells you the extent of the current drawn viewport, in - document positions. + The node ID of the next node in the buffer. */ - get viewport(): { - from: number; - to: number; - }; + id: number; /** - When there are, for example, large collapsed ranges in the - viewport, its size can be a lot bigger than the actual visible - content. Thus, if you are doing something like styling the - content in the viewport, it is preferable to only do so for - these ranges, which are the subset of the viewport that is - actually drawn. + The start position of the next node in the buffer. */ - get visibleRanges(): readonly { - from: number; - to: number; - }[]; + start: number; /** - Returns false when the editor is entirely scrolled out of view - or otherwise hidden. + The end position of the next node. */ - get inView(): boolean; + end: number; /** - Indicates whether the user is currently composing text via - [IME](https://en.wikipedia.org/wiki/Input_method). + The size of the next node (the number of nodes inside, counting + the node itself, times 4). */ - get composing(): boolean; - private _dispatch; + size: number; /** - The document or shadow root that the view lives in. + Moves `this.pos` down by 4. */ - readonly root: DocumentOrShadowRoot; + next(): void; /** - The DOM element that wraps the entire editor view. + Create a copy of this cursor. */ - readonly dom: HTMLElement; + fork(): BufferCursor; +} +/** +Tree buffers contain (type, start, end, endIndex) quads for each +node. In such a buffer, nodes are stored in prefix order (parents +before children, with the endIndex of the parent indicating which +children belong to it). +*/ +declare class TreeBuffer { /** - The DOM element that can be styled to scroll. (Note that it may - not have been, so you can't assume this is scrollable.) + The buffer's content. */ - readonly scrollDOM: HTMLElement; + readonly buffer: Uint16Array; /** - The editable DOM element holding the editor content. You should - not, usually, interact with this content directly though the - DOM, since the editor will immediately undo most of the changes - you make. Instead, [dispatch](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) - [transactions](https://codemirror.net/6/docs/ref/#state.Transaction) to modify content, and - [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) to style it. + The total length of the group of nodes in the buffer. */ - readonly contentDOM: HTMLElement; - private announceDOM; - private plugins; - private pluginMap; - private editorAttrs; - private contentAttrs; - private styleModules; - private bidiCache; - private destroyed; + readonly length: number; /** - Construct a new view. You'll usually want to put `view.dom` into - your document after creating a view, so that the user can see - it. + The node set used in this buffer. */ - constructor( + readonly set: NodeSet; /** - Initialization options. + Create a tree buffer. */ - config?: EditorConfig); + constructor( /** - All regular editor state updates should go through this. It - takes a transaction or transaction spec and updates the view to - show the new state produced by that transaction. Its - implementation can be overridden with an - [option](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.dispatch). This - function is bound to the view instance, so it does not have to - be called as a method. + The buffer's content. */ - dispatch(tr: Transaction): void; - dispatch(...specs: TransactionSpec[]): void; + buffer: Uint16Array, /** - Update the view for the given array of transactions. This will - update the visible document and selection to match the state - produced by the transactions, and notify view plugins of the - change. You should usually call - [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this - as a primitive. + The total length of the group of nodes in the buffer. */ - update(transactions: readonly Transaction[]): void; + length: number, /** - Reset the view to the given state. (This will cause the entire - document to be redrawn and all view plugins to be reinitialized, - so you should probably only use it when the new state isn't - derived from the old state. Otherwise, use - [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.) + The node set used in this buffer. */ - setState(newState: EditorState): void; - private updatePlugins; + set: NodeSet); +} +/** +The set of properties provided by both [`SyntaxNode`](#common.SyntaxNode) +and [`TreeCursor`](#common.TreeCursor). Note that, if you need +an object that is guaranteed to stay stable in the future, you +need to use the [`node`](#common.SyntaxNodeRef.node) accessor. +*/ +interface SyntaxNodeRef { /** - Get the CSS classes for the currently active editor themes. + The start position of the node. */ - get themeClasses(): string; - private updateAttrs; - private showAnnouncements; - private mountStyles; - private readMeasured; + readonly from: number; /** - Schedule a layout measurement, optionally providing callbacks to - do custom DOM measuring followed by a DOM write phase. Using - this is preferable reading DOM layout directly from, for - example, an event handler, because it'll make sure measuring and - drawing done by other components is synchronized, avoiding - unnecessary DOM layout computations. + The end position of the node. */ - requestMeasure(request?: MeasureRequest): void; + readonly to: number; /** - Collect all values provided by the active plugins for a given - field. + The type of the node. */ - pluginField(field: PluginField): readonly T[]; + readonly type: NodeType; /** - Get the value of a specific plugin, if present. Note that - plugins that crash can be dropped from a view, so even when you - know you registered a given plugin, it is recommended to check - the return value of this method. + The name of the node (`.type.name`). */ - plugin(plugin: ViewPlugin): T | null; + readonly name: string; /** - The top position of the document, in screen coordinates. This - may be negative when the editor is scrolled down. Points - directly to the top of the first line, not above the padding. + Get the [tree](#common.Tree) that represents the current node, + if any. Will return null when the node is in a [tree + buffer](#common.TreeBuffer). */ - get documentTop(): number; + readonly tree: Tree | null; /** - Reports the padding above and below the document. + Retrieve a stable [syntax node](#common.SyntaxNode) at this + position. */ - get documentPadding(): { - top: number; - bottom: number; - }; + readonly node: SyntaxNode; /** - Find the line or block widget at the given vertical position. - - By default, this position is interpreted as a screen position, - meaning `docTop` is set to the DOM top position of the editor - content (forcing a layout). You can pass a different `docTop` - value—for example 0 to interpret `height` as a document-relative - position, or a precomputed document top - (`view.contentDOM.getBoundingClientRect().top`) to limit layout - queries. - - *Deprecated: use `blockAtHeight` instead.* + Test whether the node matches a given context—a sequence of + direct parent nodes. Empty strings in the context array act as + wildcards, other strings must match the ancestor node's name. */ - blockAtHeight(height: number, docTop?: number): BlockInfo; + matchContext(context: readonly string[]): boolean; +} +/** +A syntax node provides an immutable pointer to a given node in a +tree. When iterating over large amounts of nodes, you may want to +use a mutable [cursor](#common.TreeCursor) instead, which is more +efficient. +*/ +interface SyntaxNode extends SyntaxNodeRef { /** - Find the text line or block widget at the given vertical - position (which is interpreted as relative to the [top of the - document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop) + The node's parent node, if any. */ - elementAtHeight(height: number): BlockInfo; + parent: SyntaxNode | null; /** - Find information for the visual line (see - [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given - vertical position. The resulting block info might hold another - array of block info structs in its `type` field if this line - consists of more than one block. - - Defaults to treating `height` as a screen position. See - [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the - interpretation of the `docTop` parameter. - - *Deprecated: use `lineBlockAtHeight` instead.* + The first child, if the node has children. */ - visualLineAtHeight(height: number, docTop?: number): BlockInfo; + firstChild: SyntaxNode | null; /** - Find the line block (see - [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given - height. + The node's last child, if available. */ - lineBlockAtHeight(height: number): BlockInfo; + lastChild: SyntaxNode | null; /** - Iterate over the height information of the visual lines in the - viewport. The heights of lines are reported relative to the - given document top, which defaults to the screen position of the - document (forcing a layout). - - *Deprecated: use `viewportLineBlocks` instead.* + The first child that ends after `pos`. */ - viewportLines(f: (line: BlockInfo) => void, docTop?: number): void; + childAfter(pos: number): SyntaxNode | null; /** - Get the extent and vertical position of all [line - blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions - are relative to the [top of the - document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop); + The last child that starts before `pos`. */ - get viewportLineBlocks(): BlockInfo[]; + childBefore(pos: number): SyntaxNode | null; /** - Find the extent and height of the visual line (a range delimited - on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) - line breaks, or the start/end of the document) at the given position. + Enter the child at the given position. If side is -1 the child + may end at that position, when 1 it may start there. - Vertical positions are computed relative to the `docTop` - argument, which defaults to 0 for this method. You can pass - `view.contentDOM.getBoundingClientRect().top` here to get screen - coordinates. + This will by default enter + [overlaid](#common.MountedTree.overlay) + [mounted](#common.NodeProp^mounted) trees. You can set + `overlays` to false to disable that. - *Deprecated: use `lineBlockAt` instead.* + Similarly, when `buffers` is false this will not enter + [buffers](#common.TreeBuffer), only [nodes](#common.Tree) (which + is mostly useful when looking for props, which cannot exist on + buffer-allocated nodes). */ - visualLineAt(pos: number, docTop?: number): BlockInfo; + enter(pos: number, side: -1 | 0 | 1, mode?: IterMode): SyntaxNode | null; /** - Find the line block around the given document position. A line - block is a range delimited on both sides by either a - non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the - start/end of the document. It will usually just hold a line of - text, but may be broken into multiple textblocks by block - widgets. + This node's next sibling, if any. */ - lineBlockAt(pos: number): BlockInfo; + nextSibling: SyntaxNode | null; /** - The editor's total content height. + This node's previous sibling. */ - get contentHeight(): number; + prevSibling: SyntaxNode | null; /** - Move a cursor position by [grapheme - cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether - the motion is away from the line start, or towards it. Motion in - bidirectional text is in visual order, in the editor's [text - direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start - position was the last one on the line, the returned position - will be across the line break. If there is no further line, the - original position is returned. - - By default, this method moves over a single cluster. The - optional `by` argument can be used to move across more. It will - be called with the first cluster as argument, and should return - a predicate that determines, for each subsequent cluster, - whether it should also be moved over. + A [tree cursor](#common.TreeCursor) starting at this node. */ - moveByChar(start: SelectionRange, forward: boolean, by?: (initial: string) => (next: string) => boolean): SelectionRange; + cursor(mode?: IterMode): TreeCursor; /** - Move a cursor position across the next group of either - [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter - non-whitespace characters. + Find the node around, before (if `side` is -1), or after (`side` + is 1) the given position. Will look in parent nodes if the + position is outside this node. */ - moveByGroup(start: SelectionRange, forward: boolean): SelectionRange; + resolve(pos: number, side?: -1 | 0 | 1): SyntaxNode; /** - Move to the next line boundary in the given direction. If - `includeWrap` is true, line wrapping is on, and there is a - further wrap point on the current line, the wrap point will be - returned. Otherwise this function will return the start or end - of the line. + Similar to `resolve`, but enter + [overlaid](#common.MountedTree.overlay) nodes. */ - moveToLineBoundary(start: SelectionRange, forward: boolean, includeWrap?: boolean): SelectionRange; + resolveInner(pos: number, side?: -1 | 0 | 1): SyntaxNode; /** - Move a cursor position vertically. When `distance` isn't given, - it defaults to moving to the next line (including wrapped - lines). Otherwise, `distance` should provide a positive distance - in pixels. - - When `start` has a - [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical - motion will use that as a target horizontal position. Otherwise, - the cursor's own horizontal position is used. The returned - cursor will have its goal column set to whichever column was - used. + Move the position to the innermost node before `pos` that looks + like it is unfinished (meaning it ends in an error node or has a + child ending in an error node right at its end). */ - moveVertically(start: SelectionRange, forward: boolean, distance?: number): SelectionRange; - scrollPosIntoView(pos: number): void; + enterUnfinishedNodesBefore(pos: number): SyntaxNode; /** - Find the DOM parent node and offset (child offset if `node` is - an element, character offset when it is a text node) at the - given document position. - - Note that for positions that aren't currently in - `visibleRanges`, the resulting DOM position isn't necessarily - meaningful (it may just point before or after a placeholder - element). + Get a [tree](#common.Tree) for this node. Will allocate one if it + points into a buffer. */ - domAtPos(pos: number): { - node: Node; - offset: number; - }; + toTree(): Tree; /** - Find the document position at the given DOM node. Can be useful - for associating positions with DOM events. Will raise an error - when `node` isn't part of the editor content. + Get the first child of the given type (which may be a [node + name](#common.NodeType.name) or a [group + name](#common.NodeProp^group)). If `before` is non-null, only + return children that occur somewhere after a node with that name + or group. If `after` is non-null, only return children that + occur somewhere before a node with that name or group. */ - posAtDOM(node: Node, offset?: number): number; + getChild(type: string | number, before?: string | number | null, after?: string | number | null): SyntaxNode | null; /** - Get the document position at the given screen coordinates. For - positions not covered by the visible viewport's DOM structure, - this will return null, unless `false` is passed as second - argument, in which case it'll return an estimated position that - would be near the coordinates if it were rendered. + Like [`getChild`](#common.SyntaxNode.getChild), but return all + matching children, not just the first. */ - posAtCoords(coords: { - x: number; - y: number; - }, precise: false): number; - posAtCoords(coords: { - x: number; - y: number; - }): number | null; + getChildren(type: string | number, before?: string | number | null, after?: string | number | null): SyntaxNode[]; +} +/** +A tree cursor object focuses on a given node in a syntax tree, and +allows you to move to adjacent nodes. +*/ +declare class TreeCursor implements SyntaxNodeRef { /** - Get the screen coordinates at the given document position. - `side` determines whether the coordinates are based on the - element before (-1) or after (1) the position (if no element is - available on the given side, the method will transparently use - another strategy to get reasonable coordinates). + The node's type. */ - coordsAtPos(pos: number, side?: -1 | 1): Rect | null; + type: NodeType; /** - The default width of a character in the editor. May not - accurately reflect the width of all characters (given variable - width fonts or styling of invididual ranges). + Shorthand for `.type.name`. */ - get defaultCharacterWidth(): number; + get name(): string; /** - The default height of a line in the editor. May not be accurate - for all lines. + The start source offset of this node. */ - get defaultLineHeight(): number; + from: number; /** - The text direction - ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction) - CSS property) of the editor. + The end source offset. */ - get textDirection(): Direction; + to: number; + private stack; + private bufferNode; + private yieldNode; + private yieldBuf; + private yield; /** - Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping) - (as determined by the - [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) - CSS property of its content element). - */ - get lineWrapping(): boolean; - /** - Returns the bidirectional text structure of the given line - (which should be in the current document) as an array of span - objects. The order of these spans matches the [text - direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is - left-to-right, the leftmost spans come first, otherwise the - rightmost spans come first. - */ - bidiSpans(line: Line$1): readonly BidiSpan[]; - /** - Check whether the editor has focus. + Move the cursor to this node's first child. When this returns + false, the node has no child, and the cursor has not been moved. */ - get hasFocus(): boolean; + firstChild(): boolean; /** - Put focus on the editor. + Move the cursor to this node's last child. */ - focus(): void; + lastChild(): boolean; /** - Clean up this editor view, removing its element from the - document, unregistering event handlers, and notifying - plugins. The view instance can no longer be used after - calling this. + Move the cursor to the first child that ends after `pos`. */ - destroy(): void; + childAfter(pos: number): boolean; /** - Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a - transaction to make it scroll the given range into view. - - *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. + Move to the last child that starts before `pos`. */ - static scrollTo: StateEffectType; + childBefore(pos: number): boolean; /** - Effect that makes the editor scroll the given range to the - center of the visible view. - - *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. + Move the cursor to the child around `pos`. If side is -1 the + child may end at that position, when 1 it may start there. This + will also enter [overlaid](#common.MountedTree.overlay) + [mounted](#common.NodeProp^mounted) trees unless `overlays` is + set to false. */ - static centerOn: StateEffectType; + enter(pos: number, side: -1 | 0 | 1, mode?: IterMode): boolean; /** - Returns an effect that can be - [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to - cause it to scroll the given position or range into view. + Move to the node's parent node, if this isn't the top node. */ - static scrollIntoView(pos: number | SelectionRange, options?: { - /** - By default (`"nearest"`) the position will be vertically - scrolled only the minimal amount required to move the given - position into view. You can set this to `"start"` to move it - to the top of the view, `"end"` to move it to the bottom, or - `"center"` to move it to the center. - */ - y?: ScrollStrategy; - /** - Effect similar to - [`y`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView^options.y), but for the - horizontal scroll position. - */ - x?: ScrollStrategy; - /** - Extra vertical distance to add when moving something into - view. Not used with the `"center"` strategy. Defaults to 5. - */ - yMargin?: number; - /** - Extra horizontal distance to add. Not used with the `"center"` - strategy. Defaults to 5. - */ - xMargin?: number; - }): StateEffect; + parent(): boolean; /** - Facet to add a [style - module](https://github.com/marijnh/style-mod#documentation) to - an editor view. The view will ensure that the module is - mounted in its [document - root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root). + Move to this node's next sibling, if any. */ - static styleModule: Facet; + nextSibling(): boolean; /** - Facet that can be used to add DOM event handlers. The value - should be an object mapping event names to handler functions. The - first such function to return true will be assumed to have handled - that event, and no other handlers or built-in behavior will be - activated for it. - These are registered on the [content - element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll` - handlers, which will be called any time the editor's [scroll - element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes - is scrolled. + Move to this node's previous sibling, if any. */ - static domEventHandlers(handlers: DOMEventHandlers): Extension; + prevSibling(): boolean; + private atLastNode; + private move; /** - An input handler can override the way changes to the editable - DOM content are handled. Handlers are passed the document - positions between which the change was found, and the new - content. When one returns true, no further input handlers are - called and the default behavior is prevented. + Move to the next node in a + [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order,_NLR) + traversal, going from a node to its first child or, if the + current node is empty or `enter` is false, its next sibling or + the next sibling of the first parent node that has one. */ - static inputHandler: Facet<(view: EditorView, from: number, to: number, text: string) => boolean, readonly ((view: EditorView, from: number, to: number, text: string) => boolean)[]>; + next(enter?: boolean): boolean; /** - Allows you to provide a function that should be called when the - library catches an exception from an extension (mostly from view - plugins, but may be used by other extensions to route exceptions - from user-code-provided callbacks). This is mostly useful for - debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException). + Move to the next node in a last-to-first pre-order traveral. A + node is followed by its last child or, if it has none, its + previous sibling or the previous sibling of the first parent + node that has one. */ - static exceptionSink: Facet<(exception: any) => void, readonly ((exception: any) => void)[]>; + prev(enter?: boolean): boolean; /** - A facet that can be used to register a function to be called - every time the view updates. + Move the cursor to the innermost node that covers `pos`. If + `side` is -1, it will enter nodes that end at `pos`. If it is 1, + it will enter nodes that start at `pos`. */ - static updateListener: Facet<(update: ViewUpdate) => void, readonly ((update: ViewUpdate) => void)[]>; + moveTo(pos: number, side?: -1 | 0 | 1): this; /** - Facet that controls whether the editor content DOM is editable. - When its highest-precedence value is `false`, the element will - not longer have its `contenteditable` attribute set. (Note that - this doesn't affect API calls that change the editor content, - even when those are bound to keys or buttons. See the - [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.) + Get a [syntax node](#common.SyntaxNode) at the cursor's current + position. */ - static editable: Facet; + get node(): SyntaxNode; /** - Allows you to influence the way mouse selection happens. The - functions in this facet will be called for a `mousedown` event - on the editor, and can return an object that overrides the way a - selection is computed from that mouse click or drag. + Get the [tree](#common.Tree) that represents the current node, if + any. Will return null when the node is in a [tree + buffer](#common.TreeBuffer). */ - static mouseSelectionStyle: Facet; + get tree(): Tree | null; /** - Facet used to configure whether a given selection drag event - should move or copy the selection. The given predicate will be - called with the `mousedown` event, and can return `true` when - the drag should move the content. + Iterate over the current node and all its descendants, calling + `enter` when entering a node and `leave`, if given, when leaving + one. When `enter` returns `false`, any children of that node are + skipped, and `leave` isn't called for it. */ - static dragMovesSelection: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>; + iterate(enter: (node: SyntaxNodeRef) => boolean | void, leave?: (node: SyntaxNodeRef) => void): void; /** - Facet used to configure whether a given selecting click adds - a new range to the existing selection or replaces it entirely. + Test whether the current node matches a given context—a sequence + of direct parent node names. Empty strings in the context array + are treated as wildcards. */ - static clickAddsSelectionRange: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>; + matchContext(context: readonly string[]): boolean; +} + +/** +Objects returned by the function passed to +[`parseMixed`](#common.parseMixed) should conform to this +interface. +*/ +interface NestedParse { /** - A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) - are shown in the view. See also [view - plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate - mechanism for providing decorations. + The parser to use for the inner region. */ - static decorations: Facet; + parser: Parser; /** - Create a theme extension. The first argument can be a - [`style-mod`](https://github.com/marijnh/style-mod#documentation) - style spec providing the styles for the theme. These will be - prefixed with a generated class for the style. + When this property is not given, the entire node is parsed with + this parser, and it is [mounted](#common.NodeProp^mounted) as a + non-overlay node, replacing its host node in tree iteration. - Because the selectors will be prefixed with a scope class, rule - that directly match the editor's [wrapper - element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be - added—need to be explicitly differentiated by adding an `&` to - the selector for that element—for example - `&.cm-focused`. + When an array of ranges is given, only those ranges are parsed, + and the tree is mounted as an + [overlay](#common.MountedTree.overlay). - When `dark` is set to true, the theme will be marked as dark, - which will cause the `&dark` rules from [base - themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to - `&light` when a light theme is active). + When a function is given, that function will be called for + descendant nodes of the target node, not including child nodes + that are covered by another nested parse, to determine the + overlay ranges. When it returns true, the entire descendant is + included, otherwise just the range given. The mixed parser will + optimize range-finding in reused nodes, which means it's a good + idea to use a function here when the target node is expected to + have a large, deep structure. */ - static theme(spec: { - [selector: string]: StyleSpec; - }, options?: { - dark?: boolean; - }): Extension; + overlay?: readonly { + from: number; + to: number; + }[] | ((node: SyntaxNodeRef) => { + from: number; + to: number; + } | boolean); +} +/** +Create a parse wrapper that, after the inner parse completes, +scans its tree for mixed language regions with the `nest` +function, runs the resulting [inner parses](#common.NestedParse), +and then [mounts](#common.NodeProp^mounted) their results onto the +tree. +*/ +declare function parseMixed(nest: (node: SyntaxNodeRef, input: Input) => NestedParse | null): ParseWrapper; + +/** +A parse stack. These are used internally by the parser to track +parsing progress. They also provide some properties and methods +that external code such as a tokenizer can use to get information +about the parse state. +*/ +declare class Stack { /** - Create an extension that adds styles to the base theme. Like - with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the - place of the editor wrapper element when directly targeting - that. You can also use `&dark` or `&light` instead to only - target editors with a dark or light theme. + The input position up to which this stack has parsed. */ - static baseTheme(spec: { - [selector: string]: StyleSpec; - }): Extension; + pos: number; /** - Facet that provides additional DOM attributes for the editor's - editable DOM element. + The stack's current [context](#lr.ContextTracker) value, if + any. Its type will depend on the context tracker's type + parameter, or it will be `null` if there is no context + tracker. */ - static contentAttributes: Facet; + get context(): any; /** - Facet that provides DOM attributes for the editor's outer - element. + Check if the given term would be able to be shifted (optionally + after some reductions) on this stack. This can be useful for + external tokenizers that want to make sure they only provide a + given token when it applies. */ - static editorAttributes: Facet; + canShift(term: number): boolean; /** - An extension that enables line wrapping in the editor (by - setting CSS `white-space` to `pre-wrap` in the content). + Get the parser used by this stack. */ - static lineWrapping: Extension; + get parser(): LRParser; /** - State effect used to include screen reader announcements in a - transaction. These will be added to the DOM in a visually hidden - element with `aria-live="polite"` set, and should be used to - describe effects that are visually obvious but may not be - noticed by screen reader users (such as moving to the next - search match). + Test whether a given dialect (by numeric ID, as exported from + the terms file) is enabled. */ - static announce: StateEffectType; -} -/** -Helper type that maps event names to event object types, or the -`any` type for unknown events. -*/ -interface DOMEventMap extends HTMLElementEventMap { - [other: string]: any; + dialectEnabled(dialectID: number): boolean; + private shiftContext; + private reduceContext; + private updateContext; } -/** -Event handlers are specified with objects like this. For event -types known by TypeScript, this will infer the event argument type -to hold the appropriate event object type. For unknown events, it -is inferred to `any`, and should be explicitly set if you want type -checking. -*/ -declare type DOMEventHandlers = { - [event in keyof DOMEventMap]?: (this: This, event: DOMEventMap[event], view: EditorView) => boolean | void; -}; /** -Key bindings associate key names with -[command](https://codemirror.net/6/docs/ref/#view.Command)-style functions. - -Key names may be strings like `"Shift-Ctrl-Enter"`—a key identifier -prefixed with zero or more modifiers. Key identifiers are based on -the strings that can appear in -[`KeyEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key). -Use lowercase letters to refer to letter keys (or uppercase letters -if you want shift to be held). You may use `"Space"` as an alias -for the `" "` name. - -Modifiers can be given in any order. `Shift-` (or `s-`), `Alt-` (or -`a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or -`Meta-`) are recognized. - -When a key binding contains multiple key names separated by -spaces, it represents a multi-stroke binding, which will fire when -the user presses the given keys after each other order. - -You can use `Mod-` as a shorthand for `Cmd-` on Mac and `Ctrl-` on -other platforms. So `Mod-b` is `Ctrl-b` on Linux but `Cmd-b` on -macOS. +[Tokenizers](#lr.ExternalTokenizer) interact with the input +through this interface. It presents the input as a stream of +characters, tracking lookahead and hiding the complexity of +[ranges](#common.Parser.parse^ranges) from tokenizer code. */ -interface KeyBinding { +declare class InputStream { /** - The key name to use for this binding. If the platform-specific - property (`mac`, `win`, or `linux`) for the current platform is - used as well in the binding, that one takes precedence. If `key` - isn't defined and the platform-specific binding isn't either, - a binding is ignored. + Backup chunk */ - key?: string; + private chunk2; + private chunk2Pos; /** - Key to use specifically on macOS. + The character code of the next code unit in the input, or -1 + when the stream is at the end of the input. */ - mac?: string; + next: number; /** - Key to use specifically on Windows. + The current position of the stream. Note that, due to parses + being able to cover non-contiguous + [ranges](#common.Parser.startParse), advancing the stream does + not always mean its position moves a single unit. */ - win?: string; + pos: number; + private rangeIndex; + private range; /** - Key to use specifically on Linux. + Look at a code unit near the stream position. `.peek(0)` equals + `.next`, `.peek(-1)` gives you the previous character, and so + on. + + Note that looking around during tokenizing creates dependencies + on potentially far-away content, which may reduce the + effectiveness incremental parsing—when looking forward—or even + cause invalid reparses when looking backward more than 25 code + units, since the library does not track lookbehind. */ - linux?: string; + peek(offset: number): number; /** - The command to execute when this binding is triggered. When the - command function returns `false`, further bindings will be tried - for the key. + Accept a token. By default, the end of the token is set to the + current stream position, but you can pass an offset (relative to + the stream position) to change that. */ - run: Command; + acceptToken(token: number, endOffset?: number): void; + private getChunk; + private readNext; /** - When given, this defines a second binding, using the (possibly - platform-specific) key name prefixed with `Shift-` to activate - this command. + Move the stream forward N (defaults to 1) code units. Returns + the new value of [`next`](#lr.InputStream.next). */ - shift?: Command; + advance(n?: number): number; + private setDone; +} +interface ExternalOptions { /** - By default, key bindings apply when focus is on the editor - content (the `"editor"` scope). Some extensions, mostly those - that define their own panels, might want to allow you to - register bindings local to that panel. Such bindings should use - a custom scope name. You may also set multiple scope names, - separated by spaces. + When set to true, mark this tokenizer as depending on the + current parse stack, which prevents its result from being cached + between parser actions at the same positions. */ - scope?: string; + contextual?: boolean; /** - When set to true (the default is false), this will always - prevent the further handling for the bound key, even if the - command(s) return false. This can be useful for cases where the - native behavior of the key is annoying or irrelevant but the - command doesn't always apply (such as, Mod-u for undo selection, - which would cause the browser to view source instead when no - selection can be undone). + By defaults, when a tokenizer returns a token, that prevents + tokenizers with lower precedence from even running. When + `fallback` is true, the tokenizer is allowed to run when a + previous tokenizer returned a token that didn't match any of the + current state's actions. */ - preventDefault?: boolean; + fallback?: boolean; + /** + When set to true, tokenizing will not stop after this tokenizer + has produced a token. (But it will still fail to reach this one + if a higher-precedence tokenizer produced a token.) + */ + extend?: boolean; } /** -Facet used for registering keymaps. - -You can add multiple keymaps to an editor. Their priorities -determine their precedence (the ones specified early or with high -priority get checked first). When a handler has returned `true` -for a given key, no further handlers are called. +`@external tokens` declarations in the grammar should resolve to +an instance of this class. */ -declare const keymap: Facet; - -declare type SelectionConfig = { +declare class ExternalTokenizer { /** - The length of a full cursor blink cycle, in milliseconds. - Defaults to 1200. Can be set to 0 to disable blinking. + Create a tokenizer. The first argument is the function that, + given an input stream, scans for the types of tokens it + recognizes at the stream's position, and calls + [`acceptToken`](#lr.InputStream.acceptToken) when it finds + one. */ - cursorBlinkRate?: number; + constructor( /** - Whether to show a cursor for non-empty ranges. Defaults to - true. + @internal */ - drawRangeCursor?: boolean; -}; + token: (input: InputStream, stack: Stack) => void, options?: ExternalOptions); +} + /** -Returns an extension that hides the browser's native selection and -cursor, replacing the selection with a background behind the text -(with the `cm-selectionBackground` class), and the -cursors with elements overlaid over the code (using -`cm-cursor-primary` and `cm-cursor-secondary`). +Context trackers are used to track stateful context (such as +indentation in the Python grammar, or parent elements in the XML +grammar) needed by external tokenizers. You declare them in a +grammar file as `@context exportName from "module"`. -This allows the editor to display secondary selection ranges, and -tends to produce a type of selection more in line with that users -expect in a text editor (the native selection styling will often -leave gaps between lines and won't fill the horizontal space after -a line when the selection continues past it). +Context values should be immutable, and can be updated (replaced) +on shift or reduce actions. -It does have a performance cost, in that it requires an extra DOM -layout cycle for many updates (the selection is drawn based on DOM -layout information that's only available after laying out the -content). +The export used in a `@context` declaration should be of this +type. */ -declare function drawSelection(config?: SelectionConfig): Extension; - -interface SpecialCharConfig { - /** - An optional function that renders the placeholder elements. - - The `description` argument will be text that clarifies what the - character is, which should be provided to screen readers (for - example with the - [`aria-label`](https://www.w3.org/TR/wai-aria/#aria-label) - attribute) and optionally shown to the user in other ways (such - as the - [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title) - attribute). - - The given placeholder string is a suggestion for how to display - the character visually. - */ - render?: ((code: number, description: string | null, placeholder: string) => HTMLElement) | null; - /** - Regular expression that matches the special characters to - highlight. Must have its 'g'/global flag set. - */ - specialChars?: RegExp; +declare class ContextTracker { /** - Regular expression that can be used to add characters to the - default set of characters to highlight. + Define a context tracker. */ - addSpecialChars?: RegExp | null; + constructor(spec: { + /** + The initial value of the context at the start of the parse. + */ + start: T; + /** + Update the context when the parser executes a + [shift](https://en.wikipedia.org/wiki/LR_parser#Shift_and_reduce_actions) + action. + */ + shift?(context: T, term: number, stack: Stack, input: InputStream): T; + /** + Update the context when the parser executes a reduce action. + */ + reduce?(context: T, term: number, stack: Stack, input: InputStream): T; + /** + Update the context when the parser reuses a node from a tree + fragment. + */ + reuse?(context: T, node: Tree, stack: Stack, input: InputStream): T; + /** + Reduce a context value to a number (for cheap storage and + comparison). Only needed for strict contexts. + */ + hash?(context: T): number; + /** + By default, nodes can only be reused during incremental + parsing if they were created in the same context as the one in + which they are reused. Set this to false to disable that + check (and the overhead of storing the hashes). + */ + strict?: boolean; + }); } /** -Returns an extension that installs highlighting of special -characters. -*/ -declare function highlightSpecialChars( -/** -Configuration options. -*/ -config?: SpecialCharConfig): Extension; - -/** -Extension that enables a placeholder—a piece of example content -to show when the editor is empty. -*/ -declare function placeholder(content: string | HTMLElement): Extension; - -/** -A language object manages parsing and per-language -[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is -managed as a [Lezer](https://lezer.codemirror.net) tree. You'll -want to subclass this class for custom parsers, or use the -[`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage) or -[`StreamLanguage`](https://codemirror.net/6/docs/ref/#stream-parser.StreamLanguage) abstractions for -[Lezer](https://lezer.codemirror.net/) or stream parsers. +Configuration options when +[reconfiguring](#lr.LRParser.configure) a parser. */ -declare class Language { - /** - The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) data - facet used for this language. - */ - readonly data: Facet<{ - [name: string]: any; - }>; +interface ParserConfig { /** - The node type of the top node of trees produced by this parser. + Node prop values to add to the parser's node set. */ - readonly topNode: NodeType; + props?: readonly NodePropSource[]; /** - The extension value to install this provider. + The name of the `@top` declaration to parse from. If not + specified, the first top rule declaration in the grammar is + used. */ - readonly extension: Extension; + top?: string; /** - The parser object. Can be useful when using this as a [nested - parser](https://lezer.codemirror.net/docs/ref#common.Parser). + A space-separated string of dialects to enable. */ - parser: Parser; + dialect?: string; /** - Construct a language object. You usually don't need to invoke - this directly. But when you do, make sure you use - [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet) to create - the first argument. + Replace the given external tokenizers with new ones. */ - constructor( + tokenizers?: { + from: ExternalTokenizer; + to: ExternalTokenizer; + }[]; /** - The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) data - facet used for this language. + Replace external specializers with new ones. */ - data: Facet<{ - [name: string]: any; - }>, parser: Parser, + specializers?: { + from: (value: string, stack: Stack) => number; + to: (value: string, stack: Stack) => number; + }[]; /** - The node type of the top node of trees produced by this parser. + Replace the context tracker with a new one. */ - topNode: NodeType, extraExtensions?: Extension[]); + contextTracker?: ContextTracker; /** - Query whether this language is active at the given position. + When true, the parser will raise an exception, rather than run + its error-recovery strategies, when the input doesn't match the + grammar. */ - isActiveAt(state: EditorState, pos: number, side?: -1 | 0 | 1): boolean; + strict?: boolean; /** - Find the document regions that were parsed using this language. - The returned regions will _include_ any nested languages rooted - in this language, when those exist. + Add a wrapper, which can extend parses created by this parser + with additional logic (usually used to add + [mixed-language](#common.parseMixed) parsing). */ - findRegions(state: EditorState): { - from: number; - to: number; - }[]; + wrap?: ParseWrapper; /** - Indicates whether this language allows nested languages. The - default implementation returns true. + The maximum length of the TreeBuffers generated in the output + tree. Defaults to 1024. */ - get allowsNesting(): boolean; + bufferLength?: number; } /** -A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer -[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser) -parsers. +Holds the parse tables for a given grammar, as generated by +`lezer-generator`, and provides [methods](#common.Parser) to parse +content with. */ -declare class LRLanguage extends Language { - readonly parser: LRParser; - private constructor(); +declare class LRParser extends Parser { /** - Define a language from a parser. + The nodes used in the trees emitted by this parser. */ - static define(spec: { - /** - The parser to use. Should already have added editor-relevant - node props (and optionally things like dialect and top rule) - configured. - */ - parser: LRParser; - /** - [Language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) - to register for this language. - */ - languageData?: { - [name: string]: any; - }; - }): LRLanguage; + readonly nodeSet: NodeSet; + createParse(input: Input, fragments: readonly TreeFragment[], ranges: readonly { + from: number; + to: number; + }[]): PartialParse; /** - Create a new instance of this language with a reconfigured - version of its parser. + Configure the parser. Returns a new parser instance that has the + given settings modified. Settings not provided in `config` are + kept from the original parser. */ - configure(options: ParserConfig): LRLanguage; - get allowsNesting(): boolean; -} -/** -Get the syntax tree for a state, which is the current (possibly -incomplete) parse tree of active [language](https://codemirror.net/6/docs/ref/#language.Language), -or the empty tree if there is no language available. -*/ -declare function syntaxTree(state: EditorState): Tree; -/** -This class bundles a [language object](https://codemirror.net/6/docs/ref/#language.Language) with an -optional set of supporting extensions. Language packages are -encouraged to export a function that optionally takes a -configuration object and returns a `LanguageSupport` instance, as -the main way for client code to use the package. -*/ -declare class LanguageSupport { + configure(config: ParserConfig): LRParser; /** - The language object. + Tells you whether any [parse wrappers](#lr.ParserConfig.wrap) + are registered for this parser. */ - readonly language: Language; + hasWrappers(): boolean; /** - An optional set of supporting extensions. When nesting a - language in another language, the outer language is encouraged - to include the supporting extensions for its inner languages - in its own set of support extensions. + Returns the name associated with a given term. This will only + work for all terms when the parser was generated with the + `--names` option. By default, only the names of tagged terms are + stored. */ - readonly support: Extension; + getName(term: number): string; /** - An extension including both the language and its support - extensions. (Allowing the object to be used as an extension - value itself.) + The type of top node produced by the parser. */ - extension: Extension; + get topNode(): NodeType; /** - Create a support object. + Used by the output of the parser generator. Not available to + user code. @hide */ - constructor( + static deserialize(spec: any): LRParser; +} + +declare class StyleModule { + constructor(spec: {[selector: string]: StyleSpec}, options?: { + finish?(sel: string): string + }) + getRules(): string + static mount( + root: Document | ShadowRoot | DocumentOrShadowRoot, + module: StyleModule | ReadonlyArray, + options?: {nonce?: string} + ): void + static newName(): string +} + +type StyleSpec = { + [propOrSelector: string]: string | number | StyleSpec | null +} + +/** +Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). +*/ +declare enum Direction { /** - The language object. + Left-to-right. */ - language: Language, + LTR = 0, /** - An optional set of supporting extensions. When nesting a - language in another language, the outer language is encouraged - to include the supporting extensions for its inner languages - in its own set of support extensions. + Right-to-left. */ - support?: Extension); + RTL = 1 } /** -Language descriptions are used to store metadata about languages -and to dynamically load them. Their main role is finding the -appropriate language for a filename or dynamically loading nested -parsers. +Represents a contiguous range of text that has a single direction +(as in left-to-right or right-to-left). */ -declare class LanguageDescription { - /** - The name of this language. - */ - readonly name: string; +declare class BidiSpan { /** - Alternative names for the mode (lowercased, includes `this.name`). + The start of the span (relative to the start of the line). */ - readonly alias: readonly string[]; + readonly from: number; /** - File extensions associated with this language. + The end of the span. */ - readonly extensions: readonly string[]; + readonly to: number; /** - Optional filename pattern that should be associated with this - language. + The ["bidi + level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) + of the span (in this context, 0 means + left-to-right, 1 means right-to-left, 2 means left-to-right + number inside right-to-left text). + */ + readonly level: number; + /** + The direction of this span. + */ + get dir(): Direction; +} + +type Attrs = { + [name: string]: string; +}; + +/** +Basic rectangle type. +*/ +interface Rect { + readonly left: number; + readonly right: number; + readonly top: number; + readonly bottom: number; +} +type ScrollStrategy = "nearest" | "start" | "end" | "center"; + +interface MarkDecorationSpec { + /** + Whether the mark covers its start and end position or not. This + influences whether content inserted at those positions becomes + part of the mark. Defaults to false. + */ + inclusive?: boolean; + /** + Specify whether the start position of the marked range should be + inclusive. Overrides `inclusive`, when both are present. + */ + inclusiveStart?: boolean; + /** + Whether the end should be inclusive. + */ + inclusiveEnd?: boolean; + /** + Add attributes to the DOM elements that hold the text in the + marked range. + */ + attributes?: { + [key: string]: string; + }; + /** + Shorthand for `{attributes: {class: value}}`. + */ + class?: string; + /** + Add a wrapping element around the text in the marked range. Note + that there will not necessarily be a single element covering the + entire range—other decorations with lower precedence might split + this one if they partially overlap it, and line breaks always + end decoration elements. + */ + tagName?: string; + /** + When using sets of decorations in + [`bidiIsolatedRanges`](https://codemirror.net/6/docs/ref/##view.EditorView^bidiIsolatedRanges), + this property provides the direction of the isolates. + */ + bidiIsolate?: Direction; + /** + Decoration specs allow extra properties, which can be retrieved + through the decoration's [`spec`](https://codemirror.net/6/docs/ref/#view.Decoration.spec) + property. + */ + [other: string]: any; +} +interface WidgetDecorationSpec { + /** + The type of widget to draw here. + */ + widget: WidgetType; + /** + Which side of the given position the widget is on. When this is + positive, the widget will be drawn after the cursor if the + cursor is on the same position. Otherwise, it'll be drawn before + it. When multiple widgets sit at the same position, their `side` + values will determine their ordering—those with a lower value + come first. Defaults to 0. May not be more than 10000 or less + than -10000. + */ + side?: number; + /** + By default, to avoid unintended mixing of block and inline + widgets, block widgets with a positive `side` are always drawn + after all inline widgets at that position, and those with a + non-positive side before inline widgets. Setting this option to + `true` for a block widget will turn this off and cause it to be + rendered between the inline widgets, ordered by `side`. + */ + inlineOrder?: boolean; + /** + Determines whether this is a block widgets, which will be drawn + between lines, or an inline widget (the default) which is drawn + between the surrounding text. + + Note that block-level decorations should not have vertical + margins, and if you dynamically change their height, you should + make sure to call + [`requestMeasure`](https://codemirror.net/6/docs/ref/#view.EditorView.requestMeasure), so that the + editor can update its information about its vertical layout. + */ + block?: boolean; + /** + Other properties are allowed. + */ + [other: string]: any; +} +interface ReplaceDecorationSpec { + /** + An optional widget to drawn in the place of the replaced + content. + */ + widget?: WidgetType; + /** + Whether this range covers the positions on its sides. This + influences whether new content becomes part of the range and + whether the cursor can be drawn on its sides. Defaults to false + for inline replacements, and true for block replacements. + */ + inclusive?: boolean; + /** + Set inclusivity at the start. + */ + inclusiveStart?: boolean; + /** + Set inclusivity at the end. + */ + inclusiveEnd?: boolean; + /** + Whether this is a block-level decoration. Defaults to false. + */ + block?: boolean; + /** + Other properties are allowed. + */ + [other: string]: any; +} +interface LineDecorationSpec { + /** + DOM attributes to add to the element wrapping the line. + */ + attributes?: { + [key: string]: string; + }; + /** + Shorthand for `{attributes: {class: value}}`. + */ + class?: string; + /** + Other properties are allowed. + */ + [other: string]: any; +} +/** +Widgets added to the content are described by subclasses of this +class. Using a description object like that makes it possible to +delay creating of the DOM structure for a widget until it is +needed, and to avoid redrawing widgets even if the decorations +that define them are recreated. +*/ +declare abstract class WidgetType { + /** + Build the DOM structure for this widget instance. + */ + abstract toDOM(view: EditorView): HTMLElement; + /** + Compare this instance to another instance of the same type. + (TypeScript can't express this, but only instances of the same + specific class will be passed to this method.) This is used to + avoid redrawing widgets when they are replaced by a new + decoration of the same type. The default implementation just + returns `false`, which will cause new instances of the widget to + always be redrawn. + */ + eq(widget: WidgetType): boolean; + /** + Update a DOM element created by a widget of the same type (but + different, non-`eq` content) to reflect this widget. May return + true to indicate that it could update, false to indicate it + couldn't (in which case the widget will be redrawn). The default + implementation just returns false. + */ + updateDOM(dom: HTMLElement, view: EditorView): boolean; + /** + The estimated height this widget will have, to be used when + estimating the height of content that hasn't been drawn. May + return -1 to indicate you don't know. The default implementation + returns -1. + */ + get estimatedHeight(): number; + /** + For inline widgets that are displayed inline (as opposed to + `inline-block`) and introduce line breaks (through `
` tags + or textual newlines), this must indicate the amount of line + breaks they introduce. Defaults to 0. + */ + get lineBreaks(): number; + /** + Can be used to configure which kinds of events inside the widget + should be ignored by the editor. The default is to ignore all + events. + */ + ignoreEvent(event: Event): boolean; + /** + Override the way screen coordinates for positions at/in the + widget are found. `pos` will be the offset into the widget, and + `side` the side of the position that is being queried—less than + zero for before, greater than zero for after, and zero for + directly at that position. + */ + coordsAt(dom: HTMLElement, pos: number, side: number): Rect | null; + /** + This is called when the an instance of the widget is removed + from the editor view. + */ + destroy(dom: HTMLElement): void; +} +/** +A decoration set represents a collection of decorated ranges, +organized for efficient access and mapping. See +[`RangeSet`](https://codemirror.net/6/docs/ref/#state.RangeSet) for its methods. +*/ +type DecorationSet = RangeSet; +/** +The different types of blocks that can occur in an editor view. +*/ +declare enum BlockType { + /** + A line of text. + */ + Text = 0, + /** + A block widget associated with the position after it. + */ + WidgetBefore = 1, + /** + A block widget associated with the position before it. + */ + WidgetAfter = 2, + /** + A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content. + */ + WidgetRange = 3 +} +/** +A decoration provides information on how to draw or style a piece +of content. You'll usually use it wrapped in a +[`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position. +@nonabstract +*/ +declare abstract class Decoration extends RangeValue { + /** + The config object used to create this decoration. You can + include additional properties in there to store metadata about + your decoration. + */ + readonly spec: any; + protected constructor( + /** + @internal + */ + startSide: number, + /** + @internal + */ + endSide: number, + /** + @internal + */ + widget: WidgetType | null, + /** + The config object used to create this decoration. You can + include additional properties in there to store metadata about + your decoration. + */ + spec: any); + abstract eq(other: Decoration): boolean; + /** + Create a mark decoration, which influences the styling of the + content in its range. Nested mark decorations will cause nested + DOM elements to be created. Nesting order is determined by + precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with + the higher-precedence decorations creating the inner DOM nodes. + Such elements are split on line boundaries and on the boundaries + of lower-precedence decorations. + */ + static mark(spec: MarkDecorationSpec): Decoration; + /** + Create a widget decoration, which displays a DOM element at the + given position. + */ + static widget(spec: WidgetDecorationSpec): Decoration; + /** + Create a replace decoration which replaces the given range with + a widget, or simply hides it. + */ + static replace(spec: ReplaceDecorationSpec): Decoration; + /** + Create a line decoration, which can add DOM attributes to the + line starting at the given position. + */ + static line(spec: LineDecorationSpec): Decoration; + /** + Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given + decorated range or ranges. If the ranges aren't already sorted, + pass `true` for `sort` to make the library sort them for you. + */ + static set(of: Range | readonly Range[], sort?: boolean): DecorationSet; + /** + The empty set of decorations. + */ + static none: DecorationSet; +} + +/** +Command functions are used in key bindings and other types of user +actions. Given an editor view, they check whether their effect can +apply to the editor, and if it can, perform it as a side effect +(which usually means [dispatching](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) a +transaction) and return `true`. +*/ +type Command = (target: EditorView) => boolean; +/** +This is the interface plugin objects conform to. +*/ +interface PluginValue extends Object { + /** + Notifies the plugin of an update that happened in the view. This + is called _before_ the view updates its own DOM. It is + responsible for updating the plugin's internal state (including + any state that may be read by plugin fields) and _writing_ to + the DOM for the changes in the update. To avoid unnecessary + layout recomputations, it should _not_ read the DOM layout—use + [`requestMeasure`](https://codemirror.net/6/docs/ref/#view.EditorView.requestMeasure) to schedule + your code in a DOM reading phase if you need to. + */ + update?(update: ViewUpdate): void; + /** + Called when the plugin is no longer going to be used. Should + revert any changes the plugin made to the DOM. + */ + destroy?(): void; +} +/** +Provides additional information when defining a [view +plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin). +*/ +interface PluginSpec { + /** + Register the given [event + handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers) for the plugin. + When called, these will have their `this` bound to the plugin + value. + */ + eventHandlers?: DOMEventHandlers; + /** + Registers [event observers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventObservers) + for the plugin. Will, when called, have their `this` bound to + the plugin value. + */ + eventObservers?: DOMEventHandlers; + /** + Specify that the plugin provides additional extensions when + added to an editor configuration. + */ + provide?: (plugin: ViewPlugin) => Extension; + /** + Allow the plugin to provide decorations. When given, this should + be a function that take the plugin value and return a + [decoration set](https://codemirror.net/6/docs/ref/#view.DecorationSet). See also the caveat about + [layout-changing decorations](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) that + depend on the view. + */ + decorations?: (value: V) => DecorationSet; +} +/** +View plugins associate stateful values with a view. They can +influence the way the content is drawn, and are notified of things +that happen in the view. +*/ +declare class ViewPlugin { + /** + Instances of this class act as extensions. + */ + extension: Extension; + private constructor(); + /** + Define a plugin from a constructor function that creates the + plugin's value, given an editor view. + */ + static define(create: (view: EditorView) => V, spec?: PluginSpec): ViewPlugin; + /** + Create a plugin for a class whose constructor takes a single + editor view as argument. + */ + static fromClass(cls: { + new (view: EditorView): V; + }, spec?: PluginSpec): ViewPlugin; +} +interface MeasureRequest { + /** + Called in a DOM read phase to gather information that requires + DOM layout. Should _not_ mutate the document. + */ + read(view: EditorView): T; + /** + Called in a DOM write phase to update the document. Should _not_ + do anything that triggers DOM layout. + */ + write?(measure: T, view: EditorView): void; + /** + When multiple requests with the same key are scheduled, only the + last one will actually be ran. + */ + key?: any; +} +type AttrSource = Attrs | ((view: EditorView) => Attrs | null); +/** +View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this +class, which describe what happened, whenever the view is updated. +*/ +declare class ViewUpdate { + /** + The editor view that the update is associated with. + */ + readonly view: EditorView; + /** + The new editor state. + */ + readonly state: EditorState; + /** + The transactions involved in the update. May be empty. + */ + readonly transactions: readonly Transaction[]; + /** + The changes made to the document by this update. + */ + readonly changes: ChangeSet; + /** + The previous editor state. + */ + readonly startState: EditorState; + private constructor(); + /** + Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or + [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this + update. + */ + get viewportChanged(): boolean; + /** + Indicates whether the height of a block element in the editor + changed in this update. + */ + get heightChanged(): boolean; + /** + Returns true when the document was modified or the size of the + editor, or elements within the editor, changed. + */ + get geometryChanged(): boolean; + /** + True when this update indicates a focus change. + */ + get focusChanged(): boolean; + /** + Whether the document changed in this update. + */ + get docChanged(): boolean; + /** + Whether the selection was explicitly set in this update. + */ + get selectionSet(): boolean; +} + +/** +Interface that objects registered with +[`EditorView.mouseSelectionStyle`](https://codemirror.net/6/docs/ref/#view.EditorView^mouseSelectionStyle) +must conform to. +*/ +interface MouseSelectionStyle { + /** + Return a new selection for the mouse gesture that starts with + the event that was originally given to the constructor, and ends + with the event passed here. In case of a plain click, those may + both be the `mousedown` event, in case of a drag gesture, the + latest `mousemove` event will be passed. + + When `extend` is true, that means the new selection should, if + possible, extend the start selection. If `multiple` is true, the + new selection should be added to the original selection. + */ + get: (curEvent: MouseEvent, extend: boolean, multiple: boolean) => EditorSelection; + /** + Called when the view is updated while the gesture is in + progress. When the document changes, it may be necessary to map + some data (like the original selection or start position) + through the changes. + + This may return `true` to indicate that the `get` method should + get queried again after the update, because something in the + update could change its result. Be wary of infinite loops when + using this (where `get` returns a new selection, which will + trigger `update`, which schedules another `get` in response). + */ + update: (update: ViewUpdate) => boolean | void; +} +type MakeSelectionStyle = (view: EditorView, event: MouseEvent) => MouseSelectionStyle | null; + +/** +Record used to represent information about a block-level element +in the editor view. +*/ +declare class BlockInfo { + /** + The start of the element in the document. + */ + readonly from: number; + /** + The length of the element. + */ + readonly length: number; + /** + The top position of the element (relative to the top of the + document). + */ + readonly top: number; + /** + Its height. + */ + readonly height: number; + /** + The type of element this is. When querying lines, this may be + an array of all the blocks that make up the line. + */ + get type(): BlockType | readonly BlockInfo[]; + /** + The end of the element as a document position. + */ + get to(): number; + /** + The bottom position of the element. + */ + get bottom(): number; + /** + If this is a widget block, this will return the widget + associated with it. + */ + get widget(): WidgetType | null; + /** + If this is a textblock, this holds the number of line breaks + that appear in widgets inside the block. + */ + get widgetLineBreaks(): number; +} + +/** +The type of object given to the [`EditorView`](https://codemirror.net/6/docs/ref/#view.EditorView) +constructor. +*/ +interface EditorViewConfig extends EditorStateConfig { + /** + The view's initial state. If not given, a new state is created + by passing this configuration object to + [`EditorState.create`](https://codemirror.net/6/docs/ref/#state.EditorState^create), using its + `doc`, `selection`, and `extensions` field (if provided). + */ + state?: EditorState; + /** + When given, the editor is immediately appended to the given + element on creation. (Otherwise, you'll have to place the view's + [`dom`](https://codemirror.net/6/docs/ref/#view.EditorView.dom) element in the document yourself.) + */ + parent?: Element | DocumentFragment; + /** + If the view is going to be mounted in a shadow root or document + other than the one held by the global variable `document` (the + default), you should pass it here. If you provide `parent`, but + not this option, the editor will automatically look up a root + from the parent. + */ + root?: Document | ShadowRoot; + /** + Override the way transactions are + [dispatched](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) for this editor view. + Your implementation, if provided, should probably call the + view's [`update` method](https://codemirror.net/6/docs/ref/#view.EditorView.update). + */ + dispatchTransactions?: (trs: readonly Transaction[], view: EditorView) => void; + /** + **Deprecated** single-transaction version of + `dispatchTransactions`. Will force transactions to be dispatched + one at a time when used. + */ + dispatch?: (tr: Transaction, view: EditorView) => void; +} +/** +An editor view represents the editor's user interface. It holds +the editable DOM surface, and possibly other elements such as the +line number gutter. It handles events and dispatches state +transactions for editing actions. +*/ +declare class EditorView { + /** + The current editor state. + */ + get state(): EditorState; + /** + To be able to display large documents without consuming too much + memory or overloading the browser, CodeMirror only draws the + code that is visible (plus a margin around it) to the DOM. This + property tells you the extent of the current drawn viewport, in + document positions. + */ + get viewport(): { + from: number; + to: number; + }; + /** + When there are, for example, large collapsed ranges in the + viewport, its size can be a lot bigger than the actual visible + content. Thus, if you are doing something like styling the + content in the viewport, it is preferable to only do so for + these ranges, which are the subset of the viewport that is + actually drawn. + */ + get visibleRanges(): readonly { + from: number; + to: number; + }[]; + /** + Returns false when the editor is entirely scrolled out of view + or otherwise hidden. + */ + get inView(): boolean; + /** + Indicates whether the user is currently composing text via + [IME](https://en.wikipedia.org/wiki/Input_method), and at least + one change has been made in the current composition. + */ + get composing(): boolean; + /** + Indicates whether the user is currently in composing state. Note + that on some platforms, like Android, this will be the case a + lot, since just putting the cursor on a word starts a + composition there. + */ + get compositionStarted(): boolean; + private dispatchTransactions; + private _root; + /** + The document or shadow root that the view lives in. + */ + get root(): DocumentOrShadowRoot; + /** + The DOM element that wraps the entire editor view. + */ + readonly dom: HTMLElement; + /** + The DOM element that can be styled to scroll. (Note that it may + not have been, so you can't assume this is scrollable.) + */ + readonly scrollDOM: HTMLElement; + /** + The editable DOM element holding the editor content. You should + not, usually, interact with this content directly though the + DOM, since the editor will immediately undo most of the changes + you make. Instead, [dispatch](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) + [transactions](https://codemirror.net/6/docs/ref/#state.Transaction) to modify content, and + [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) to style it. + */ + readonly contentDOM: HTMLElement; + private announceDOM; + private plugins; + private pluginMap; + private editorAttrs; + private contentAttrs; + private styleModules; + private bidiCache; + private destroyed; + /** + Construct a new view. You'll want to either provide a `parent` + option, or put `view.dom` into your document after creating a + view, so that the user can see the editor. + */ + constructor(config?: EditorViewConfig); + /** + All regular editor state updates should go through this. It + takes a transaction, array of transactions, or transaction spec + and updates the view to show the new state produced by that + transaction. Its implementation can be overridden with an + [option](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.dispatchTransactions). + This function is bound to the view instance, so it does not have + to be called as a method. + + Note that when multiple `TransactionSpec` arguments are + provided, these define a single transaction (the specs will be + merged), not a sequence of transactions. + */ + dispatch(tr: Transaction): void; + dispatch(trs: readonly Transaction[]): void; + dispatch(...specs: TransactionSpec[]): void; + /** + Update the view for the given array of transactions. This will + update the visible document and selection to match the state + produced by the transactions, and notify view plugins of the + change. You should usually call + [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this + as a primitive. + */ + update(transactions: readonly Transaction[]): void; + /** + Reset the view to the given state. (This will cause the entire + document to be redrawn and all view plugins to be reinitialized, + so you should probably only use it when the new state isn't + derived from the old state. Otherwise, use + [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.) + */ + setState(newState: EditorState): void; + private updatePlugins; + /** + Get the CSS classes for the currently active editor themes. + */ + get themeClasses(): string; + private updateAttrs; + private showAnnouncements; + private mountStyles; + private readMeasured; + /** + Schedule a layout measurement, optionally providing callbacks to + do custom DOM measuring followed by a DOM write phase. Using + this is preferable reading DOM layout directly from, for + example, an event handler, because it'll make sure measuring and + drawing done by other components is synchronized, avoiding + unnecessary DOM layout computations. + */ + requestMeasure(request?: MeasureRequest): void; + /** + Get the value of a specific plugin, if present. Note that + plugins that crash can be dropped from a view, so even when you + know you registered a given plugin, it is recommended to check + the return value of this method. + */ + plugin(plugin: ViewPlugin): T | null; + /** + The top position of the document, in screen coordinates. This + may be negative when the editor is scrolled down. Points + directly to the top of the first line, not above the padding. + */ + get documentTop(): number; + /** + Reports the padding above and below the document. + */ + get documentPadding(): { + top: number; + bottom: number; + }; + /** + If the editor is transformed with CSS, this provides the scale + along the X axis. Otherwise, it will just be 1. Note that + transforms other than translation and scaling are not supported. + */ + get scaleX(): number; + /** + Provide the CSS transformed scale along the Y axis. + */ + get scaleY(): number; + /** + Find the text line or block widget at the given vertical + position (which is interpreted as relative to the [top of the + document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)). + */ + elementAtHeight(height: number): BlockInfo; + /** + Find the line block (see + [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given + height, again interpreted relative to the [top of the + document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop). + */ + lineBlockAtHeight(height: number): BlockInfo; + /** + Get the extent and vertical position of all [line + blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions + are relative to the [top of the + document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop); + */ + get viewportLineBlocks(): BlockInfo[]; + /** + Find the line block around the given document position. A line + block is a range delimited on both sides by either a + non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the + start/end of the document. It will usually just hold a line of + text, but may be broken into multiple textblocks by block + widgets. + */ + lineBlockAt(pos: number): BlockInfo; + /** + The editor's total content height. + */ + get contentHeight(): number; + /** + Move a cursor position by [grapheme + cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether + the motion is away from the line start, or towards it. In + bidirectional text, the line is traversed in visual order, using + the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). + When the start position was the last one on the line, the + returned position will be across the line break. If there is no + further line, the original position is returned. + + By default, this method moves over a single cluster. The + optional `by` argument can be used to move across more. It will + be called with the first cluster as argument, and should return + a predicate that determines, for each subsequent cluster, + whether it should also be moved over. + */ + moveByChar(start: SelectionRange, forward: boolean, by?: (initial: string) => (next: string) => boolean): SelectionRange; + /** + Move a cursor position across the next group of either + [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter + non-whitespace characters. + */ + moveByGroup(start: SelectionRange, forward: boolean): SelectionRange; + /** + Move to the next line boundary in the given direction. If + `includeWrap` is true, line wrapping is on, and there is a + further wrap point on the current line, the wrap point will be + returned. Otherwise this function will return the start or end + of the line. + */ + moveToLineBoundary(start: SelectionRange, forward: boolean, includeWrap?: boolean): SelectionRange; + /** + Move a cursor position vertically. When `distance` isn't given, + it defaults to moving to the next line (including wrapped + lines). Otherwise, `distance` should provide a positive distance + in pixels. + + When `start` has a + [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical + motion will use that as a target horizontal position. Otherwise, + the cursor's own horizontal position is used. The returned + cursor will have its goal column set to whichever column was + used. + */ + moveVertically(start: SelectionRange, forward: boolean, distance?: number): SelectionRange; + /** + Find the DOM parent node and offset (child offset if `node` is + an element, character offset when it is a text node) at the + given document position. + + Note that for positions that aren't currently in + `visibleRanges`, the resulting DOM position isn't necessarily + meaningful (it may just point before or after a placeholder + element). + */ + domAtPos(pos: number): { + node: Node; + offset: number; + }; + /** + Find the document position at the given DOM node. Can be useful + for associating positions with DOM events. Will raise an error + when `node` isn't part of the editor content. + */ + posAtDOM(node: Node, offset?: number): number; + /** + Get the document position at the given screen coordinates. For + positions not covered by the visible viewport's DOM structure, + this will return null, unless `false` is passed as second + argument, in which case it'll return an estimated position that + would be near the coordinates if it were rendered. + */ + posAtCoords(coords: { + x: number; + y: number; + }, precise: false): number; + posAtCoords(coords: { + x: number; + y: number; + }): number | null; + /** + Get the screen coordinates at the given document position. + `side` determines whether the coordinates are based on the + element before (-1) or after (1) the position (if no element is + available on the given side, the method will transparently use + another strategy to get reasonable coordinates). + */ + coordsAtPos(pos: number, side?: -1 | 1): Rect | null; + /** + Return the rectangle around a given character. If `pos` does not + point in front of a character that is in the viewport and + rendered (i.e. not replaced, not a line break), this will return + null. For space characters that are a line wrap point, this will + return the position before the line break. + */ + coordsForChar(pos: number): Rect | null; + /** + The default width of a character in the editor. May not + accurately reflect the width of all characters (given variable + width fonts or styling of invididual ranges). + */ + get defaultCharacterWidth(): number; + /** + The default height of a line in the editor. May not be accurate + for all lines. + */ + get defaultLineHeight(): number; + /** + The text direction + ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction) + CSS property) of the editor's content element. + */ + get textDirection(): Direction; + /** + Find the text direction of the block at the given position, as + assigned by CSS. If + [`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection) + isn't enabled, or the given position is outside of the viewport, + this will always return the same as + [`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that + this may trigger a DOM layout. */ - readonly filename: RegExp | undefined; - private loadFunc; + textDirectionAt(pos: number): Direction; /** - If the language has been loaded, this will hold its value. + Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping) + (as determined by the + [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) + CSS property of its content element). */ - support: LanguageSupport | undefined; - private loading; - private constructor(); + get lineWrapping(): boolean; /** - Start loading the the language. Will return a promise that - resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport) - object when the language successfully loads. + Returns the bidirectional text structure of the given line + (which should be in the current document) as an array of span + objects. The order of these spans matches the [text + direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is + left-to-right, the leftmost spans come first, otherwise the + rightmost spans come first. */ - load(): Promise; + bidiSpans(line: Line$1): readonly BidiSpan[]; /** - Create a language description. + Check whether the editor has focus. */ - static of(spec: { - /** - The language's name. - */ - name: string; - /** - An optional array of alternative names. - */ - alias?: readonly string[]; + get hasFocus(): boolean; + /** + Put focus on the editor. + */ + focus(): void; + /** + Update the [root](https://codemirror.net/6/docs/ref/##view.EditorViewConfig.root) in which the editor lives. This is only + necessary when moving the editor's existing DOM to a new window or shadow root. + */ + setRoot(root: Document | ShadowRoot): void; + /** + Clean up this editor view, removing its element from the + document, unregistering event handlers, and notifying + plugins. The view instance can no longer be used after + calling this. + */ + destroy(): void; + /** + Returns an effect that can be + [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to + cause it to scroll the given position or range into view. + */ + static scrollIntoView(pos: number | SelectionRange, options?: { /** - An optional array of filename extensions associated with this - language. + By default (`"nearest"`) the position will be vertically + scrolled only the minimal amount required to move the given + position into view. You can set this to `"start"` to move it + to the top of the view, `"end"` to move it to the bottom, or + `"center"` to move it to the center. */ - extensions?: readonly string[]; + y?: ScrollStrategy; /** - An optional filename pattern associated with this language. + Effect similar to + [`y`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView^options.y), but for the + horizontal scroll position. */ - filename?: RegExp; + x?: ScrollStrategy; /** - A function that will asynchronously load the language. + Extra vertical distance to add when moving something into + view. Not used with the `"center"` strategy. Defaults to 5. */ - load?: () => Promise; + yMargin?: number; /** - Alternatively to `load`, you can provide an already loaded - support object. Either this or `load` should be provided. + Extra horizontal distance to add. Not used with the `"center"` + strategy. Defaults to 5. */ - support?: LanguageSupport; - }): LanguageDescription; + xMargin?: number; + }): StateEffect; /** - Look for a language in the given array of descriptions that - matches the filename. Will first match - [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns, - and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions), - and return the first language that matches. + Facet to add a [style + module](https://github.com/marijnh/style-mod#documentation) to + an editor view. The view will ensure that the module is + mounted in its [document + root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root). */ - static matchFilename(descs: readonly LanguageDescription[], filename: string): LanguageDescription | null; + static styleModule: Facet; /** - Look for a language whose name or alias matches the the given - name (case-insensitively). If `fuzzy` is true, and no direct - matchs is found, this'll also search for a language whose name - or alias occurs in the string (for names shorter than three - characters, only when surrounded by non-word characters). + Returns an extension that can be used to add DOM event handlers. + The value should be an object mapping event names to handler + functions. For any given event, such functions are ordered by + extension precedence, and the first handler to return true will + be assumed to have handled that event, and no other handlers or + built-in behavior will be activated for it. These are registered + on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except + for `scroll` handlers, which will be called any time the + editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of + its parent nodes is scrolled. */ - static matchLanguageName(descs: readonly LanguageDescription[], name: string, fuzzy?: boolean): LanguageDescription | null; + static domEventHandlers(handlers: DOMEventHandlers): Extension; + /** + Create an extension that registers DOM event observers. Contrary + to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers), + observers can't be prevented from running by a higher-precedence + handler returning true. They also don't prevent other handlers + and observers from running when they return true, and should not + call `preventDefault`. + */ + static domEventObservers(observers: DOMEventHandlers): Extension; + /** + An input handler can override the way changes to the editable + DOM content are handled. Handlers are passed the document + positions between which the change was found, and the new + content. When one returns true, no further input handlers are + called and the default behavior is prevented. + + The `insert` argument can be used to get the default transaction + that would be applied for this input. This can be useful when + dispatching the custom behavior as a separate transaction. + */ + static inputHandler: Facet<(view: EditorView, from: number, to: number, text: string, insert: () => Transaction) => boolean, readonly ((view: EditorView, from: number, to: number, text: string, insert: () => Transaction) => boolean)[]>; + /** + This facet can be used to provide functions that create effects + to be dispatched when the editor's focus state changes. + */ + static focusChangeEffect: Facet<(state: EditorState, focusing: boolean) => StateEffect | null, readonly ((state: EditorState, focusing: boolean) => StateEffect | null)[]>; + /** + By default, the editor assumes all its content has the same + [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true` + value to make it read the text direction of every (rendered) + line separately. + */ + static perLineTextDirection: Facet; + /** + Allows you to provide a function that should be called when the + library catches an exception from an extension (mostly from view + plugins, but may be used by other extensions to route exceptions + from user-code-provided callbacks). This is mostly useful for + debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException). + */ + static exceptionSink: Facet<(exception: any) => void, readonly ((exception: any) => void)[]>; + /** + A facet that can be used to register a function to be called + every time the view updates. + */ + static updateListener: Facet<(update: ViewUpdate) => void, readonly ((update: ViewUpdate) => void)[]>; + /** + Facet that controls whether the editor content DOM is editable. + When its highest-precedence value is `false`, the element will + not have its `contenteditable` attribute set. (Note that this + doesn't affect API calls that change the editor content, even + when those are bound to keys or buttons. See the + [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.) + */ + static editable: Facet; + /** + Allows you to influence the way mouse selection happens. The + functions in this facet will be called for a `mousedown` event + on the editor, and can return an object that overrides the way a + selection is computed from that mouse click or drag. + */ + static mouseSelectionStyle: Facet; + /** + Facet used to configure whether a given selection drag event + should move or copy the selection. The given predicate will be + called with the `mousedown` event, and can return `true` when + the drag should move the content. + */ + static dragMovesSelection: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>; + /** + Facet used to configure whether a given selecting click adds a + new range to the existing selection or replaces it entirely. The + default behavior is to check `event.metaKey` on macOS, and + `event.ctrlKey` elsewhere. + */ + static clickAddsSelectionRange: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>; + /** + A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) + are shown in the view. Decorations can be provided in two + ways—directly, or via a function that takes an editor view. + + Only decoration sets provided directly are allowed to influence + the editor's vertical layout structure. The ones provided as + functions are called _after_ the new viewport has been computed, + and thus **must not** introduce block widgets or replacing + decorations that cover line breaks. + + If you want decorated ranges to behave like atomic units for + cursor motion and deletion purposes, also provide the range set + containing the decorations to + [`EditorView.atomicRanges`](https://codemirror.net/6/docs/ref/#view.EditorView^atomicRanges). + */ + static decorations: Facet DecorationSet), readonly (DecorationSet | ((view: EditorView) => DecorationSet))[]>; + /** + Used to provide ranges that should be treated as atoms as far as + cursor motion is concerned. This causes methods like + [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and + [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the + commands built on top of them) to skip across such regions when + a selection endpoint would enter them. This does _not_ prevent + direct programmatic [selection + updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such + regions. + */ + static atomicRanges: Facet<(view: EditorView) => RangeSet, readonly ((view: EditorView) => RangeSet)[]>; + /** + When range decorations add a `unicode-bidi: isolate` style, they + should also include a + [`bidiIsolate`](https://codemirror.net/6/docs/ref/#view.MarkDecorationSpec.bidiIsolate) property + in their decoration spec, and be exposed through this facet, so + that the editor can compute the proper text order. (Other values + for `unicode-bidi`, except of course `normal`, are not + supported.) + */ + static bidiIsolatedRanges: Facet DecorationSet), readonly (DecorationSet | ((view: EditorView) => DecorationSet))[]>; + /** + Facet that allows extensions to provide additional scroll + margins (space around the sides of the scrolling element that + should be considered invisible). This can be useful when the + plugin introduces elements that cover part of that element (for + example a horizontally fixed gutter). + */ + static scrollMargins: Facet<(view: EditorView) => Partial | null, readonly ((view: EditorView) => Partial | null)[]>; + /** + Create a theme extension. The first argument can be a + [`style-mod`](https://github.com/marijnh/style-mod#documentation) + style spec providing the styles for the theme. These will be + prefixed with a generated class for the style. + + Because the selectors will be prefixed with a scope class, rule + that directly match the editor's [wrapper + element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be + added—need to be explicitly differentiated by adding an `&` to + the selector for that element—for example + `&.cm-focused`. + + When `dark` is set to true, the theme will be marked as dark, + which will cause the `&dark` rules from [base + themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to + `&light` when a light theme is active). + */ + static theme(spec: { + [selector: string]: StyleSpec; + }, options?: { + dark?: boolean; + }): Extension; + /** + This facet records whether a dark theme is active. The extension + returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically + includes an instance of this when the `dark` option is set to + true. + */ + static darkTheme: Facet; + /** + Create an extension that adds styles to the base theme. Like + with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the + place of the editor wrapper element when directly targeting + that. You can also use `&dark` or `&light` instead to only + target editors with a dark or light theme. + */ + static baseTheme(spec: { + [selector: string]: StyleSpec; + }): Extension; + /** + Provides a Content Security Policy nonce to use when creating + the style sheets for the editor. Holds the empty string when no + nonce has been provided. + */ + static cspNonce: Facet; + /** + Facet that provides additional DOM attributes for the editor's + editable DOM element. + */ + static contentAttributes: Facet; + /** + Facet that provides DOM attributes for the editor's outer + element. + */ + static editorAttributes: Facet; + /** + An extension that enables line wrapping in the editor (by + setting CSS `white-space` to `pre-wrap` in the content). + */ + static lineWrapping: Extension; + /** + State effect used to include screen reader announcements in a + transaction. These will be added to the DOM in a visually hidden + element with `aria-live="polite"` set, and should be used to + describe effects that are visually obvious but may not be + noticed by screen reader users (such as moving to the next + search match). + */ + static announce: StateEffectType; + /** + Retrieve an editor view instance from the view's DOM + representation. + */ + static findFromDOM(dom: HTMLElement): EditorView | null; } /** -Facet for overriding the unit by which indentation happens. -Should be a string consisting either entirely of spaces or -entirely of tabs. When not set, this defaults to 2 spaces. +Helper type that maps event names to event object types, or the +`any` type for unknown events. */ -declare const indentUnit: Facet; +interface DOMEventMap extends HTMLElementEventMap { + [other: string]: any; +} +/** +Event handlers are specified with objects like this. For event +types known by TypeScript, this will infer the event argument type +to hold the appropriate event object type. For unknown events, it +is inferred to `any`, and should be explicitly set if you want type +checking. +*/ +type DOMEventHandlers = { + [event in keyof DOMEventMap]?: (this: This, event: DOMEventMap[event], view: EditorView) => boolean | void; +}; + /** -Indentation contexts are used when calling [indentation -services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities -useful in indentation logic, and can selectively override the -indentation reported for some lines. +Key bindings associate key names with +[command](https://codemirror.net/6/docs/ref/#view.Command)-style functions. + +Key names may be strings like `"Shift-Ctrl-Enter"`—a key identifier +prefixed with zero or more modifiers. Key identifiers are based on +the strings that can appear in +[`KeyEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key). +Use lowercase letters to refer to letter keys (or uppercase letters +if you want shift to be held). You may use `"Space"` as an alias +for the `" "` name. + +Modifiers can be given in any order. `Shift-` (or `s-`), `Alt-` (or +`a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or +`Meta-`) are recognized. + +When a key binding contains multiple key names separated by +spaces, it represents a multi-stroke binding, which will fire when +the user presses the given keys after each other. + +You can use `Mod-` as a shorthand for `Cmd-` on Mac and `Ctrl-` on +other platforms. So `Mod-b` is `Ctrl-b` on Linux but `Cmd-b` on +macOS. */ -declare class IndentContext { - /** - The editor state. - */ - readonly state: EditorState; +interface KeyBinding { /** - The indent unit (number of columns per indentation level). + The key name to use for this binding. If the platform-specific + property (`mac`, `win`, or `linux`) for the current platform is + used as well in the binding, that one takes precedence. If `key` + isn't defined and the platform-specific binding isn't either, + a binding is ignored. */ - unit: number; + key?: string; /** - Create an indent context. + Key to use specifically on macOS. */ - constructor( + mac?: string; /** - The editor state. + Key to use specifically on Windows. */ - state: EditorState, + win?: string; /** - @internal + Key to use specifically on Linux. */ - options?: { - /** - Override line indentations provided to the indentation - helper function, which is useful when implementing region - indentation, where indentation for later lines needs to refer - to previous lines, which may have been reindented compared to - the original start state. If given, this function should - return -1 for lines (given by start position) that didn't - change, and an updated indentation otherwise. - */ - overrideIndentation?: (pos: number) => number; - /** - Make it look, to the indent logic, like a line break was - added at the given position (which is mostly just useful for - implementing something like - [`insertNewlineAndIndent`](https://codemirror.net/6/docs/ref/#commands.insertNewlineAndIndent)). - */ - simulateBreak?: number; - /** - When `simulateBreak` is given, this can be used to make the - simulate break behave like a double line break. - */ - simulateDoubleBreak?: boolean; - }); + linux?: string; /** - Get a description of the line at the given position, taking - [simulated line - breaks](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) - into account. If there is such a break at `pos`, the `bias` - argument determines whether the part of the line line before or - after the break is used. + The command to execute when this binding is triggered. When the + command function returns `false`, further bindings will be tried + for the key. */ - lineAt(pos: number, bias?: -1 | 1): { - text: string; - from: number; - }; + run?: Command; /** - Get the text directly after `pos`, either the entire line - or the next 100 characters, whichever is shorter. + When given, this defines a second binding, using the (possibly + platform-specific) key name prefixed with `Shift-` to activate + this command. */ - textAfterPos(pos: number, bias?: -1 | 1): string; + shift?: Command; /** - Find the column for the given position. + When this property is present, the function is called for every + key that is not a multi-stroke prefix. */ - column(pos: number, bias?: -1 | 1): number; + any?: (view: EditorView, event: KeyboardEvent) => boolean; /** - Find the column position (taking tabs into account) of the given - position in the given string. + By default, key bindings apply when focus is on the editor + content (the `"editor"` scope). Some extensions, mostly those + that define their own panels, might want to allow you to + register bindings local to that panel. Such bindings should use + a custom scope name. You may also assign multiple scope names to + a binding, separating them by spaces. */ - countColumn(line: string, pos?: number): number; + scope?: string; /** - Find the indentation column of the line at the given point. + When set to true (the default is false), this will always + prevent the further handling for the bound key, even if the + command(s) return false. This can be useful for cases where the + native behavior of the key is annoying or irrelevant but the + command doesn't always apply (such as, Mod-u for undo selection, + which would cause the browser to view source instead when no + selection can be undone). */ - lineIndent(pos: number, bias?: -1 | 1): number; + preventDefault?: boolean; /** - Returns the [simulated line - break](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) - for this context, if any. + When set to true, `stopPropagation` will be called on keyboard + events that have their `preventDefault` called in response to + this key binding (see also + [`preventDefault`](https://codemirror.net/6/docs/ref/#view.KeyBinding.preventDefault)). */ - get simulatedBreak(): number | null; + stopPropagation?: boolean; } /** -Enables reindentation on input. When a language defines an -`indentOnInput` field in its [language -data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular -expression, the line at the cursor will be reindented whenever new -text is typed and the input from the start of the line up to the -cursor matches that regexp. +Facet used for registering keymaps. -To avoid unneccesary reindents, it is recommended to start the -regexp with `^` (usually followed by `\s*`), and end it with `$`. -For example, `/^\s*\}$/` will reindent when a closing brace is -added at the start of a line. +You can add multiple keymaps to an editor. Their priorities +determine their precedence (the ones specified early or with high +priority get checked first). When a handler has returned `true` +for a given key, no further handlers are called. */ -declare function indentOnInput(): Extension; +declare const keymap: Facet; -/** -Encapsulates a single line of input. Given to stream syntax code, -which uses it to tokenize the content. -*/ -declare class StringStream { +type SelectionConfig = { /** - The line. + The length of a full cursor blink cycle, in milliseconds. + Defaults to 1200. Can be set to 0 to disable blinking. */ - string: string; - private tabSize; + cursorBlinkRate?: number; /** - The current indent unit size. + Whether to show a cursor for non-empty ranges. Defaults to + true. */ - indentUnit: number; + drawRangeCursor?: boolean; +}; +/** +Returns an extension that hides the browser's native selection and +cursor, replacing the selection with a background behind the text +(with the `cm-selectionBackground` class), and the +cursors with elements overlaid over the code (using +`cm-cursor-primary` and `cm-cursor-secondary`). + +This allows the editor to display secondary selection ranges, and +tends to produce a type of selection more in line with that users +expect in a text editor (the native selection styling will often +leave gaps between lines and won't fill the horizontal space after +a line when the selection continues past it). + +It does have a performance cost, in that it requires an extra DOM +layout cycle for many updates (the selection is drawn based on DOM +layout information that's only available after laying out the +content). +*/ +declare function drawSelection(config?: SelectionConfig): Extension; + +interface SpecialCharConfig { /** - The current position on the line. + An optional function that renders the placeholder elements. + + The `description` argument will be text that clarifies what the + character is, which should be provided to screen readers (for + example with the + [`aria-label`](https://www.w3.org/TR/wai-aria/#aria-label) + attribute) and optionally shown to the user in other ways (such + as the + [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title) + attribute). + + The given placeholder string is a suggestion for how to display + the character visually. */ - pos: number; + render?: ((code: number, description: string | null, placeholder: string) => HTMLElement) | null; /** - The start position of the current token. + Regular expression that matches the special characters to + highlight. Must have its 'g'/global flag set. */ - start: number; - private lastColumnPos; - private lastColumnValue; + specialChars?: RegExp; /** - True if we are at the end of the line. + Regular expression that can be used to add characters to the + default set of characters to highlight. */ - eol(): boolean; + addSpecialChars?: RegExp | null; +} +/** +Returns an extension that installs highlighting of special +characters. +*/ +declare function highlightSpecialChars( +/** +Configuration options. +*/ +config?: SpecialCharConfig): Extension; + +/** +Extension that enables a placeholder—a piece of example content +to show when the editor is empty. +*/ +declare function placeholder(content: string | HTMLElement): Extension; + +/** +Create an extension that enables rectangular selections. By +default, it will react to left mouse drag with the Alt key held +down. When such a selection occurs, the text within the rectangle +that was dragged over will be selected, as one selection +[range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line. +*/ +declare function rectangularSelection(options?: { /** - True if we are at the start of the line. + A custom predicate function, which takes a `mousedown` event and + returns true if it should be used for rectangular selection. */ - sol(): boolean; - /** - Get the next code unit after the current position, or undefined - if we're at the end of the line. + eventFilter?: (event: MouseEvent) => boolean; +}): Extension; + +/** +Creates an extension that configures tooltip behavior. +*/ +declare function tooltips(config?: { + /** + By default, tooltips use `"fixed"` + [positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/position), + which has the advantage that tooltips don't get cut off by + scrollable parent elements. However, CSS rules like `contain: + layout` can break fixed positioning in child nodes, which can be + worked about by using `"absolute"` here. + + On iOS, which at the time of writing still doesn't properly + support fixed positioning, the library always uses absolute + positioning. + + If the tooltip parent element sits in a transformed element, the + library also falls back to absolute positioning. */ - peek(): string | undefined; + position?: "fixed" | "absolute"; /** - Read the next code unit and advance `this.pos`. + The element to put the tooltips into. By default, they are put + in the editor (`cm-editor`) element, and that is usually what + you want. But in some layouts that can lead to positioning + issues, and you need to use a different parent to work around + those. */ - next(): string | void; + parent?: HTMLElement; /** - Match the next character against the given string, regular - expression, or predicate. Consume and return it if it matches. + By default, when figuring out whether there is room for a + tooltip at a given position, the extension considers the entire + space between 0,0 and `innerWidth`,`innerHeight` to be available + for showing tooltips. You can provide a function here that + returns an alternative rectangle. */ - eat(match: string | RegExp | ((ch: string) => boolean)): string | void; + tooltipSpace?: (view: EditorView) => Rect; +}): Extension; +/** +Describes a tooltip. Values of this type, when provided through +the [`showTooltip`](https://codemirror.net/6/docs/ref/#view.showTooltip) facet, control the +individual tooltips on the editor. +*/ +interface Tooltip { /** - Continue matching characters that match the given string, - regular expression, or predicate function. Return true if any - characters were consumed. + The document position at which to show the tooltip. */ - eatWhile(match: string | RegExp | ((ch: string) => boolean)): boolean; + pos: number; /** - Consume whitespace ahead of `this.pos`. Return true if any was - found. + The end of the range annotated by this tooltip, if different + from `pos`. */ - eatSpace(): boolean; + end?: number; /** - Move to the end of the line. + A constructor function that creates the tooltip's [DOM + representation](https://codemirror.net/6/docs/ref/#view.TooltipView). */ - skipToEnd(): void; + create(view: EditorView): TooltipView; /** - Move to directly before the given character, if found on the - current line. + Whether the tooltip should be shown above or below the target + position. Not guaranteed to be respected for hover tooltips + since all hover tooltips for the same range are always + positioned together. Defaults to false. */ - skipTo(ch: string): boolean | void; + above?: boolean; /** - Move back `n` characters. + Whether the `above` option should be honored when there isn't + enough space on that side to show the tooltip inside the + viewport. Defaults to false. */ - backUp(n: number): void; + strictSide?: boolean; /** - Get the column position at `this.pos`. + When set to true, show a triangle connecting the tooltip element + to position `pos`. */ - column(): number; + arrow?: boolean; +} +/** +Describes the way a tooltip is displayed. +*/ +interface TooltipView { /** - Get the indentation column of the current line. + The DOM element to position over the editor. */ - indentation(): number; + dom: HTMLElement; /** - Match the input against the given string or regular expression - (which should start with a `^`). Return true or the regexp match - if it matches. - - Unless `consume` is set to `false`, this will move `this.pos` - past the matched text. - - When matching a string `caseInsensitive` can be set to true to - make the match case-insensitive. + Adjust the position of the tooltip relative to its anchor + position. A positive `x` value will move the tooltip + horizontally along with the text direction (so right in + left-to-right context, left in right-to-left). A positive `y` + will move the tooltip up when it is above its anchor, and down + otherwise. */ - match(pattern: string | RegExp, consume?: boolean, caseInsensitive?: boolean): boolean | RegExpMatchArray | null; + offset?: { + x: number; + y: number; + }; /** - Get the current token. + By default, a tooltip's screen position will be based on the + text position of its `pos` property. This method can be provided + to make the tooltip view itself responsible for finding its + screen position. */ - current(): string; -} - -/** -A stream parser parses or tokenizes content from start to end, -emitting tokens as it goes over it. It keeps a mutable (but -copyable) object with state, in which it can store information -about the current context. -*/ -interface StreamParser { + getCoords?: (pos: number) => Rect; /** - Read one token, advancing the stream past it, and returning a - string indicating the token's style tag—either the name of one - of the tags in [`tags`](https://codemirror.net/6/docs/ref/#highlight.tags), or such a name - suffixed by one or more tag - [modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) names, separated by - spaces. For example `"keyword"` or "`variableName.constant"`. - - It is okay to return a zero-length token, but only if that - updates the state so that the next call will return a non-empty - token again. + By default, tooltips are moved when they overlap with other + tooltips. Set this to `true` to disable that behavior for this + tooltip. */ - token(stream: StringStream, state: State): string | null; + overlap?: boolean; /** - This notifies the parser of a blank line in the input. It can - update its state here if it needs to. + Called after the tooltip is added to the DOM for the first time. */ - blankLine?(state: State, indentUnit: number): void; + mount?(view: EditorView): void; /** - Produce a start state for the parser. + Update the DOM element for a change in the view's state. */ - startState?(indentUnit: number): State; + update?(update: ViewUpdate): void; /** - Copy a given state. By default, a shallow object copy is done - which also copies arrays held at the top level of the object. + Called when the tooltip is removed from the editor or the editor + is destroyed. */ - copyState?(state: State): State; + destroy?(): void; /** - Compute automatic indentation for the line that starts with the - given state and text. + Called when the tooltip has been (re)positioned. The argument is + the [space](https://codemirror.net/6/docs/ref/#view.tooltips^config.tooltipSpace) available to the + tooltip. */ - indent?(state: State, textAfter: string, context: IndentContext): number | null; + positioned?(space: Rect): void; /** - Default [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) to - attach to this language. + By default, the library will restrict the size of tooltips so + that they don't stick out of the available space. Set this to + false to disable that. */ - languageData?: { - [name: string]: any; - }; + resize?: boolean; } /** -A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a streaming -parser. +Facet to which an extension can add a value to show a tooltip. */ -declare class StreamLanguage extends Language { - private constructor(); - static define(spec: StreamParser): StreamLanguage; - private getIndent; - get allowsNesting(): boolean; -} - -declare const julia$1: StreamParser - -declare type JuliaLanguageConfig = { - /** Enable keyword completion */ - enableKeywordCompletion?: boolean; -}; -declare function julia(config?: JuliaLanguageConfig): LanguageSupport; - -declare type Handlers = { +declare const showTooltip: Facet; +type Handlers$1 = { [event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean; }; interface LineNumberConfig { @@ -3676,96 +4568,44 @@ interface LineNumberConfig { /** Supply event handlers for DOM events on this gutter. */ - domEventHandlers?: Handlers; -} -/** -Create a line number gutter extension. -*/ -declare function lineNumbers(config?: LineNumberConfig): Extension; - -interface HistoryConfig { - /** - The minimum depth (amount of events) to store. Defaults to 100. - */ - minDepth?: number; - /** - The maximum time (in milliseconds) that adjacent events can be - apart and still be grouped together. Defaults to 500. - */ - newGroupDelay?: number; -} -/** -Create a history extension with the given configuration. -*/ -declare function history(config?: HistoryConfig): Extension; -/** -Default key bindings for the undo history. - -- Mod-z: [`undo`](https://codemirror.net/6/docs/ref/#history.undo). -- Mod-y (Mod-Shift-z on macOS): [`redo`](https://codemirror.net/6/docs/ref/#history.redo). -- Mod-u: [`undoSelection`](https://codemirror.net/6/docs/ref/#history.undoSelection). -- Alt-u (Mod-Shift-u on macOS): [`redoSelection`](https://codemirror.net/6/docs/ref/#history.redoSelection). -*/ -declare const historyKeymap: readonly KeyBinding[]; - -/** -Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected -lines. -*/ -declare const indentMore: StateCommand; -/** -Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all -selected lines. -*/ -declare const indentLess: StateCommand; -/** -The default keymap. Includes all bindings from -[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following: - -- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift) -- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift) -- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp) -- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown) -- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp) -- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown) -- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection) -- Ctrl-Enter (Comd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine) -- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine) -- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax) -- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess) -- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) -- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection) -- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine) -- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket) + domEventHandlers?: Handlers$1; +} +/** +Create a line number gutter extension. */ -declare const defaultKeymap: readonly KeyBinding[]; +declare function lineNumbers(config?: LineNumberConfig): Extension; /** Highlighting tags are markers that denote a highlighting category. -They are [associated](https://codemirror.net/6/docs/ref/#highlight.styleTags) with parts of a syntax +They are [associated](#highlight.styleTags) with parts of a syntax tree by a language mode, and then mapped to an actual CSS style by -a [highlight style](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle). +a [highlighter](#highlight.Highlighter). Because syntax tree node types and highlight styles have to be able to talk the same language, CodeMirror uses a mostly _closed_ -[vocabulary](https://codemirror.net/6/docs/ref/#highlight.tags) of syntax tags (as opposed to +[vocabulary](#highlight.tags) of syntax tags (as opposed to traditional open string-based systems, which make it hard for highlighting themes to cover all the tokens produced by the various languages). -It _is_ possible to [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) your own +It _is_ possible to [define](#highlight.Tag^define) your own highlighting tags for system-internal use (where you control both the language package and the highlighter), but such tags will not be picked up by regular highlighters (though you can derive them from standard tags to allow highlighters to fall back to those). */ declare class Tag { + /** + The set of this tag and all its parent tags, starting with + this one itself and sorted in order of decreasing specificity. + */ + readonly set: Tag[]; /** Define a new tag. If `parent` is given, the tag is treated as a - sub-tag of that parent, and [highlight - styles](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle) that don't mention this tag - will try to fall back to the parent tag (or grandparent tag, - etc). + sub-tag of that parent, and + [highlighters](#highlight.tagHighlighter) that don't mention + this tag will try to fall back to the parent tag (or grandparent + tag, etc). */ static define(parent?: Tag): Tag; /** @@ -3783,108 +4623,28 @@ declare class Tag { static defineModifier(): (tag: Tag) => Tag; } /** -A highlight style associates CSS styles with higlighting -[tags](https://codemirror.net/6/docs/ref/#highlight.Tag). -*/ -declare class HighlightStyle { - /** - Extension that registers this style with an editor. When - multiple highlight styles are given, they _all_ apply, assigning - the combination of their matching styles to tokens. - */ - readonly extension: Extension; - /** - An extension that installs this highlighter as a fallback - highlight style, which will only be used if no other highlight - styles are configured. - */ - readonly fallback: Extension; - /** - A style module holding the CSS rules for this highlight style. - When using [`highlightTree`](https://codemirror.net/6/docs/ref/#highlight.highlightTree), you may - want to manually mount this module to show the highlighting. - */ - readonly module: StyleModule | null; - private map; - private scope; - private all; - private constructor(); - /** - Returns the CSS class associated with the given tag, if any. - This method is bound to the instance by the constructor. - */ - match(tag: Tag, scope: NodeType): string | null; - /** - Combines an array of highlight styles into a single match - function that returns all of the classes assigned by the styles - for a given tag. - */ - static combinedMatch(styles: readonly HighlightStyle[]): (tag: Tag, scope: NodeType) => any; - /** - Create a highlighter style that associates the given styles to - the given tags. The spec must be objects that hold a style tag - or array of tags in their `tag` property, and either a single - `class` property providing a static CSS class (for highlighters - like [`classHighlightStyle`](https://codemirror.net/6/docs/ref/#highlight.classHighlightStyle) - that rely on external styling), or a - [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style - set of CSS properties (which define the styling for those tags). - - The CSS rules created for a highlighter will be emitted in the - order of the spec's properties. That means that for elements that - have multiple tags associated with them, styles defined further - down in the list will have a higher CSS precedence than styles - defined earlier. - */ - static define(specs: readonly TagStyle[], options?: { - /** - By default, highlighters apply to the entire document. You can - scope them to a single language by providing the language's - [top node](https://codemirror.net/6/docs/ref/#language.Language.topNode) here. - */ - scope?: NodeType; - /** - Add a style to _all_ content. Probably only useful in - combination with `scope`. - */ - all?: string | StyleSpec; - }): HighlightStyle; - /** - Returns the CSS classes (if any) that the highlight styles - active in the given state would assign to the given a style - [tag](https://codemirror.net/6/docs/ref/#highlight.Tag) and (optional) language - [scope](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle^define^options.scope). - */ - static get(state: EditorState, tag: Tag, scope?: NodeType): string | null; -} -/** -The type of object used in -[`HighlightStyle.define`](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle^define). -Assigns a style to one or more highlighting -[tags](https://codemirror.net/6/docs/ref/#highlight.Tag), which can either be a fixed class name -(which must be defined elsewhere), or a set of CSS properties, for -which the library will define an anonymous class. +A highlighter defines a mapping from highlighting tags and +language scopes to CSS class names. They are usually defined via +[`tagHighlighter`](#highlight.tagHighlighter) or some wrapper +around that, but it is also possible to implement them from +scratch. */ -interface TagStyle { - /** - The tag or tags to target. - */ - tag: Tag | readonly Tag[]; +interface Highlighter { /** - If given, this maps the tags to a fixed class name. + Get the set of classes that should be applied to the given set + of highlighting tags, or null if this highlighter doesn't assign + a style to the tags. */ - class?: string; + style(tags: readonly Tag[]): string | null; /** - Any further properties (if `class` isn't given) will be - interpreted as in style objects given to - [style-mod](https://github.com/marijnh/style-mod#documentation). - The type here is `any` because of TypeScript limitations. + When given, the highlighter will only be applied to trees on + whose [top](#common.NodeType.isTop) node this predicate returns + true. */ - [styleProperty: string]: any; + scope?(node: NodeType): boolean; } /** -The default set of highlighting [tags](https://codemirror.net/6/docs/ref/#highlight.Tag^define) used -by regular language packages and themes. +The default set of highlighting [tags](#highlight.Tag). This collection is heavily biased towards programming languages, and necessarily incomplete. A full ontology of syntactic @@ -3892,7 +4652,7 @@ constructs would fill a stack of books, and be impractical to write themes for. So try to make do with this set. If all else fails, [open an issue](https://github.com/codemirror/codemirror.next) to propose a -new tag, or [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) a local custom tag for +new tag, or [define](#highlight.Tag^define) a local custom tag for your use case. Note that it is not obligatory to always attach the most specific @@ -3909,15 +4669,15 @@ declare const tags: { */ comment: Tag; /** - A line [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + A line [comment](#highlight.tags.comment). */ lineComment: Tag; /** - A block [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + A block [comment](#highlight.tags.comment). */ blockComment: Tag; /** - A documentation [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + A documentation [comment](#highlight.tags.comment). */ docComment: Tag; /** @@ -3925,39 +4685,39 @@ declare const tags: { */ name: Tag; /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a variable. + The [name](#highlight.tags.name) of a variable. */ variableName: Tag; /** - A type [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + A type [name](#highlight.tags.name). */ typeName: Tag; /** - A tag name (subtag of [`typeName`](https://codemirror.net/6/docs/ref/#highlight.tags.typeName)). + A tag name (subtag of [`typeName`](#highlight.tags.typeName)). */ tagName: Tag; /** - A property or field [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + A property or field [name](#highlight.tags.name). */ propertyName: Tag; /** - An attribute name (subtag of [`propertyName`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName)). + An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)). */ attributeName: Tag; /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a class. + The [name](#highlight.tags.name) of a class. */ className: Tag; /** - A label [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + A label [name](#highlight.tags.name). */ labelName: Tag; /** - A namespace [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + A namespace [name](#highlight.tags.name). */ namespace: Tag; /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a macro. + The [name](#highlight.tags.name) of a macro. */ macroName: Tag; /** @@ -3965,52 +4725,52 @@ declare const tags: { */ literal: Tag; /** - A string [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + A string [literal](#highlight.tags.literal). */ string: Tag; /** - A documentation [string](https://codemirror.net/6/docs/ref/#highlight.tags.string). + A documentation [string](#highlight.tags.string). */ docString: Tag; /** - A character literal (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). + A character literal (subtag of [string](#highlight.tags.string)). */ character: Tag; /** - An attribute value (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). + An attribute value (subtag of [string](#highlight.tags.string)). */ attributeValue: Tag; /** - A number [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + A number [literal](#highlight.tags.literal). */ number: Tag; /** - An integer [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. + An integer [number](#highlight.tags.number) literal. */ integer: Tag; /** - A floating-point [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. + A floating-point [number](#highlight.tags.number) literal. */ float: Tag; /** - A boolean [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + A boolean [literal](#highlight.tags.literal). */ bool: Tag; /** - Regular expression [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + Regular expression [literal](#highlight.tags.literal). */ regexp: Tag; /** - An escape [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal), for example a + An escape [literal](#highlight.tags.literal), for example a backslash escape in a string. */ escape: Tag; /** - A color [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + A color [literal](#highlight.tags.literal). */ color: Tag; /** - A URL [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + A URL [literal](#highlight.tags.literal). */ url: Tag; /** @@ -4018,76 +4778,81 @@ declare const tags: { */ keyword: Tag; /** - The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for the self or this + The [keyword](#highlight.tags.keyword) for the self or this object. */ self: Tag; /** - The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for null. + The [keyword](#highlight.tags.keyword) for null. */ null: Tag; /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) denoting some atomic value. + A [keyword](#highlight.tags.keyword) denoting some atomic value. */ atom: Tag; /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that represents a unit. + A [keyword](#highlight.tags.keyword) that represents a unit. */ unit: Tag; /** - A modifier [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). + A modifier [keyword](#highlight.tags.keyword). */ modifier: Tag; /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that acts as an operator. + A [keyword](#highlight.tags.keyword) that acts as an operator. */ operatorKeyword: Tag; /** - A control-flow related [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). + A control-flow related [keyword](#highlight.tags.keyword). */ controlKeyword: Tag; /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that defines something. + A [keyword](#highlight.tags.keyword) that defines something. */ definitionKeyword: Tag; /** + A [keyword](#highlight.tags.keyword) related to defining or + interfacing with modules. + */ + moduleKeyword: Tag; + /** An operator. */ operator: Tag; /** - An [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + An [operator](#highlight.tags.operator) that dereferences something. */ derefOperator: Tag; /** - Arithmetic-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Arithmetic-related [operator](#highlight.tags.operator). */ arithmeticOperator: Tag; /** - Logical [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Logical [operator](#highlight.tags.operator). */ logicOperator: Tag; /** - Bit [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Bit [operator](#highlight.tags.operator). */ bitwiseOperator: Tag; /** - Comparison [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Comparison [operator](#highlight.tags.operator). */ compareOperator: Tag; /** - [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that updates its operand. + [Operator](#highlight.tags.operator) that updates its operand. */ updateOperator: Tag; /** - [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + [Operator](#highlight.tags.operator) that defines something. */ definitionOperator: Tag; /** - Type-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Type-related [operator](#highlight.tags.operator). */ typeOperator: Tag; /** - Control-flow [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Control-flow [operator](#highlight.tags.operator). */ controlOperator: Tag; /** @@ -4095,32 +4860,32 @@ declare const tags: { */ punctuation: Tag; /** - [Punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation) that separates + [Punctuation](#highlight.tags.punctuation) that separates things. */ separator: Tag; /** - Bracket-style [punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation). + Bracket-style [punctuation](#highlight.tags.punctuation). */ bracket: Tag; /** - Angle [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `<` and `>` + Angle [brackets](#highlight.tags.bracket) (usually `<` and `>` tokens). */ angleBracket: Tag; /** - Square [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `[` and `]` + Square [brackets](#highlight.tags.bracket) (usually `[` and `]` tokens). */ squareBracket: Tag; /** Parentheses (usually `(` and `)` tokens). Subtag of - [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + [bracket](#highlight.tags.bracket). */ paren: Tag; /** Braces (usually `{` and `}` tokens). Subtag of - [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + [bracket](#highlight.tags.bracket). */ brace: Tag; /** @@ -4128,31 +4893,31 @@ declare const tags: { */ content: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a heading. + [Content](#highlight.tags.content) that represents a heading. */ heading: Tag; /** - A level 1 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 1 [heading](#highlight.tags.heading). */ heading1: Tag; /** - A level 2 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 2 [heading](#highlight.tags.heading). */ heading2: Tag; /** - A level 3 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 3 [heading](#highlight.tags.heading). */ heading3: Tag; /** - A level 4 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 4 [heading](#highlight.tags.heading). */ heading4: Tag; /** - A level 5 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 5 [heading](#highlight.tags.heading). */ heading5: Tag; /** - A level 6 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + A level 6 [heading](#highlight.tags.heading). */ heading6: Tag; /** @@ -4160,32 +4925,32 @@ declare const tags: { */ contentSeparator: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a list. + [Content](#highlight.tags.content) that represents a list. */ list: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a quote. + [Content](#highlight.tags.content) that represents a quote. */ quote: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is emphasized. + [Content](#highlight.tags.content) that is emphasized. */ emphasis: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled strong. + [Content](#highlight.tags.content) that is styled strong. */ strong: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is part of a link. + [Content](#highlight.tags.content) that is part of a link. */ link: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled as code or + [Content](#highlight.tags.content) that is styled as code or monospace. */ monospace: Tag; /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that has a strike-through + [Content](#highlight.tags.content) that has a strike-through style. */ strikethrough: Tag; @@ -4210,89 +4975,341 @@ declare const tags: { */ meta: Tag; /** - [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that applies to the entire + [Metadata](#highlight.tags.meta) that applies to the entire document. */ documentMeta: Tag; /** - [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that annotates or adds + [Metadata](#highlight.tags.meta) that annotates or adds attributes to a given syntactic element. */ annotation: Tag; /** Processing instruction or preprocessor directive. Subtag of - [meta](https://codemirror.net/6/docs/ref/#highlight.tags.meta). + [meta](#highlight.tags.meta). */ processingInstruction: Tag; /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that a + [Modifier](#highlight.Tag^defineModifier) that indicates that a given element is being defined. Expected to be used with the - various [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) tags. + various [name](#highlight.tags.name) tags. */ definition: (tag: Tag) => Tag; /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that + [Modifier](#highlight.Tag^defineModifier) that indicates that something is constant. Mostly expected to be used with - [variable names](https://codemirror.net/6/docs/ref/#highlight.tags.variableName). + [variable names](#highlight.tags.variableName). */ constant: (tag: Tag) => Tag; /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) used to indicate that - a [variable](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) or [property - name](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) is being called or defined + [Modifier](#highlight.Tag^defineModifier) used to indicate that + a [variable](#highlight.tags.variableName) or [property + name](#highlight.tags.propertyName) is being called or defined as a function. */ function: (tag: Tag) => Tag; /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that can be applied to - [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) to indicate that they belong to + [Modifier](#highlight.Tag^defineModifier) that can be applied to + [names](#highlight.tags.name) to indicate that they belong to the language's standard environment. */ standard: (tag: Tag) => Tag; /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates a given - [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) is local to some scope. + [Modifier](#highlight.Tag^defineModifier) that indicates a given + [names](#highlight.tags.name) is local to some scope. + */ + local: (tag: Tag) => Tag; + /** + A generic variant [modifier](#highlight.Tag^defineModifier) that + can be used to tag language-specific alternative variants of + some common tag. It is recommended for themes to define special + forms of at least the [string](#highlight.tags.string) and + [variable name](#highlight.tags.variableName) tags, since those + come up a lot. + */ + special: (tag: Tag) => Tag; +}; + +/** +A language object manages parsing and per-language +[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is +managed as a [Lezer](https://lezer.codemirror.net) tree. The class +can be used directly, via the [`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage) +subclass for [Lezer](https://lezer.codemirror.net/) LR parsers, or +via the [`StreamLanguage`](https://codemirror.net/6/docs/ref/#language.StreamLanguage) subclass +for stream parsers. +*/ +declare class Language { + /** + The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet + used for this language. + */ + readonly data: Facet<{ + [name: string]: any; + }>; + /** + A language name. + */ + readonly name: string; + /** + The extension value to install this as the document language. + */ + readonly extension: Extension; + /** + The parser object. Can be useful when using this as a [nested + parser](https://lezer.codemirror.net/docs/ref#common.Parser). + */ + parser: Parser; + /** + Construct a language object. If you need to invoke this + directly, first define a data facet with + [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet), and then + configure your parser to [attach](https://codemirror.net/6/docs/ref/#language.languageDataProp) it + to the language's outer syntax node. + */ + constructor( + /** + The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet + used for this language. + */ + data: Facet<{ + [name: string]: any; + }>, parser: Parser, extraExtensions?: Extension[], + /** + A language name. + */ + name?: string); + /** + Query whether this language is active at the given position. + */ + isActiveAt(state: EditorState, pos: number, side?: -1 | 0 | 1): boolean; + /** + Find the document regions that were parsed using this language. + The returned regions will _include_ any nested languages rooted + in this language, when those exist. + */ + findRegions(state: EditorState): { + from: number; + to: number; + }[]; + /** + Indicates whether this language allows nested languages. The + default implementation returns true. + */ + get allowsNesting(): boolean; +} +/** +A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer +[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser) +parsers. +*/ +declare class LRLanguage extends Language { + readonly parser: LRParser; + private constructor(); + /** + Define a language from a parser. + */ + static define(spec: { + /** + The [name](https://codemirror.net/6/docs/ref/#Language.name) of the language. + */ + name?: string; + /** + The parser to use. Should already have added editor-relevant + node props (and optionally things like dialect and top rule) + configured. + */ + parser: LRParser; + /** + [Language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) + to register for this language. + */ + languageData?: { + [name: string]: any; + }; + }): LRLanguage; + /** + Create a new instance of this language with a reconfigured + version of its parser and optionally a new name. + */ + configure(options: ParserConfig, name?: string): LRLanguage; + get allowsNesting(): boolean; +} +/** +Get the syntax tree for a state, which is the current (possibly +incomplete) parse tree of the active +[language](https://codemirror.net/6/docs/ref/#language.Language), or the empty tree if there is no +language available. +*/ +declare function syntaxTree(state: EditorState): Tree; +/** +Queries whether there is a full syntax tree available up to the +given document position. If there isn't, the background parse +process _might_ still be working and update the tree further, but +there is no guarantee of that—the parser will [stop +working](https://codemirror.net/6/docs/ref/#language.syntaxParserRunning) when it has spent a +certain amount of time or has moved beyond the visible viewport. +Always returns false if no language has been enabled. +*/ +declare function syntaxTreeAvailable(state: EditorState, upto?: number): boolean; +/** +This class bundles a [language](https://codemirror.net/6/docs/ref/#language.Language) with an +optional set of supporting extensions. Language packages are +encouraged to export a function that optionally takes a +configuration object and returns a `LanguageSupport` instance, as +the main way for client code to use the package. +*/ +declare class LanguageSupport { + /** + The language object. + */ + readonly language: Language; + /** + An optional set of supporting extensions. When nesting a + language in another language, the outer language is encouraged + to include the supporting extensions for its inner languages + in its own set of support extensions. + */ + readonly support: Extension; + /** + An extension including both the language and its support + extensions. (Allowing the object to be used as an extension + value itself.) + */ + extension: Extension; + /** + Create a language support object. + */ + constructor( + /** + The language object. + */ + language: Language, + /** + An optional set of supporting extensions. When nesting a + language in another language, the outer language is encouraged + to include the supporting extensions for its inner languages + in its own set of support extensions. + */ + support?: Extension); +} +/** +Language descriptions are used to store metadata about languages +and to dynamically load them. Their main role is finding the +appropriate language for a filename or dynamically loading nested +parsers. +*/ +declare class LanguageDescription { + /** + The name of this language. + */ + readonly name: string; + /** + Alternative names for the mode (lowercased, includes `this.name`). + */ + readonly alias: readonly string[]; + /** + File extensions associated with this language. + */ + readonly extensions: readonly string[]; + /** + Optional filename pattern that should be associated with this + language. + */ + readonly filename: RegExp | undefined; + private loadFunc; + /** + If the language has been loaded, this will hold its value. + */ + support: LanguageSupport | undefined; + private loading; + private constructor(); + /** + Start loading the the language. Will return a promise that + resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport) + object when the language successfully loads. + */ + load(): Promise; + /** + Create a language description. + */ + static of(spec: { + /** + The language's name. + */ + name: string; + /** + An optional array of alternative names. + */ + alias?: readonly string[]; + /** + An optional array of filename extensions associated with this + language. + */ + extensions?: readonly string[]; + /** + An optional filename pattern associated with this language. + */ + filename?: RegExp; + /** + A function that will asynchronously load the language. + */ + load?: () => Promise; + /** + Alternatively to `load`, you can provide an already loaded + support object. Either this or `load` should be provided. + */ + support?: LanguageSupport; + }): LanguageDescription; + /** + Look for a language in the given array of descriptions that + matches the filename. Will first match + [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns, + and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions), + and return the first language that matches. */ - local: (tag: Tag) => Tag; + static matchFilename(descs: readonly LanguageDescription[], filename: string): LanguageDescription | null; /** - A generic variant [modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that - can be used to tag language-specific alternative variants of - some common tag. It is recommended for themes to define special - forms of at least the [string](https://codemirror.net/6/docs/ref/#highlight.tags.string) and - [variable name](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) tags, since those - come up a lot. + Look for a language whose name or alias matches the the given + name (case-insensitively). If `fuzzy` is true, and no direct + matchs is found, this'll also search for a language whose name + or alias occurs in the string (for names shorter than three + characters, only when surrounded by non-word characters). */ - special: (tag: Tag) => Tag; -}; + static matchLanguageName(descs: readonly LanguageDescription[], name: string, fuzzy?: boolean): LanguageDescription | null; +} /** -A default highlight style (works well with light themes). +Facet for overriding the unit by which indentation happens. Should +be a string consisting either entirely of the same whitespace +character. When not set, this defaults to 2 spaces. */ -declare const defaultHighlightStyle: HighlightStyle; - +declare const indentUnit: Facet; /** -Create an extension that enables rectangular selections. By -default, it will react to left mouse drag with the Alt key held -down. When such a selection occurs, the text within the rectangle -that was dragged over will be selected, as one selection -[range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line. -*/ -declare function rectangularSelection(options?: { - /** - A custom predicate function, which takes a `mousedown` event and - returns true if it should be used for rectangular selection. - */ - eventFilter?: (event: MouseEvent) => boolean; -}): Extension; +Enables reindentation on input. When a language defines an +`indentOnInput` field in its [language +data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular +expression, the line at the cursor will be reindented whenever new +text is typed and the input from the start of the line up to the +cursor matches that regexp. +To avoid unneccesary reindents, it is recommended to start the +regexp with `^` (usually followed by `\s*`), and end it with `$`. +For example, `/^\s*\}$/` will reindent when a closing brace is +added at the start of a line. +*/ +declare function indentOnInput(): Extension; /** Default fold-related key bindings. - - Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#fold.foldCode). - - Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](https://codemirror.net/6/docs/ref/#fold.unfoldCode). - - Ctrl-Alt-[: [`foldAll`](https://codemirror.net/6/docs/ref/#fold.foldAll). - - Ctrl-Alt-]: [`unfoldAll`](https://codemirror.net/6/docs/ref/#fold.unfoldAll). + - Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#language.foldCode). + - Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](https://codemirror.net/6/docs/ref/#language.unfoldCode). + - Ctrl-Alt-[: [`foldAll`](https://codemirror.net/6/docs/ref/#language.foldAll). + - Ctrl-Alt-]: [`unfoldAll`](https://codemirror.net/6/docs/ref/#language.unfoldAll). */ declare const foldKeymap: readonly KeyBinding[]; +type Handlers = { + [event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean; +}; interface FoldGutterConfig { /** A function that creates the DOM element used to indicate a @@ -4310,6 +5327,15 @@ interface FoldGutterConfig { Defaults to `"›"`. */ closedText?: string; + /** + Supply event handlers for DOM events on this gutter. + */ + domEventHandlers?: Handlers; + /** + When given, if this returns true for a given view update, + recompute the fold markers. + */ + foldingChanged?: (update: ViewUpdate) => boolean; } /** Create an extension that registers a fold gutter, which shows a @@ -4318,6 +5344,105 @@ to fold or unfold the line). */ declare function foldGutter(config?: FoldGutterConfig): Extension; +/** +A highlight style associates CSS styles with higlighting +[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag). +*/ +declare class HighlightStyle implements Highlighter { + /** + The tag styles used to create this highlight style. + */ + readonly specs: readonly TagStyle[]; + /** + A style module holding the CSS rules for this highlight style. + When using + [`highlightTree`](https://lezer.codemirror.net/docs/ref#highlight.highlightTree) + outside of the editor, you may want to manually mount this + module to show the highlighting. + */ + readonly module: StyleModule | null; + readonly style: (tags: readonly Tag[]) => string | null; + readonly scope: ((type: NodeType) => boolean) | undefined; + private constructor(); + /** + Create a highlighter style that associates the given styles to + the given tags. The specs must be objects that hold a style tag + or array of tags in their `tag` property, and either a single + `class` property providing a static CSS class (for highlighter + that rely on external styling), or a + [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style + set of CSS properties (which define the styling for those tags). + + The CSS rules created for a highlighter will be emitted in the + order of the spec's properties. That means that for elements that + have multiple tags associated with them, styles defined further + down in the list will have a higher CSS precedence than styles + defined earlier. + */ + static define(specs: readonly TagStyle[], options?: { + /** + By default, highlighters apply to the entire document. You can + scope them to a single language by providing the language + object or a language's top node type here. + */ + scope?: Language | NodeType; + /** + Add a style to _all_ content. Probably only useful in + combination with `scope`. + */ + all?: string | StyleSpec; + /** + Specify that this highlight style should only be active then + the theme is dark or light. By default, it is active + regardless of theme. + */ + themeType?: "dark" | "light"; + }): HighlightStyle; +} +/** +Wrap a highlighter in an editor extension that uses it to apply +syntax highlighting to the editor content. + +When multiple (non-fallback) styles are provided, the styling +applied is the union of the classes they emit. +*/ +declare function syntaxHighlighting(highlighter: Highlighter, options?: { + /** + When enabled, this marks the highlighter as a fallback, which + only takes effect if no other highlighters are registered. + */ + fallback: boolean; +}): Extension; +/** +The type of object used in +[`HighlightStyle.define`](https://codemirror.net/6/docs/ref/#language.HighlightStyle^define). +Assigns a style to one or more highlighting +[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag), which can either be a fixed class name +(which must be defined elsewhere), or a set of CSS properties, for +which the library will define an anonymous class. +*/ +interface TagStyle { + /** + The tag or tags to target. + */ + tag: Tag | readonly Tag[]; + /** + If given, this maps the tags to a fixed class name. + */ + class?: string; + /** + Any further properties (if `class` isn't given) will be + interpreted as in style objects given to + [style-mod](https://github.com/marijnh/style-mod#documentation). + (The type here is `any` because of TypeScript limitations.) + */ + [styleProperty: string]: any; +} +/** +A default highlight style (works well with light themes). +*/ +declare const defaultHighlightStyle: HighlightStyle; + interface Config { /** Whether the bracket matching should look at the character after @@ -4339,6 +5464,13 @@ interface Config { to 10 000. */ maxScanDistance?: number; + /** + Can be used to configure the way in which brackets are + decorated. The default behavior is to add the + `cm-matchingBracket` class for matching pairs, and + `cm-nonmatchingBracket` for mismatched pairs or single brackets. + */ + renderMatch?: (match: MatchResult, state: EditorState) => readonly Range[]; } /** Create an extension that enables bracket matching. Whenever the @@ -4347,78 +5479,109 @@ are highlighted. Or, when no matching bracket is found, another highlighting style is used to indicate this. */ declare function bracketMatching(config?: Config): Extension; - -/** -Extension to enable bracket-closing behavior. When a closeable -bracket is typed, its closing bracket is immediately inserted -after the cursor. When closing a bracket directly in front of a -closing bracket inserted by the extension, the cursor moves over -that bracket. -*/ -declare function closeBrackets(): Extension; /** -Close-brackets related key bindings. Binds Backspace to -[`deleteBracketPair`](https://codemirror.net/6/docs/ref/#closebrackets.deleteBracketPair). +The result returned from `matchBrackets`. */ -declare const closeBracketsKeymap: readonly KeyBinding[]; - -interface CompletionConfig { - /** - When enabled (defaults to true), autocompletion will start - whenever the user types something that can be completed. - */ - activateOnTyping?: boolean; - /** - Override the completion sources used. By default, they will be - taken from the `"autocomplete"` [language - data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) (which should hold - [completion sources](https://codemirror.net/6/docs/ref/#autocomplete.CompletionSource) or arrays - of [completions](https://codemirror.net/6/docs/ref/#autocomplete.Completion)). - */ - override?: readonly CompletionSource[] | null; +interface MatchResult { /** - The maximum number of options to render to the DOM. + The extent of the bracket token found. */ - maxRenderedOptions?: number; + start: { + from: number; + to: number; + }; /** - Set this to false to disable the [default completion - keymap](https://codemirror.net/6/docs/ref/#autocomplete.completionKeymap). (This requires you to - add bindings to control completion yourself. The bindings should - probably have a higher precedence than other bindings for the - same keys.) + The extent of the matched token, if any was found. */ - defaultKeymap?: boolean; + end?: { + from: number; + to: number; + }; /** - By default, completions are shown below the cursor when there is - space. Setting this to true will make the extension put the - completions above the cursor when possible. + Whether the tokens match. This can be false even when `end` has + a value, if that token doesn't match the opening token. */ - aboveCursor?: boolean; + matched: boolean; +} + +type JuliaLanguageConfig = { + /** Enable keyword completion */ + enableKeywordCompletion?: boolean; +}; +declare function julia(config?: JuliaLanguageConfig): LanguageSupport; + +interface HistoryConfig { /** - This can be used to add additional CSS classes to completion - options. + The minimum depth (amount of events) to store. Defaults to 100. */ - optionClass?: (completion: Completion) => string; + minDepth?: number; /** - By default, the library will render icons based on the - completion's [type](https://codemirror.net/6/docs/ref/#autocomplete.Completion.type) in front of - each option. Set this to false to turn that off. + The maximum time (in milliseconds) that adjacent events can be + apart and still be grouped together. Defaults to 500. */ - icons?: boolean; + newGroupDelay?: number; /** - This option can be used to inject additional content into - options. The `render` function will be called for each visible - completion, and should produce a DOM node to show. `position` - determines where in the DOM the result appears, relative to - other added widgets and the standard content. The default icons - have position 20, the label position 50, and the detail position - 70. + By default, when close enough together in time, changes are + joined into an existing undo event if they touch any of the + changed ranges from that event. You can pass a custom predicate + here to influence that logic. */ - addToOptions?: { - render: (completion: Completion, state: EditorState) => Node | null; - position: number; - }[]; + joinToEvent?: (tr: Transaction, isAdjacent: boolean) => boolean; } +/** +Create a history extension with the given configuration. +*/ +declare function history(config?: HistoryConfig): Extension; +/** +Default key bindings for the undo history. + +- Mod-z: [`undo`](https://codemirror.net/6/docs/ref/#commands.undo). +- Mod-y (Mod-Shift-z on macOS) + Ctrl-Shift-z on Linux: [`redo`](https://codemirror.net/6/docs/ref/#commands.redo). +- Mod-u: [`undoSelection`](https://codemirror.net/6/docs/ref/#commands.undoSelection). +- Alt-u (Mod-Shift-u on macOS): [`redoSelection`](https://codemirror.net/6/docs/ref/#commands.redoSelection). +*/ +declare const historyKeymap: readonly KeyBinding[]; +/** +Move the selected lines up one line. +*/ +declare const moveLineUp: StateCommand; +/** +Move the selected lines down one line. +*/ +declare const moveLineDown: StateCommand; +/** +Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected +lines. +*/ +declare const indentMore: StateCommand; +/** +Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all +selected lines. +*/ +declare const indentLess: StateCommand; +/** +The default keymap. Includes all bindings from +[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following: + +- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift) +- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift) +- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp) +- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown) +- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp) +- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown) +- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection) +- Ctrl-Enter (Cmd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine) +- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine) +- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax) +- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess) +- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) +- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection) +- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine) +- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket) +- Ctrl-/ (Cmd-/ on macOS): [`toggleComment`](https://codemirror.net/6/docs/ref/#commands.toggleComment). +- Shift-Alt-a: [`toggleBlockComment`](https://codemirror.net/6/docs/ref/#commands.toggleBlockComment). +*/ +declare const defaultKeymap: readonly KeyBinding[]; /** Objects type used to represent individual completions. @@ -4426,11 +5589,18 @@ Objects type used to represent individual completions. interface Completion { /** The label to show in the completion picker. This is what input - is matched agains to determine whether a completion matches (and + is matched against to determine whether a completion matches (and how well it matches). */ label: string; /** + An optional override for the completion's visible label. When + using this, matched characters will only be highlighted if you + provide a [`getMatch`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.getMatch) + function. + */ + displayLabel?: string; + /** An optional short piece of information to show (with a different style) after the label. */ @@ -4440,7 +5610,7 @@ interface Completion { a plain string or a function that'll render the DOM structure to show when invoked. */ - info?: string | ((completion: Completion) => (Node | Promise)); + info?: string | ((completion: Completion) => CompletionInfo | Promise); /** How to apply the completion. The default is to replace it with its [label](https://codemirror.net/6/docs/ref/#autocomplete.Completion.label). When this holds a @@ -4470,6 +5640,49 @@ interface Completion { down the list, a positive number moves it up. */ boost?: number; + /** + Can be used to divide the completion list into sections. + Completions in a given section (matched by name) will be grouped + together, with a heading above them. Options without section + will appear above all sections. A string value is equivalent to + a `{name}` object. + */ + section?: string | CompletionSection; +} +/** +The type returned from +[`Completion.info`](https://codemirror.net/6/docs/ref/#autocomplete.Completion.info). May be a DOM +node, null to indicate there is no info, or an object with an +optional `destroy` method that cleans up the node. +*/ +type CompletionInfo = Node | null | { + dom: Node; + destroy?(): void; +}; +/** +Object used to describe a completion +[section](https://codemirror.net/6/docs/ref/#autocomplete.Completion.section). It is recommended to +create a shared object used by all the completions in a given +section. +*/ +interface CompletionSection { + /** + The name of the section. If no `render` method is present, this + will be displayed above the options. + */ + name: string; + /** + An optional function that renders the section header. Since the + headers are shown inside a list, you should make sure the + resulting element has a `display: list-item` style. + */ + header?: (section: CompletionSection) => HTMLElement; + /** + By default, sections are ordered alphabetically by name. To + specify an explicit order, `rank` can be used. Sections with a + lower rank will be shown above sections with a higher rank. + */ + rank?: number; } /** An instance of this is passed to completion source functions. @@ -4563,7 +5776,7 @@ may return its [result](https://codemirror.net/6/docs/ref/#autocomplete.Completi synchronously or as a promise. Returning null indicates no completions are available. */ -declare type CompletionSource = (context: CompletionContext) => CompletionResult | null | Promise; +type CompletionSource = (context: CompletionContext) => CompletionResult | null | Promise; /** Interface for objects returned by completion sources. */ @@ -4585,33 +5798,170 @@ interface CompletionResult { */ options: readonly Completion[]; /** - When given, further input that causes the part of the document - between ([mapped](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) `from` and `to` to - match this regular expression will not query the completion - source again, but continue with this list of options. This can - help a lot with responsiveness, since it allows the completion - list to be updated synchronously. + When given, further typing or deletion that causes the part of + the document between ([mapped](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) `from` + and `to` to match this regular expression or predicate function + will not query the completion source again, but continue with + this list of options. This can help a lot with responsiveness, + since it allows the completion list to be updated synchronously. */ - span?: RegExp; + validFor?: RegExp | ((text: string, from: number, to: number, state: EditorState) => boolean); /** By default, the library filters and scores completions. Set `filter` to `false` to disable this, and cause your completions to all be included, in the order they were given. When there are other sources, unfiltered completions appear at the top of the - list of completions. `span` must not be given when `filter` is - `false`, because it only works when filtering. + list of completions. `validFor` must not be given when `filter` + is `false`, because it only works when filtering. */ filter?: boolean; + /** + When [`filter`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.filter) is set to + `false` or a completion has a + [`displayLabel`](https://codemirror.net/6/docs/ref/#autocomplete.Completion.displayLabel), this + may be provided to compute the ranges on the label that match + the input. Should return an array of numbers where each pair of + adjacent numbers provide the start and end of a range. The + second argument, the match found by the library, is only passed + when `filter` isn't `false`. + */ + getMatch?: (completion: Completion, matched?: readonly number[]) => readonly number[]; + /** + Synchronously update the completion result after typing or + deletion. If given, this should not do any expensive work, since + it will be called during editor state updates. The function + should make sure (similar to + [`validFor`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.validFor)) that the + completion still applies in the new state. + */ + update?: (current: CompletionResult, from: number, to: number, context: CompletionContext) => CompletionResult | null; } /** This annotation is added to transactions that are produced by picking a completion. */ declare const pickedCompletion: AnnotationType; +/** +Helper function that returns a transaction spec which inserts a +completion's text in the main selection range, and any other +selection range that has the same text in front of it. +*/ +declare function insertCompletionText(state: EditorState, text: string, from: number, to: number): TransactionSpec; + +interface CompletionConfig { + /** + When enabled (defaults to true), autocompletion will start + whenever the user types something that can be completed. + */ + activateOnTyping?: boolean; + /** + By default, when completion opens, the first option is selected + and can be confirmed with + [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this + is set to false, the completion widget starts with no completion + selected, and the user has to explicitly move to a completion + before you can confirm one. + */ + selectOnOpen?: boolean; + /** + Override the completion sources used. By default, they will be + taken from the `"autocomplete"` [language + data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) (which should hold + [completion sources](https://codemirror.net/6/docs/ref/#autocomplete.CompletionSource) or arrays + of [completions](https://codemirror.net/6/docs/ref/#autocomplete.Completion)). + */ + override?: readonly CompletionSource[] | null; + /** + Determines whether the completion tooltip is closed when the + editor loses focus. Defaults to true. + */ + closeOnBlur?: boolean; + /** + The maximum number of options to render to the DOM. + */ + maxRenderedOptions?: number; + /** + Set this to false to disable the [default completion + keymap](https://codemirror.net/6/docs/ref/#autocomplete.completionKeymap). (This requires you to + add bindings to control completion yourself. The bindings should + probably have a higher precedence than other bindings for the + same keys.) + */ + defaultKeymap?: boolean; + /** + By default, completions are shown below the cursor when there is + space. Setting this to true will make the extension put the + completions above the cursor when possible. + */ + aboveCursor?: boolean; + /** + When given, this may return an additional CSS class to add to + the completion dialog element. + */ + tooltipClass?: (state: EditorState) => string; + /** + This can be used to add additional CSS classes to completion + options. + */ + optionClass?: (completion: Completion) => string; + /** + By default, the library will render icons based on the + completion's [type](https://codemirror.net/6/docs/ref/#autocomplete.Completion.type) in front of + each option. Set this to false to turn that off. + */ + icons?: boolean; + /** + This option can be used to inject additional content into + options. The `render` function will be called for each visible + completion, and should produce a DOM node to show. `position` + determines where in the DOM the result appears, relative to + other added widgets and the standard content. The default icons + have position 20, the label position 50, and the detail position + 80. + */ + addToOptions?: { + render: (completion: Completion, state: EditorState) => Node | null; + position: number; + }[]; + /** + By default, [info](https://codemirror.net/6/docs/ref/#autocomplete.Completion.info) tooltips are + placed to the side of the selected completion. This option can + be used to override that. It will be given rectangles for the + list of completions, the selected option, the info element, and + the availble [tooltip + space](https://codemirror.net/6/docs/ref/#view.tooltips^config.tooltipSpace), and should return + style and/or class strings for the info element. + */ + positionInfo?: (view: EditorView, list: Rect, option: Rect, info: Rect, space: Rect) => { + style?: string; + class?: string; + }; + /** + The comparison function to use when sorting completions with the same + match score. Defaults to using + [`localeCompare`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare). + */ + compareCompletions?: (a: Completion, b: Completion) => number; + /** + By default, commands relating to an open completion only take + effect 75 milliseconds after the completion opened, so that key + presses made before the user is aware of the tooltip don't go to + the tooltip. This option can be used to configure that delay. + */ + interactionDelay?: number; + /** + When there are multiple asynchronous completion sources, this + controls how long the extension waits for a slow source before + displaying results from faster sources. Defaults to 100 + milliseconds. + */ + updateSyncTime?: number; +} /** -Convert a snippet template to a function that can apply it. -Snippets are written using syntax like this: +Convert a snippet template to a function that can +[apply](https://codemirror.net/6/docs/ref/#autocomplete.Completion.apply) it. Snippets are written +using syntax like this: "for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}" @@ -4633,11 +5983,15 @@ cursor out of the current field deactivates the fields. The order of fields defaults to textual order, but you can add numbers to placeholders (`${1}` or `${1:defaultText}`) to provide a custom order. + +To include a literal `{` or `}` in your template, put a backslash +in front of it. This will be removed and the brace will not be +interpreted as indicating a placeholder. */ declare function snippet(template: string): (editor: { state: EditorState; dispatch: (tr: Transaction) => void; -}, _completion: Completion, from: number, to: number) => void; +}, completion: Completion | null, from: number, to: number) => void; /** A command that clears the active snippet, if any. */ @@ -4651,6 +6005,16 @@ Move to the previous snippet field, if available. */ declare const prevSnippetField: StateCommand; /** +Check if there is an active snippet with a next field for +`nextSnippetField` to move to. +*/ +declare function hasNextSnippetField(state: EditorState): boolean; +/** +Returns true if there is an active snippet and a previous field +for `prevSnippetField` to move to. +*/ +declare function hasPrevSnippetField(state: EditorState): boolean; +/** A facet that can be used to configure the key bindings used by snippets. The default binds Tab to [`nextSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.nextSnippetField), Shift-Tab to @@ -4690,6 +6054,61 @@ return those as completions. */ declare const completeAnyWord: CompletionSource; +/** +Configures bracket closing behavior for a syntax (via +[language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt)) using the `"closeBrackets"` +identifier. +*/ +interface CloseBracketConfig { + /** + The opening brackets to close. Defaults to `["(", "[", "{", "'", + '"']`. Brackets may be single characters or a triple of quotes + (as in `"''''"`). + */ + brackets?: string[]; + /** + Characters in front of which newly opened brackets are + automatically closed. Closing always happens in front of + whitespace. Defaults to `")]}:;>"`. + */ + before?: string; + /** + When determining whether a given node may be a string, recognize + these prefixes before the opening quote. + */ + stringPrefixes?: string[]; +} +/** +Extension to enable bracket-closing behavior. When a closeable +bracket is typed, its closing bracket is immediately inserted +after the cursor. When closing a bracket directly in front of a +closing bracket inserted by the extension, the cursor moves over +that bracket. +*/ +declare function closeBrackets(): Extension; +/** +Command that implements deleting a pair of matching brackets when +the cursor is between them. +*/ +declare const deleteBracketPair: StateCommand; +/** +Close-brackets related key bindings. Binds Backspace to +[`deleteBracketPair`](https://codemirror.net/6/docs/ref/#autocomplete.deleteBracketPair). +*/ +declare const closeBracketsKeymap: readonly KeyBinding[]; +/** +Implements the extension's behavior on text insertion. If the +given string counts as a bracket in the language around the +selection, and replacing the selection with it requires custom +behavior (inserting a closing version or skipping past a +previously-closed bracket), this function returns a transaction +representing that custom behavior. (You only need this if you want +to programmatically insert brackets—the +[`closeBrackets`](https://codemirror.net/6/docs/ref/#autocomplete.closeBrackets) extension will +take care of running this for user input.) +*/ +declare function insertBracket(state: EditorState, bracket: string): Transaction | null; + /** Returns an extension that enables autocompletion. */ @@ -4721,62 +6140,96 @@ declare function currentCompletions(state: EditorState): readonly Completion[]; Return the currently selected completion, if any. */ declare function selectedCompletion(state: EditorState): Completion | null; +/** +Returns the currently selected position in the active completion +list, or null if no completions are active. +*/ +declare function selectedCompletionIndex(state: EditorState): number | null; +/** +Create an effect that can be attached to a transaction to change +the currently selected completion. +*/ +declare function setSelectedCompletion(index: number): StateEffect; -type index_Completion = Completion; -type index_CompletionContext = CompletionContext; -declare const index_CompletionContext: typeof CompletionContext; -type index_CompletionResult = CompletionResult; -type index_CompletionSource = CompletionSource; -declare const index_acceptCompletion: typeof acceptCompletion; -declare const index_autocompletion: typeof autocompletion; -declare const index_clearSnippet: typeof clearSnippet; -declare const index_closeCompletion: typeof closeCompletion; -declare const index_completeAnyWord: typeof completeAnyWord; -declare const index_completeFromList: typeof completeFromList; -declare const index_completionKeymap: typeof completionKeymap; -declare const index_completionStatus: typeof completionStatus; -declare const index_currentCompletions: typeof currentCompletions; -declare const index_ifIn: typeof ifIn; -declare const index_ifNotIn: typeof ifNotIn; -declare const index_moveCompletionSelection: typeof moveCompletionSelection; -declare const index_nextSnippetField: typeof nextSnippetField; -declare const index_pickedCompletion: typeof pickedCompletion; -declare const index_prevSnippetField: typeof prevSnippetField; -declare const index_selectedCompletion: typeof selectedCompletion; -declare const index_snippet: typeof snippet; -declare const index_snippetCompletion: typeof snippetCompletion; -declare const index_snippetKeymap: typeof snippetKeymap; -declare const index_startCompletion: typeof startCompletion; -declare namespace index { +type index_d_CloseBracketConfig = CloseBracketConfig; +type index_d_Completion = Completion; +type index_d_CompletionContext = CompletionContext; +declare const index_d_CompletionContext: typeof CompletionContext; +type index_d_CompletionInfo = CompletionInfo; +type index_d_CompletionResult = CompletionResult; +type index_d_CompletionSection = CompletionSection; +type index_d_CompletionSource = CompletionSource; +declare const index_d_acceptCompletion: typeof acceptCompletion; +declare const index_d_autocompletion: typeof autocompletion; +declare const index_d_clearSnippet: typeof clearSnippet; +declare const index_d_closeBrackets: typeof closeBrackets; +declare const index_d_closeBracketsKeymap: typeof closeBracketsKeymap; +declare const index_d_closeCompletion: typeof closeCompletion; +declare const index_d_completeAnyWord: typeof completeAnyWord; +declare const index_d_completeFromList: typeof completeFromList; +declare const index_d_completionKeymap: typeof completionKeymap; +declare const index_d_completionStatus: typeof completionStatus; +declare const index_d_currentCompletions: typeof currentCompletions; +declare const index_d_deleteBracketPair: typeof deleteBracketPair; +declare const index_d_hasNextSnippetField: typeof hasNextSnippetField; +declare const index_d_hasPrevSnippetField: typeof hasPrevSnippetField; +declare const index_d_ifIn: typeof ifIn; +declare const index_d_ifNotIn: typeof ifNotIn; +declare const index_d_insertBracket: typeof insertBracket; +declare const index_d_insertCompletionText: typeof insertCompletionText; +declare const index_d_moveCompletionSelection: typeof moveCompletionSelection; +declare const index_d_nextSnippetField: typeof nextSnippetField; +declare const index_d_pickedCompletion: typeof pickedCompletion; +declare const index_d_prevSnippetField: typeof prevSnippetField; +declare const index_d_selectedCompletion: typeof selectedCompletion; +declare const index_d_selectedCompletionIndex: typeof selectedCompletionIndex; +declare const index_d_setSelectedCompletion: typeof setSelectedCompletion; +declare const index_d_snippet: typeof snippet; +declare const index_d_snippetCompletion: typeof snippetCompletion; +declare const index_d_snippetKeymap: typeof snippetKeymap; +declare const index_d_startCompletion: typeof startCompletion; +declare namespace index_d { export { - index_Completion as Completion, - index_CompletionContext as CompletionContext, - index_CompletionResult as CompletionResult, - index_CompletionSource as CompletionSource, - index_acceptCompletion as acceptCompletion, - index_autocompletion as autocompletion, - index_clearSnippet as clearSnippet, - index_closeCompletion as closeCompletion, - index_completeAnyWord as completeAnyWord, - index_completeFromList as completeFromList, - index_completionKeymap as completionKeymap, - index_completionStatus as completionStatus, - index_currentCompletions as currentCompletions, - index_ifIn as ifIn, - index_ifNotIn as ifNotIn, - index_moveCompletionSelection as moveCompletionSelection, - index_nextSnippetField as nextSnippetField, - index_pickedCompletion as pickedCompletion, - index_prevSnippetField as prevSnippetField, - index_selectedCompletion as selectedCompletion, - index_snippet as snippet, - index_snippetCompletion as snippetCompletion, - index_snippetKeymap as snippetKeymap, - index_startCompletion as startCompletion, + index_d_CloseBracketConfig as CloseBracketConfig, + index_d_Completion as Completion, + index_d_CompletionContext as CompletionContext, + index_d_CompletionInfo as CompletionInfo, + index_d_CompletionResult as CompletionResult, + index_d_CompletionSection as CompletionSection, + index_d_CompletionSource as CompletionSource, + index_d_acceptCompletion as acceptCompletion, + index_d_autocompletion as autocompletion, + index_d_clearSnippet as clearSnippet, + index_d_closeBrackets as closeBrackets, + index_d_closeBracketsKeymap as closeBracketsKeymap, + index_d_closeCompletion as closeCompletion, + index_d_completeAnyWord as completeAnyWord, + index_d_completeFromList as completeFromList, + index_d_completionKeymap as completionKeymap, + index_d_completionStatus as completionStatus, + index_d_currentCompletions as currentCompletions, + index_d_deleteBracketPair as deleteBracketPair, + index_d_hasNextSnippetField as hasNextSnippetField, + index_d_hasPrevSnippetField as hasPrevSnippetField, + index_d_ifIn as ifIn, + index_d_ifNotIn as ifNotIn, + index_d_insertBracket as insertBracket, + index_d_insertCompletionText as insertCompletionText, + index_d_moveCompletionSelection as moveCompletionSelection, + index_d_nextSnippetField as nextSnippetField, + index_d_pickedCompletion as pickedCompletion, + index_d_prevSnippetField as prevSnippetField, + index_d_selectedCompletion as selectedCompletion, + index_d_selectedCompletionIndex as selectedCompletionIndex, + index_d_setSelectedCompletion as setSelectedCompletion, + index_d_snippet as snippet, + index_d_snippetCompletion as snippetCompletion, + index_d_snippetKeymap as snippetKeymap, + index_d_startCompletion as startCompletion, }; } -declare type HighlightOptions = { +type HighlightOptions = { /** Determines whether, when nothing is selected, the word around the cursor is matched instead. Defaults to false. @@ -4792,6 +6245,10 @@ declare type HighlightOptions = { highlighting. Defaults to 100. */ maxMatches?: number; + /** + Whether to only highlight whole words. + */ + wholeWords?: boolean; }; /** This extension highlights text that matches the selection. It uses @@ -4801,6 +6258,11 @@ itself will be highlighted with `"cm-selectionMatch-main"`. */ declare function highlightSelectionMatches(options?: HighlightOptions): Extension; /** +Select next occurrence of the current selection. Expand selection +to the surrounding word when the selection is empty. +*/ +declare const selectNextOccurrence: StateCommand; +/** Default search-related key bindings. - Mod-f: [`openSearchPanel`](https://codemirror.net/6/docs/ref/#search.openSearchPanel) @@ -4811,17 +6273,10 @@ Default search-related key bindings. */ declare const searchKeymap: readonly KeyBinding[]; -/** -Default key bindings for this package. - - - Ctrl-/ (Cmd-/ on macOS): [`toggleComment`](https://codemirror.net/6/docs/ref/#comment.toggleComment). - - Shift-Alt-a: [`toggleBlockComment`](https://codemirror.net/6/docs/ref/#comment.toggleBlockComment). -*/ -declare const commentKeymap: readonly KeyBinding[]; - declare class LeafBlock { readonly start: number; content: string; + parsers: LeafBlockParser[]; } declare class Line { text: string; @@ -4837,7 +6292,7 @@ declare class Line { countIndent(to: number, from?: number, indent?: number): number; findColumn(goal: number): number; } -declare type BlockResult = boolean | null; +type BlockResult = boolean | null; declare class BlockContext implements PartialParse { readonly parser: MarkdownParser; private line; @@ -4850,6 +6305,8 @@ declare class BlockContext implements PartialParse { advance(): Tree; stopAt(pos: number): void; private reuseFragment; + get depth(): number; + parentType(depth?: number): NodeType; nextLine(): boolean; private moveRangeI; private lineChunkAt; @@ -4866,6 +6323,9 @@ interface NodeSpec { name: string; block?: boolean; composite?(cx: BlockContext, line: Line, value: number): boolean; + style?: Tag | readonly Tag[] | { + [selector: string]: Tag | readonly Tag[]; + }; } interface InlineParser { name: string; @@ -4877,7 +6337,7 @@ interface BlockParser { name: string; parse?(cx: BlockContext, line: Line): BlockResult; leaf?(cx: BlockContext, leaf: LeafBlock): LeafBlockParser | null; - endLeaf?(cx: BlockContext, line: Line): boolean; + endLeaf?(cx: BlockContext, line: Line, leaf: LeafBlock): boolean; before?: string; after?: string; } @@ -4893,7 +6353,7 @@ interface MarkdownConfig { remove?: readonly string[]; wrap?: ParseWrapper; } -declare type MarkdownExtension = MarkdownConfig | readonly MarkdownExtension[]; +type MarkdownExtension = MarkdownConfig | readonly MarkdownExtension[]; declare class MarkdownParser extends Parser { readonly nodeSet: NodeSet; createParse(input: Input, fragments: readonly TreeFragment[], ranges: readonly { @@ -4948,12 +6408,14 @@ declare function markdown(config?: { */ defaultCodeLanguage?: Language | LanguageSupport; /** - A collection of language descriptions to search through for a - matching language (with - [`LanguageDescription.matchLanguageName`](https://codemirror.net/6/docs/ref/#language.LanguageDescription^matchLanguageName)) - when a fenced code block has an info string. + A source of language support for highlighting fenced code + blocks. When it is an array, the parser will use + [`LanguageDescription.matchLanguageName`](https://codemirror.net/6/docs/ref/#language.LanguageDescription^matchLanguageName) + with the fenced code info to find a matching language. When it + is a function, will be called with the info string and may + return a language or `LanguageDescription` object. */ - codeLanguages?: readonly LanguageDescription[]; + codeLanguages?: readonly LanguageDescription[] | ((info: string) => Language | LanguageDescription | null); /** Set this to false to disable installation of the Markdown [keymap](https://codemirror.net/6/docs/ref/#lang-markdown.markdownKeymap). @@ -4970,8 +6432,47 @@ declare function markdown(config?: { [`commonmarkLanguage`](https://codemirror.net/6/docs/ref/#lang-markdown.commonmarkLanguage). */ base?: Language; + /** + By default, the extension installs an autocompletion source that + completes HTML tags when a `<` is typed. Set this to false to + disable this. + */ + completeHTMLTags?: boolean; }): LanguageSupport; +/** +Type used to specify tags to complete. +*/ +interface TagSpec { + /** + Define tag-specific attributes. Property names are attribute + names, and property values can be null to indicate free-form + attributes, or a list of strings for suggested attribute values. + */ + attrs?: Record; + /** + When set to false, don't complete global attributes on this tag. + */ + globalAttrs?: boolean; + /** + Can be used to specify a list of child tags that are valid + inside this tag. The default is to allow any tag. + */ + children?: readonly string[]; +} + +type NestedLang = { + tag: string; + attrs?: (attrs: { + [attr: string]: string; + }) => boolean; + parser: Parser; +}; +type NestedAttr = { + name: string; + tagName?: string; + parser: Parser; +}; /** A language provider based on the [Lezer HTML parser](https://github.com/lezer-parser/html), extended with the @@ -4992,13 +6493,134 @@ declare function html(config?: { document). */ matchClosingTags?: boolean; + selfClosingTags?: boolean; /** Determines whether [`autoCloseTags`](https://codemirror.net/6/docs/ref/#lang-html.autoCloseTags) is included in the support extensions. Defaults to true. */ autoCloseTags?: boolean; + /** + Add additional tags that can be completed. + */ + extraTags?: Record; + /** + Add additional completable attributes to all tags. + */ + extraGlobalAttributes?: Record; + /** + Register additional languages to parse the content of specific + tags. If given, `attrs` should be a function that, given an + object representing the tag's attributes, returns `true` if this + language applies. + */ + nestedLanguages?: NestedLang[]; + /** + Register additional languages to parse attribute values with. + */ + nestedAttributes?: NestedAttr[]; }): LanguageSupport; +type Severity = "hint" | "info" | "warning" | "error"; +/** +Describes a problem or hint for a piece of code. +*/ +interface Diagnostic { + /** + The start position of the relevant text. + */ + from: number; + /** + The end position. May be equal to `from`, though actually + covering text is preferable. + */ + to: number; + /** + The severity of the problem. This will influence how it is + displayed. + */ + severity: Severity; + /** + When given, add an extra CSS class to parts of the code that + this diagnostic applies to. + */ + markClass?: string; + /** + An optional source string indicating where the diagnostic is + coming from. You can put the name of your linter here, if + applicable. + */ + source?: string; + /** + The message associated with this diagnostic. + */ + message: string; + /** + An optional custom rendering function that displays the message + as a DOM node. + */ + renderMessage?: () => Node; + /** + An optional array of actions that can be taken on this + diagnostic. + */ + actions?: readonly Action[]; +} +/** +An action associated with a diagnostic. +*/ +interface Action { + /** + The label to show to the user. Should be relatively short. + */ + name: string; + /** + The function to call when the user activates this action. Is + given the diagnostic's _current_ position, which may have + changed since the creation of the diagnostic, due to editing. + */ + apply: (view: EditorView, from: number, to: number) => void; +} +type DiagnosticFilter = (diagnostics: readonly Diagnostic[]) => Diagnostic[]; +interface LintConfig { + /** + Time to wait (in milliseconds) after a change before running + the linter. Defaults to 750ms. + */ + delay?: number; + /** + Optional predicate that can be used to indicate when diagnostics + need to be recomputed. Linting is always re-done on document + changes. + */ + needsRefresh?: null | ((update: ViewUpdate) => boolean); + /** + Optional filter to determine which diagnostics produce markers + in the content. + */ + markerFilter?: null | DiagnosticFilter; + /** + Filter applied to a set of diagnostics shown in a tooltip. No + tooltip will appear if the empty set is returned. + */ + tooltipFilter?: null | DiagnosticFilter; +} +/** +Returns a transaction spec which updates the current set of +diagnostics, and enables the lint extension if if wasn't already +active. +*/ +declare function setDiagnostics(state: EditorState, diagnostics: readonly Diagnostic[]): TransactionSpec; +/** +The type of a function that produces diagnostics. +*/ +type LintSource = (view: EditorView) => readonly Diagnostic[] | Promise; +/** +Given a diagnostic source, this function returns an extension that +enables linting with that source. It will be called whenever the +editor is idle (after its content changed). +*/ +declare function linter(source: LintSource, config?: LintConfig): Extension; + /** A language provider based on the [Lezer JavaScript parser](https://github.com/lezer-parser/javascript), extended with @@ -5014,6 +6636,20 @@ declare function javascript(config?: { typescript?: boolean; }): LanguageSupport; +/** +A language provider based on the [Lezer CSS +parser](https://github.com/lezer-parser/css), extended with +highlighting and indentation information. +*/ +declare const cssLanguage: LRLanguage; +/** +Language support for CSS. +*/ +declare function css(): LanguageSupport; + +/** +Configuration for an [SQL Dialect](https://codemirror.net/6/docs/ref/#lang-sql.SQLDialect). +*/ declare type SQLDialectSpec = { /** A space-separated list of keywords for the dialect. @@ -5045,6 +6681,11 @@ declare type SQLDialectSpec = { */ spaceAfterDashes?: boolean; /** + When enabled, things quoted with "$$" are treated as + strings, rather than identifiers. + */ + doubleDollarQuotedStrings?: boolean; + /** When enabled, things quoted with double quotes are treated as strings, rather than identifiers. */ @@ -5054,6 +6695,11 @@ declare type SQLDialectSpec = { */ charSetCasts?: boolean; /** + Enables string quoting syntax like `q'[str]'`, as used in + PL/SQL. + */ + plsqlQuotingMechanism?: boolean; + /** The set of characters that make up operators. Defaults to `"*+\-%<>!=&|~^/"`. */ @@ -5068,6 +6714,16 @@ declare type SQLDialectSpec = { to `"\""`. */ identifierQuotes?: string; + /** + Controls whether bit values can be defined as 0b1010. Defaults + to false. + */ + unquotedBitLiterals?: boolean; + /** + Controls whether bit values can contain other characters than 0 and 1. + Defaults to false. + */ + treatBitsAsBytes?: boolean; }; /** Represents an SQL dialect. @@ -5078,6 +6734,11 @@ declare class SQLDialect { */ readonly language: LRLanguage; /** + The spec used to define this dialect. + */ + readonly spec: SQLDialectSpec; + private constructor(); + /** Returns the language for this dialect as an extension. */ get extension(): Extension; @@ -5096,8 +6757,9 @@ interface SQLConfig { */ dialect?: SQLDialect; /** - An object that maps table names to options (columns) that can - be completed for that table. Use lower-case names here. + An object that maps table names, optionally prefixed with a + schema name (`"schema.table"`) to options (columns) that can be + completed for that table. Use lower-case names here. */ schema?: { [table: string]: readonly (string | Completion)[]; @@ -5110,11 +6772,22 @@ interface SQLConfig { */ tables?: readonly Completion[]; /** + Similar to `tables`, if you want to provide completion objects + for your schemas rather than using the generated ones, pass them + here. + */ + schemas?: readonly Completion[]; + /** When given, columns from the named table can be completed directly at the top level. */ defaultTable?: string; /** + When given, tables prefixed with this schema name can be + completed directly at the top level. + */ + defaultSchema?: string; + /** When set to true, keyword completions will be upper-case. */ upperCaseKeywords?: boolean; @@ -5141,7 +6814,27 @@ Python language support. */ declare function python(): LanguageSupport; -declare type CollabConfig = { +/** +An update is a set of changes and effects. +*/ +interface Update { + /** + The changes made by this update. + */ + changes: ChangeSet; + /** + The effects in this update. There'll only ever be effects here + when you configure your collab extension with a + [`sharedEffects`](https://codemirror.net/6/docs/ref/#collab.collab^config.sharedEffects) option. + */ + effects?: readonly StateEffect[]; + /** + The [ID](https://codemirror.net/6/docs/ref/#collab.collab^config.clientID) of the client who + created this update. + */ + clientID: string; +} +type CollabConfig = { /** The starting document version. Defaults to 0. */ @@ -5165,5 +6858,32 @@ declare type CollabConfig = { Create an instance of the collaborative editing plugin. */ declare function collab(config?: CollabConfig): Extension; +/** +Create a transaction that represents a set of new updates received +from the authority. Applying this transaction moves the state +forward to adjust to the authority's view of the document. +*/ +declare function receiveUpdates(state: EditorState, updates: readonly Update[]): Transaction; +/** +Returns the set of locally made updates that still have to be sent +to the authority. The returned objects will also have an `origin` +property that points at the transaction that created them. This +may be useful if you want to send along metadata like timestamps. +(But note that the updates may have been mapped in the meantime, +whereas the transaction is just the original transaction that +created them.) +*/ +declare function sendableUpdates(state: EditorState): readonly (Update & { + origin: Transaction; +})[]; +/** +Get the version up to which the collab plugin has synced with the +central authority. +*/ +declare function getSyncedVersion(state: EditorState): number; +/** +Get this editor's collaborative editing client ID. +*/ +declare function getClientID(state: EditorState): string; -export { Annotation, Compartment, Decoration, EditorSelection, EditorState, EditorView, Facet, HighlightStyle, NodeProp, PostgreSQL, SelectionRange, StateEffect, StateField, StreamLanguage, Text, Transaction, TreeCursor, ViewPlugin, ViewUpdate, WidgetType, index as autocomplete, bracketMatching, closeBrackets, closeBracketsKeymap, collab, combineConfig, commentKeymap, completionKeymap, defaultHighlightStyle, defaultKeymap, drawSelection, foldGutter, foldKeymap, highlightSelectionMatches, highlightSpecialChars, history, historyKeymap, html, htmlLanguage, indentLess, indentMore, indentOnInput, indentUnit, javascript, javascriptLanguage, julia as julia_andrey, julia$1 as julia_legacy, keymap, lineNumbers, markdown, markdownLanguage, parseCode, parseMixed, placeholder, python, pythonLanguage, rectangularSelection, searchKeymap, sql, syntaxTree, tags }; +export { Annotation, ChangeSet, Compartment, Decoration, Diagnostic, EditorSelection, EditorState, EditorView, Facet, HighlightStyle, NodeProp, PostgreSQL, SelectionRange, StateEffect, StateField, Text, Tooltip, Transaction, TreeCursor, ViewPlugin, ViewUpdate, WidgetType, index_d as autocomplete, bracketMatching, closeBrackets, closeBracketsKeymap, collab, combineConfig, completionKeymap, css, cssLanguage, defaultHighlightStyle, defaultKeymap, drawSelection, foldGutter, foldKeymap, getClientID, getSyncedVersion, highlightSelectionMatches, highlightSpecialChars, history, historyKeymap, html, htmlLanguage, indentLess, indentMore, indentOnInput, indentUnit, javascript, javascriptLanguage, julia as julia_andrey, keymap, lineNumbers, linter, markdown, markdownLanguage, moveLineDown, moveLineUp, parseCode, parseMixed, placeholder, python, pythonLanguage, receiveUpdates, rectangularSelection, searchKeymap, selectNextOccurrence, sendableUpdates, setDiagnostics, showTooltip, sql, syntaxHighlighting, syntaxTree, syntaxTreeAvailable, tags, tooltips }; diff --git a/frontend/imports/CodemirrorPlutoSetup.js b/frontend/imports/CodemirrorPlutoSetup.js index 0132dd044e..acb00b9ce1 100644 --- a/frontend/imports/CodemirrorPlutoSetup.js +++ b/frontend/imports/CodemirrorPlutoSetup.js @@ -4,15 +4,16 @@ import { Compartment, EditorView, placeholder, - julia_legacy, julia_andrey, keymap, + syntaxHighlighting, history, historyKeymap, defaultKeymap, - StreamLanguage, indentMore, indentLess, + moveLineUp, + moveLineDown, tags, HighlightStyle, lineNumbers, @@ -28,8 +29,9 @@ import { closeBracketsKeymap, searchKeymap, foldKeymap, - commentKeymap, + // commentKeymap, syntaxTree, + syntaxTreeAvailable, Decoration, ViewUpdate, ViewPlugin, @@ -55,23 +57,32 @@ import { sql, javascript, python, -} from "https://cdn.jsdelivr.net/gh/JuliaPluto/codemirror-pluto-setup@0.19.6/dist/index.es.min.js" + Text, + css, + cssLanguage, + selectNextOccurrence, + linter, + setDiagnostics, + //@ts-ignore +} from "https://cdn.jsdelivr.net/gh/JuliaPluto/codemirror-pluto-setup@1234.2.0/dist/index.es.min.js" export { + linter, + setDiagnostics, EditorState, EditorSelection, Compartment, EditorView, placeholder, - julia_legacy, julia_andrey, keymap, history, historyKeymap, defaultKeymap, - StreamLanguage, indentMore, indentLess, + moveLineUp, + moveLineDown, tags, HighlightStyle, lineNumbers, @@ -87,8 +98,8 @@ export { closeBracketsKeymap, searchKeymap, foldKeymap, - commentKeymap, syntaxTree, + syntaxTreeAvailable, Decoration, ViewUpdate, ViewPlugin, @@ -112,6 +123,11 @@ export { PostgreSQL, pythonLanguage, sql, + syntaxHighlighting, javascript, python, + Text, + css, + cssLanguage, + selectNextOccurrence, } diff --git a/frontend/imports/DOMPurify.d.ts b/frontend/imports/DOMPurify.d.ts new file mode 100644 index 0000000000..ff1c9b5cf6 --- /dev/null +++ b/frontend/imports/DOMPurify.d.ts @@ -0,0 +1,148 @@ +// Type definitions for DOM Purify 3.0 +// Project: https://github.com/cure53/DOMPurify +// Definitions by: Dave Taylor https://github.com/davetayls +// Samira Bazuzi +// FlowCrypt +// Exigerr +// Piotr Błażejewicz +// Nicholas Ellul +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// Minimum TypeScript Version: 4.5 + + +export as namespace DOMPurify; +export = DOMPurify; + +declare const DOMPurify: createDOMPurifyI; + +type WindowLike = Pick< + typeof globalThis, + | 'NodeFilter' + | 'Node' + | 'Element' + | 'HTMLTemplateElement' + | 'DocumentFragment' + | 'HTMLFormElement' + | 'DOMParser' + | 'NamedNodeMap' +>; + +interface createDOMPurifyI extends DOMPurify.DOMPurifyI { + (window?: Window | WindowLike): DOMPurify.DOMPurifyI; +} + +declare namespace DOMPurify { + interface DOMPurifyI { + sanitize(source: string | Node): string; + // sanitize(source: string | Node, config: Config & { RETURN_TRUSTED_TYPE: true }): TrustedHTML; + sanitize( + source: string | Node, + config: Config & { RETURN_DOM_FRAGMENT?: false | undefined; RETURN_DOM?: false | undefined }, + ): string; + sanitize(source: string | Node, config: Config & { RETURN_DOM_FRAGMENT: true }): DocumentFragment; + sanitize(source: string | Node, config: Config & { RETURN_DOM: true }): HTMLElement; + sanitize(source: string | Node, config: Config): string | HTMLElement | DocumentFragment; + + addHook( + hook: 'uponSanitizeElement', + cb: (currentNode: Element, data: SanitizeElementHookEvent, config: Config) => void, + ): void; + addHook( + hook: 'uponSanitizeAttribute', + cb: (currentNode: Element, data: SanitizeAttributeHookEvent, config: Config) => void, + ): void; + addHook(hook: HookName, cb: (currentNode: Element, data: HookEvent, config: Config) => void): void; + + setConfig(cfg: Config): void; + clearConfig(): void; + isValidAttribute(tag: string, attr: string, value: string): boolean; + + removeHook(entryPoint: HookName): void; + removeHooks(entryPoint: HookName): void; + removeAllHooks(): void; + + version: string; + removed: any[]; + isSupported: boolean; + } + + interface Config { + ADD_ATTR?: string[] | undefined; + ADD_DATA_URI_TAGS?: string[] | undefined; + ADD_TAGS?: string[] | undefined; + ADD_URI_SAFE_ATTR?: string[] | undefined; + ALLOW_ARIA_ATTR?: boolean | undefined; + ALLOW_DATA_ATTR?: boolean | undefined; + ALLOW_UNKNOWN_PROTOCOLS?: boolean | undefined; + ALLOW_SELF_CLOSE_IN_ATTR?: boolean | undefined; + ALLOWED_ATTR?: string[] | undefined; + ALLOWED_TAGS?: string[] | undefined; + ALLOWED_NAMESPACES?: string[] | undefined; + ALLOWED_URI_REGEXP?: RegExp | undefined; + FORBID_ATTR?: string[] | undefined; + FORBID_CONTENTS?: string[] | undefined; + FORBID_TAGS?: string[] | undefined; + FORCE_BODY?: boolean | undefined; + IN_PLACE?: boolean | undefined; + KEEP_CONTENT?: boolean | undefined; + /** + * change the default namespace from HTML to something different + */ + NAMESPACE?: string | undefined; + PARSER_MEDIA_TYPE?: string | undefined; + RETURN_DOM_FRAGMENT?: boolean | undefined; + /** + * This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false` + * might cause XSS from attacks hidden in closed shadowroots in case the browser + * supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/ + */ + RETURN_DOM_IMPORT?: boolean | undefined; + RETURN_DOM?: boolean | undefined; + RETURN_TRUSTED_TYPE?: boolean | undefined; + SAFE_FOR_TEMPLATES?: boolean | undefined; + SANITIZE_DOM?: boolean | undefined; + /** @default false */ + SANITIZE_NAMED_PROPS?: boolean | undefined; + USE_PROFILES?: + | false + | { + mathMl?: boolean | undefined; + svg?: boolean | undefined; + svgFilters?: boolean | undefined; + html?: boolean | undefined; + } + | undefined; + WHOLE_DOCUMENT?: boolean | undefined; + CUSTOM_ELEMENT_HANDLING?: { + tagNameCheck?: RegExp | ((tagName: string) => boolean) | null | undefined; + attributeNameCheck?: RegExp | ((lcName: string) => boolean) | null | undefined; + allowCustomizedBuiltInElements?: boolean | undefined; + }; + } + + type HookName = + | 'beforeSanitizeElements' + | 'uponSanitizeElement' + | 'afterSanitizeElements' + | 'beforeSanitizeAttributes' + | 'uponSanitizeAttribute' + | 'afterSanitizeAttributes' + | 'beforeSanitizeShadowDOM' + | 'uponSanitizeShadowNode' + | 'afterSanitizeShadowDOM'; + + type HookEvent = SanitizeElementHookEvent | SanitizeAttributeHookEvent | null; + + interface SanitizeElementHookEvent { + tagName: string; + allowedTags: { [key: string]: boolean }; + } + + interface SanitizeAttributeHookEvent { + attrName: string; + attrValue: string; + keepAttr: boolean; + allowedAttributes: { [key: string]: boolean }; + forceKeepAttr?: boolean | undefined; + } +} \ No newline at end of file diff --git a/frontend/imports/DOMPurify.js b/frontend/imports/DOMPurify.js new file mode 100644 index 0000000000..f49c6bfe36 --- /dev/null +++ b/frontend/imports/DOMPurify.js @@ -0,0 +1,4 @@ +// @ts-ignore +import purify from "https://esm.sh/dompurify@3.0.3?pin=v122" + +export default purify diff --git a/frontend/imports/Preact.d.ts b/frontend/imports/Preact.d.ts index 3b2382415b..e491d9168b 100644 --- a/frontend/imports/Preact.d.ts +++ b/frontend/imports/Preact.d.ts @@ -1,23 +1,51 @@ declare class ReactElement {} -type ValidRenderResult = number | string | Array | ReactElement +type ComponentChild = number | string | Array | ReactElement type Dispatch = (value: A) => void type SetStateAction = S | ((prevState: S) => S) -export declare class Component { - state: State +export interface ErrorInfo { + componentStack?: string; +} + +export declare class Component

{ + constructor(props?: P, context?: any); + + componentWillMount?(): void; + componentDidMount?(): void; + componentWillUnmount?(): void; + getChildContext?(): object; + componentWillReceiveProps?(nextProps: Readonly

, nextContext: any): void; + shouldComponentUpdate?( + nextProps: Readonly

, + nextState: Readonly, + nextContext: any + ): boolean; + componentWillUpdate?( + nextProps: Readonly

, + nextState: Readonly, + nextContext: any + ): void; + getSnapshotBeforeUpdate?(oldProps: Readonly

, oldState: Readonly): any; + componentDidUpdate?( + previousProps: Readonly

, + previousState: Readonly, + snapshot: any + ): void; + componentDidCatch?(error: any, errorInfo: ErrorInfo): void; + state: S setState(state: any, callback?: any): void - props: any + props: P base: HTMLElement - render(): ValidRenderResult + render(): ComponentChild } export declare function html(strings: TemplateStringsArray, ...interpolations: Array): ReactElement -export declare function render(vnode: ValidRenderResult, parent: Element | Document | ShadowRoot | DocumentFragment, replaceNode?: Element | Text): void -export declare function hydrate(vnode: ValidRenderResult, parent: Element | Document | ShadowRoot | DocumentFragment): void -export declare function cloneElement(vnode: ReactElement, props?: any, ...children: ValidRenderResult[]): ReactElement +export declare function render(vnode: ComponentChild, parent: Element | Document | ShadowRoot | DocumentFragment, replaceNode?: Element | Text): void +export declare function hydrate(vnode: ComponentChild, parent: Element | Document | ShadowRoot | DocumentFragment): void +export declare function cloneElement(vnode: ReactElement, props?: any, ...children: ComponentChild[]): ReactElement export declare function h(type: string, props: any, ...children: any[]): ReactElement declare function SetState(value: T): void @@ -30,6 +58,7 @@ export declare function useRef(initialValue?: T): Ref export declare function useMemo(calculate: () => T, deps?: Array): T export declare function useCallback(callback: T, deps?: Array): T +export declare function useErrorBoundary(callback?: (error: any) => Promise | void): [any, () => void]; type UnsubscribeFn = () => void type EffectFn = () => void | UnsubscribeFn diff --git a/frontend/imports/Preact.js b/frontend/imports/Preact.js index 3e0a27d570..36cc871a5d 100644 --- a/frontend/imports/Preact.js +++ b/frontend/imports/Preact.js @@ -1,544 +1,37 @@ -var te = Object.defineProperty; -var ne = (e, t)=>{ - for(var n in t)te(e, n, { - get: t[n], - enumerable: !0 - }); -}; -var N = { -}; -ne(N, { - Component: ()=>S - , - Fragment: ()=>P - , - cloneElement: ()=>se - , - createContext: ()=>ce - , - createElement: ()=>V - , - createRef: ()=>re - , - h: ()=>V - , - hydrate: ()=>ee - , - isValidElement: ()=>F - , - options: ()=>d - , - render: ()=>Z - , - toChildArray: ()=>K -}); -var d, F, C, H, R, I, U = { -}, L = [], _e = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; -function b(e, t) { - for(var n in t)e[n] = t[n]; - return e; +// @ts-nocheck +import { render, Component, h, cloneElement, createContext, createRef, hydrate } from "https://esm.sh/preact@10.13.2?pin=v113&target=es2020" +import { + // + useEffect, + useLayoutEffect, + useState, + useRef, + useMemo, + useCallback, + useContext, + useErrorBoundary, +} from "https://esm.sh/preact@10.13.2/hooks?pin=v113&target=es2020" + +import htm from "https://esm.sh/htm@3.1.1?pin=v113&target=es2020" + +const html = htm.bind(h) + +export { + // + html, + render, + Component, + useEffect, + useLayoutEffect, + useState, + useRef, + useMemo, + useCallback, + useErrorBoundary, + createContext, + createRef, + useContext, + h, + cloneElement, + hydrate, } -function O(e) { - var t = e.parentNode; - t && t.removeChild(e); -} -function V(e, t, n) { - var o, l, _, c = arguments, s = { - }; - for(_ in t)_ == "key" ? o = t[_] : _ == "ref" ? l = t[_] : s[_] = t[_]; - if (arguments.length > 3) for(n = [ - n - ], _ = 3; _ < arguments.length; _++)n.push(c[_]); - if (n != null && (s.children = n), typeof e == "function" && e.defaultProps != null) for(_ in e.defaultProps)s[_] === void 0 && (s[_] = e.defaultProps[_]); - return x(e, s, o, l, null); -} -function x(e, t, n, o, l) { - var _ = { - type: e, - props: t, - key: n, - ref: o, - __k: null, - __: null, - __b: 0, - __e: null, - __d: void 0, - __c: null, - __h: null, - constructor: void 0, - __v: l ?? ++d.__v - }; - return d.vnode != null && d.vnode(_), _; -} -function re() { - return { - current: null - }; -} -function P(e) { - return e.children; -} -function S(e, t) { - this.props = e, this.context = t; -} -function E(e, t) { - if (t == null) return e.__ ? E(e.__, e.__.__k.indexOf(e) + 1) : null; - for(var n; t < e.__k.length; t++)if ((n = e.__k[t]) != null && n.__e != null) return n.__e; - return typeof e.type == "function" ? E(e) : null; -} -function $(e) { - var t, n; - if ((e = e.__) != null && e.__c != null) { - for(e.__e = e.__c.base = null, t = 0; t < e.__k.length; t++)if ((n = e.__k[t]) != null && n.__e != null) { - e.__e = e.__c.base = n.__e; - break; - } - return $(e); - } -} -function M(e) { - (!e.__d && (e.__d = !0) && C.push(e) && !T.__r++ || R !== d.debounceRendering) && ((R = d.debounceRendering) || H)(T); -} -function T() { - for(var e; T.__r = C.length;)e = C.sort(function(t, n) { - return t.__v.__b - n.__v.__b; - }), C = [], e.some(function(t) { - var n, o, l, _, c, s; - t.__d && (c = (_ = (n = t).__v).__e, (s = n.__P) && (o = [], (l = b({ - }, _)).__v = _.__v + 1, W(s, _, l, n.__n, s.ownerSVGElement !== void 0, _.__h != null ? [ - c - ] : null, o, c ?? E(_), _.__h), B(o, _), _.__e != c && $(_))); - }); -} -function J(e, t, n, o, l, _, c, s, p, u) { - var r, v, f, i, y, a, h, m = o && o.__k || L, g = m.length; - for(n.__k = [], r = 0; r < t.length; r++)if ((i = n.__k[r] = (i = t[r]) == null || typeof i == "boolean" ? null : typeof i == "string" || typeof i == "number" || typeof i == "bigint" ? x(null, i, null, null, i) : Array.isArray(i) ? x(P, { - children: i - }, null, null, null) : i.__b > 0 ? x(i.type, i.props, i.key, null, i.__v) : i) != null) { - if (i.__ = n, i.__b = n.__b + 1, (f = m[r]) === null || f && i.key == f.key && i.type === f.type) m[r] = void 0; - else for(v = 0; v < g; v++){ - if ((f = m[v]) && i.key == f.key && i.type === f.type) { - m[v] = void 0; - break; - } - f = null; - } - W(e, i, f = f || U, l, _, c, s, p, u), y = i.__e, (v = i.ref) && f.ref != v && (h || (h = []), f.ref && h.push(f.ref, null, i), h.push(v, i.__c || y, i)), y != null ? (a == null && (a = y), typeof i.type == "function" && i.__k != null && i.__k === f.__k ? i.__d = p = j(i, p, e) : p = z(e, i, f, m, y, p), u || n.type !== "option" ? typeof n.type == "function" && (n.__d = p) : e.value = "") : p && f.__e == p && p.parentNode != e && (p = E(f)); - } - for(n.__e = a, r = g; r--;)m[r] != null && (typeof n.type == "function" && m[r].__e != null && m[r].__e == n.__d && (n.__d = E(o, r + 1)), q(m[r], m[r])); - if (h) for(r = 0; r < h.length; r++)G(h[r], h[++r], h[++r]); -} -function j(e, t, n) { - var o, l; - for(o = 0; o < e.__k.length; o++)(l = e.__k[o]) && (l.__ = e, t = typeof l.type == "function" ? j(l, t, n) : z(n, l, l, e.__k, l.__e, t)); - return t; -} -function K(e, t) { - return t = t || [], e == null || typeof e == "boolean" || (Array.isArray(e) ? e.some(function(n) { - K(n, t); - }) : t.push(e)), t; -} -function z(e, t, n, o, l, _) { - var c, s, p; - if (t.__d !== void 0) c = t.__d, t.__d = void 0; - else if (n == null || l != _ || l.parentNode == null) e: if (_ == null || _.parentNode !== e) e.appendChild(l), c = null; - else { - for(s = _, p = 0; (s = s.nextSibling) && p < o.length; p += 2)if (s == l) break e; - e.insertBefore(l, _), c = _; - } - return c !== void 0 ? c : l.nextSibling; -} -function oe(e, t, n, o, l) { - var _; - for(_ in n)_ === "children" || _ === "key" || _ in t || D(e, _, null, n[_], o); - for(_ in t)l && typeof t[_] != "function" || _ === "children" || _ === "key" || _ === "value" || _ === "checked" || n[_] === t[_] || D(e, _, t[_], n[_], o); -} -function Q(e, t, n) { - t[0] === "-" ? e.setProperty(t, n) : e[t] = n == null ? "" : typeof n != "number" || _e.test(t) ? n : n + "px"; -} -function D(e, t, n, o, l) { - var _; - e: if (t === "style") if (typeof n == "string") e.style.cssText = n; - else { - if (typeof o == "string" && (e.style.cssText = o = ""), o) for(t in o)n && t in n || Q(e.style, t, ""); - if (n) for(t in n)o && n[t] === o[t] || Q(e.style, t, n[t]); - } - else if (t[0] === "o" && t[1] === "n") _ = t !== (t = t.replace(/Capture$/, "")), t = t.toLowerCase() in e ? t.toLowerCase().slice(2) : t.slice(2), e.l || (e.l = { - }), e.l[t + _] = n, n ? o || e.addEventListener(t, _ ? Y : X, _) : e.removeEventListener(t, _ ? Y : X, _); - else if (t !== "dangerouslySetInnerHTML") { - if (l) t = t.replace(/xlink[H:h]/, "h").replace(/sName$/, "s"); - else if (t !== "href" && t !== "list" && t !== "form" && t !== "tabIndex" && t !== "download" && t in e) try { - e[t] = n ?? ""; - break e; - } catch (c) { - } - typeof n == "function" || (n != null && (n !== !1 || t[0] === "a" && t[1] === "r") ? e.setAttribute(t, n) : e.removeAttribute(t)); - } -} -function X(e) { - this.l[e.type + !1](d.event ? d.event(e) : e); -} -function Y(e) { - this.l[e.type + !0](d.event ? d.event(e) : e); -} -function W(e, t, n, o, l, _, c, s, p) { - var u, r, v, f, i, y, a, h, m, g, w, k = t.type; - if (t.constructor !== void 0) return null; - n.__h != null && (p = n.__h, s = t.__e = n.__e, t.__h = null, _ = [ - s - ]), (u = d.__b) && u(t); - try { - e: if (typeof k == "function") { - if (h = t.props, m = (u = k.contextType) && o[u.__c], g = u ? m ? m.props.value : u.__ : o, n.__c ? a = (r = t.__c = n.__c).__ = r.__E : ("prototype" in k && k.prototype.render ? t.__c = r = new k(h, g) : (t.__c = r = new S(h, g), r.constructor = k, r.render = ie), m && m.sub(r), r.props = h, r.state || (r.state = { - }), r.context = g, r.__n = o, v = r.__d = !0, r.__h = []), r.__s == null && (r.__s = r.state), k.getDerivedStateFromProps != null && (r.__s == r.state && (r.__s = b({ - }, r.__s)), b(r.__s, k.getDerivedStateFromProps(h, r.__s))), f = r.props, i = r.state, v) k.getDerivedStateFromProps == null && r.componentWillMount != null && r.componentWillMount(), r.componentDidMount != null && r.__h.push(r.componentDidMount); - else { - if (k.getDerivedStateFromProps == null && h !== f && r.componentWillReceiveProps != null && r.componentWillReceiveProps(h, g), !r.__e && r.shouldComponentUpdate != null && r.shouldComponentUpdate(h, r.__s, g) === !1 || t.__v === n.__v) { - r.props = h, r.state = r.__s, t.__v !== n.__v && (r.__d = !1), r.__v = t, t.__e = n.__e, t.__k = n.__k, t.__k.forEach(function(A) { - A && (A.__ = t); - }), r.__h.length && c.push(r); - break e; - } - r.componentWillUpdate != null && r.componentWillUpdate(h, r.__s, g), r.componentDidUpdate != null && r.__h.push(function() { - r.componentDidUpdate(f, i, y); - }); - } - r.context = g, r.props = h, r.state = r.__s, (u = d.__r) && u(t), r.__d = !1, r.__v = t, r.__P = e, u = r.render(r.props, r.state, r.context), r.state = r.__s, r.getChildContext != null && (o = b(b({ - }, o), r.getChildContext())), v || r.getSnapshotBeforeUpdate == null || (y = r.getSnapshotBeforeUpdate(f, i)), w = u != null && u.type === P && u.key == null ? u.props.children : u, J(e, Array.isArray(w) ? w : [ - w - ], t, n, o, l, _, c, s, p), r.base = t.__e, t.__h = null, r.__h.length && c.push(r), a && (r.__E = r.__ = null), r.__e = !1; - } else _ == null && t.__v === n.__v ? (t.__k = n.__k, t.__e = n.__e) : t.__e = le(n.__e, t, n, o, l, _, c, p); - (u = d.diffed) && u(t); - } catch (A) { - t.__v = null, (p || _ != null) && (t.__e = s, t.__h = !!p, _[_.indexOf(s)] = null), d.__e(A, t, n); - } -} -function B(e, t) { - d.__c && d.__c(t, e), e.some(function(n) { - try { - e = n.__h, n.__h = [], e.some(function(o) { - o.call(n); - }); - } catch (o) { - d.__e(o, n.__v); - } - }); -} -function le(e, t, n, o, l, _, c, s) { - var p, u, r, v, f = n.props, i = t.props, y = t.type, a = 0; - if (y === "svg" && (l = !0), _ != null) { - for(; a < _.length; a++)if ((p = _[a]) && (p === e || (y ? p.localName == y : p.nodeType == 3))) { - e = p, _[a] = null; - break; - } - } - if (e == null) { - if (y === null) return document.createTextNode(i); - e = l ? document.createElementNS("http://www.w3.org/2000/svg", y) : document.createElement(y, i.is && i), _ = null, s = !1; - } - if (y === null) f === i || s && e.data === i || (e.data = i); - else { - if (_ = _ && L.slice.call(e.childNodes), u = (f = n.props || U).dangerouslySetInnerHTML, r = i.dangerouslySetInnerHTML, !s) { - if (_ != null) for(f = { - }, v = 0; v < e.attributes.length; v++)f[e.attributes[v].name] = e.attributes[v].value; - (r || u) && (r && (u && r.__html == u.__html || r.__html === e.innerHTML) || (e.innerHTML = r && r.__html || "")); - } - if (oe(e, i, f, l, s), r) t.__k = []; - else if (a = t.props.children, J(e, Array.isArray(a) ? a : [ - a - ], t, n, o, l && y !== "foreignObject", _, c, e.firstChild, s), _ != null) for(a = _.length; a--;)_[a] != null && O(_[a]); - s || ("value" in i && (a = i.value) !== void 0 && (a !== e.value || y === "progress" && !a) && D(e, "value", a, f.value, !1), "checked" in i && (a = i.checked) !== void 0 && a !== e.checked && D(e, "checked", a, f.checked, !1)); - } - return e; -} -function G(e, t, n) { - try { - typeof e == "function" ? e(t) : e.current = t; - } catch (o) { - d.__e(o, n); - } -} -function q(e, t, n) { - var o, l, _; - if (d.unmount && d.unmount(e), (o = e.ref) && (o.current && o.current !== e.__e || G(o, null, t)), n || typeof e.type == "function" || (n = (l = e.__e) != null), e.__e = e.__d = void 0, (o = e.__c) != null) { - if (o.componentWillUnmount) try { - o.componentWillUnmount(); - } catch (c) { - d.__e(c, t); - } - o.base = o.__P = null; - } - if (o = e.__k) for(_ = 0; _ < o.length; _++)o[_] && q(o[_], t, n); - l != null && O(l); -} -function ie(e, t, n) { - return this.constructor(e, n); -} -function Z(e, t, n) { - var o, l, _; - d.__ && d.__(e, t), l = (o = typeof n == "function") ? null : n && n.__k || t.__k, _ = [], W(t, e = (!o && n || t).__k = V(P, null, [ - e - ]), l || U, U, t.ownerSVGElement !== void 0, !o && n ? [ - n - ] : l ? null : t.firstChild ? L.slice.call(t.childNodes) : null, _, !o && n ? n : l ? l.__e : t.firstChild, o), B(_, e); -} -function ee(e, t) { - Z(e, t, ee); -} -function se(e, t, n) { - var o, l, _, c = arguments, s = b({ - }, e.props); - for(_ in t)_ == "key" ? o = t[_] : _ == "ref" ? l = t[_] : s[_] = t[_]; - if (arguments.length > 3) for(n = [ - n - ], _ = 3; _ < arguments.length; _++)n.push(c[_]); - return n != null && (s.children = n), x(e.type, s, o || e.key, l || e.ref, null); -} -function ce(e, t) { - var n = { - __c: t = "__cC" + I++, - __: e, - Consumer: function(o, l) { - return o.children(l); - }, - Provider: function(o) { - var l, _; - return this.getChildContext || (l = [], (_ = { - })[t] = this, this.getChildContext = function() { - return _; - }, this.shouldComponentUpdate = function(c) { - this.props.value !== c.value && l.some(M); - }, this.sub = function(c) { - l.push(c); - var s = c.componentWillUnmount; - c.componentWillUnmount = function() { - l.splice(l.indexOf(c), 1), s && s.call(c); - }; - }), o.children; - } - }; - return n.Provider.__ = n.Consumer.contextType = n; -} -d = { - __e: function(e, t) { - for(var n, o, l; t = t.__;)if ((n = t.__c) && !n.__) try { - if ((o = n.constructor) && o.getDerivedStateFromError != null && (n.setState(o.getDerivedStateFromError(e)), l = n.__d), n.componentDidCatch != null && (n.componentDidCatch(e), l = n.__d), l) return n.__E = n; - } catch (_) { - e = _; - } - throw e; - }, - __v: 0 -}, F = function(e) { - return e != null && e.constructor === void 0; -}, S.prototype.setState = function(e, t) { - var n; - n = this.__s != null && this.__s !== this.state ? this.__s : this.__s = b({ - }, this.state), typeof e == "function" && (e = e(b({ - }, n), this.props)), e && b(n, e), e != null && this.__v && (t && this.__h.push(t), M(this)); -}, S.prototype.forceUpdate = function(e) { - this.__v && (this.__e = !0, e && this.__h.push(e), M(this)); -}, S.prototype.render = P, C = [], H = typeof Promise == "function" ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, T.__r = 0, I = 0; -var { createElement: ae , cloneElement: ue , toChildArray: de , hydrate: he , Fragment: ve , h: ye , createContext: me , options: ge , createRef: ke , isValidElement: be , Component: Ce , render: xe } = N; -var q1 = Object.defineProperty; -var k = (_, e)=>{ - for(var n in e)q1(_, n, { - get: e[n], - enumerable: !0 - }); -}; -var h1 = { -}; -k(h1, { - useCallback: ()=>S1 - , - useContext: ()=>B1 - , - useDebugValue: ()=>I1 - , - useEffect: ()=>R1 - , - useErrorBoundary: ()=>L1 - , - useImperativeHandle: ()=>V1 - , - useLayoutEffect: ()=>D1 - , - useMemo: ()=>l - , - useReducer: ()=>x1 - , - useRef: ()=>T1 - , - useState: ()=>C1 -}); -var c, r, H1, a = 0, m = [], d1 = ge.__b, E1 = ge.__r, y = ge.diffed, b1 = ge.__c, g = ge.unmount; -function i(_, e) { - ge.__h && ge.__h(r, _, a || e), a = 0; - var n = r.__H || (r.__H = { - __: [], - __h: [] - }); - return _ >= n.__.length && n.__.push({ - }), n.__[_]; -} -function C1(_) { - return a = 1, x1(A, _); -} -function x1(_, e, n) { - var t = i(c++, 2); - return t.t = _, t.__c || (t.__ = [ - n ? n(e) : A(void 0, e), - function(o) { - var f = t.t(t.__[0], o); - t.__[0] !== f && (t.__ = [ - f, - t.__[1] - ], t.__c.setState({ - })); - } - ], t.__c = r), t.__; -} -function R1(_, e) { - var n = i(c++, 3); - !ge.__s && v(n.__H, e) && (n.__ = _, n.__H = e, r.__H.__h.push(n)); -} -function D1(_, e) { - var n = i(c++, 4); - !ge.__s && v(n.__H, e) && (n.__ = _, n.__H = e, r.__h.push(n)); -} -function T1(_) { - return a = 5, l(function() { - return { - current: _ - }; - }, []); -} -function V1(_, e, n) { - a = 6, D1(function() { - typeof _ == "function" ? _(e()) : _ && (_.current = e()); - }, n == null ? n : n.concat(_)); -} -function l(_, e) { - var n = i(c++, 7); - return v(n.__H, e) && (n.__ = _(), n.__H = e, n.__h = _), n.__; -} -function S1(_, e) { - return a = 8, l(function() { - return _; - }, e); -} -function B1(_) { - var e = r.context[_.__c], n = i(c++, 9); - return n.__c = _, e ? (n.__ == null && (n.__ = !0, e.sub(r)), e.props.value) : _.__; -} -function I1(_, e) { - ge.useDebugValue && ge.useDebugValue(e ? e(_) : _); -} -function L1(_) { - var e = i(c++, 10), n = C1(); - return e.__ = _, r.componentDidCatch || (r.componentDidCatch = function(t) { - e.__ && e.__(t), n[1](t); - }), [ - n[0], - function() { - n[1](void 0); - } - ]; -} -function M1() { - m.forEach(function(_) { - if (_.__P) try { - _.__H.__h.forEach(s), _.__H.__h.forEach(p), _.__H.__h = []; - } catch (e) { - _.__H.__h = [], ge.__e(e, _.__v); - } - }), m = []; -} -ge.__b = function(_) { - r = null, d1 && d1(_); -}, ge.__r = function(_) { - E1 && E1(_), c = 0; - var e = (r = _.__c).__H; - e && (e.__h.forEach(s), e.__h.forEach(p), e.__h = []); -}, ge.diffed = function(_) { - y && y(_); - var e = _.__c; - e && e.__H && e.__H.__h.length && (m.push(e) !== 1 && H1 === ge.requestAnimationFrame || ((H1 = ge.requestAnimationFrame) || function(n) { - var t, o = function() { - clearTimeout(f), F1 && cancelAnimationFrame(t), setTimeout(n); - }, f = setTimeout(o, 100); - F1 && (t = requestAnimationFrame(o)); - })(M1)), r = void 0; -}, ge.__c = function(_, e) { - e.some(function(n) { - try { - n.__h.forEach(s), n.__h = n.__h.filter(function(t) { - return !t.__ || p(t); - }); - } catch (t) { - e.some(function(o) { - o.__h && (o.__h = []); - }), e = [], ge.__e(t, n.__v); - } - }), b1 && b1(_, e); -}, ge.unmount = function(_) { - g && g(_); - var e = _.__c; - if (e && e.__H) try { - e.__H.__.forEach(s); - } catch (n) { - ge.__e(n, e.__v); - } -}; -var F1 = typeof requestAnimationFrame == "function"; -function s(_) { - var e = r; - typeof _.__c == "function" && _.__c(), r = e; -} -function p(_) { - var e = r; - _.__c = _.__(), r = e; -} -function v(_, e) { - return !_ || _.length !== e.length || e.some(function(n, t) { - return n !== _[t]; - }); -} -function A(_, e) { - return typeof e == "function" ? e(_) : e; -} -var { useRef: z1 , useMemo: G1 , useDebugValue: J1 , useErrorBoundary: K1 , useReducer: N1 , useLayoutEffect: O1 , useImperativeHandle: Q1 , useEffect: U1 , useCallback: W1 , useContext: X1 , useState: Y1 } = h1; -var a1 = function(p, o, l, n) { - var v; - o[0] = 0; - for(var u = 1; u < o.length; u++){ - var f = o[u++], t = o[u] ? (o[0] |= f ? 1 : 2, l[o[u++]]) : o[++u]; - f === 3 ? n[0] = t : f === 4 ? n[1] = Object.assign(n[1] || { - }, t) : f === 5 ? (n[1] = n[1] || { - })[o[++u]] = t : f === 6 ? n[1][o[++u]] += t + "" : f ? (v = p.apply(t, a1(p, t, l, [ - "", - null - ])), n.push(v), t[0] ? o[0] |= 2 : (o[u - 2] = 0, o[u] = v)) : n.push(t); - } - return n; -}, d2 = new Map; -function w(p) { - var o = d2.get(this); - return o || (o = new Map, d2.set(this, o)), (o = a1(this, o.get(p) || (o.set(p, o = function(l) { - for(var n, v, u = 1, f = "", t = "", g = [ - 0 - ], c = function(i) { - u === 1 && (i || (f = f.replace(/^\s*\n\s*|\s*\n\s*$/g, ""))) ? g.push(0, i, f) : u === 3 && (i || f) ? (g.push(3, i, f), u = 2) : u === 2 && f === "..." && i ? g.push(4, i, 0) : u === 2 && f && !i ? g.push(5, 0, !0, f) : u >= 5 && ((f || !i && u === 5) && (g.push(u, 0, f, v), u = 6), i && (g.push(u, i, 0, v), u = 6)), f = ""; - }, s = 0; s < l.length; s++){ - s && (u === 1 && c(), c(s)); - for(var m = 0; m < l[s].length; m++)n = l[s][m], u === 1 ? n === "<" ? (c(), g = [ - g - ], u = 3) : f += n : u === 4 ? f === "--" && n === ">" ? (u = 1, f = "") : f = n + f[0] : t ? n === t ? t = "" : f += n : n === '"' || n === "'" ? t = n : n === ">" ? (c(), u = 1) : u && (n === "=" ? (u = 5, v = f, f = "") : n === "/" && (u < 5 || l[s][m + 1] === ">") ? (c(), u === 3 && (g = g[0]), u = g, (g = g[0]).push(2, 0, u), u = 0) : n === " " || n === " " || n === ` -` || n === "\r" ? (c(), u = 2) : f += n), u === 3 && f === "!--" && (u = 4, g = g[0]); - } - return c(), g; - }(p)), o), arguments, [])).length > 1 ? o : o[0]; -} -const html1 = w.bind(ye); -export { html1 as html, xe as render, Ce as Component, U1 as useEffect, O1 as useLayoutEffect, Y1 as useState, z1 as useRef, G1 as useMemo, W1 as useCallback, me as createContext, ke as createRef, X1 as useContext, ye as h, ue as cloneElement, he as hydrate, }; diff --git a/frontend/imports/Preact.original.js b/frontend/imports/Preact.original.js deleted file mode 100644 index da4dad275a..0000000000 --- a/frontend/imports/Preact.original.js +++ /dev/null @@ -1,45 +0,0 @@ -// @ts-nocheck -import { - // - render, - Component, - h, - cloneElement, - createContext, - createRef, - hydrate, - createRef, -} from "https://esm.sh/preact@10.5.13?target=es2020" -import { - // - useEffect, - useLayoutEffect, - useState, - useRef, - useMemo, - useCallback, - useContext, -} from "https://esm.sh/preact@10.5.13/hooks?target=es2020" - -import htm from "https://esm.sh/htm@3.0.4?target=es2020" - -const html = htm.bind(h) - -export { - // - html, - render, - Component, - useEffect, - useLayoutEffect, - useState, - useRef, - useMemo, - useCallback, - createContext, - createRef, - useContext, - h, - cloneElement, - hydrate, -} diff --git a/frontend/imports/bundle.sh b/frontend/imports/bundle.sh deleted file mode 100755 index 2dffc71c2e..0000000000 --- a/frontend/imports/bundle.sh +++ /dev/null @@ -1 +0,0 @@ -deno bundle Preact.original.js Preact.js diff --git a/frontend/imports/highlightjs.js b/frontend/imports/highlightjs.js index 15fd1190ff..f10ca1e001 100644 --- a/frontend/imports/highlightjs.js +++ b/frontend/imports/highlightjs.js @@ -1,13 +1,15 @@ // @ts-ignore -import hljs from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/es/highlight.min.js" +import hljs from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/es/highlight.min.js" // @ts-ignore -import hljs_julia from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/es/languages/julia.min.js" +import hljs_julia from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/es/languages/julia.min.js" // @ts-ignore -import hljs_juliarepl from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/es/languages/julia-repl.min.js" +import hljs_juliarepl from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/es/languages/julia-repl.min.js" hljs.registerLanguage("julia", hljs_julia) hljs.registerLanguage("julia-repl", hljs_juliarepl) -// https://github.com/highlightjs/highlight.js/pull/3432 -hljs.registerAliases(["jldoctest"], { languageName: "julia-repl" }) + +// Attach the highlighter object to the window to allow custom highlighting from the frontend. See https://github.com/fonsp/Pluto.jl/pull/2244 +//@ts-ignore +window.hljs = hljs export default hljs diff --git a/frontend/imports/immer.d.ts b/frontend/imports/immer.d.ts index 479635f1f4..35884f8800 100644 --- a/frontend/imports/immer.d.ts +++ b/frontend/imports/immer.d.ts @@ -1,6 +1,6 @@ export type Patch = { path: Array - op: "add" | "replace" + op: "add" | "replace" | "remove" value: any } diff --git a/frontend/imports/lodash.d.ts b/frontend/imports/lodash.d.ts new file mode 100644 index 0000000000..de0d3a58f4 --- /dev/null +++ b/frontend/imports/lodash.d.ts @@ -0,0 +1,2 @@ +import _ from "lodash-es" +export default _ diff --git a/frontend/index.css b/frontend/index.css index e82c80d106..562862c38a 100644 --- a/frontend/index.css +++ b/frontend/index.css @@ -4,48 +4,38 @@ @import url("vollkorn.css"); @import url("juliamono.css"); +@import url("light_color.css"); +@import url("dark_color.css"); + +@import url("featured-card.css"); + * { box-sizing: border-box; } - -#title { - /* position: absolute; */ - /* left: 0; */ - /* right: 0; */ - margin-top: 34vh; - /* bottom: 0; */ - /* margin: auto; */ - display: block; - width: 100%; - text-align: center; +html { + font-size: 17px; } -body.error #title { - margin-top: 10vh; - /* text-align: left; */ -} - -#title h1, -#title h2 { +#title h1 { font-style: italic; font-size: 2em; letter-spacing: 0.08em; font-weight: 500; font-family: "Vollkorn", serif; - color: hsl(0, 0%, 26%); + color: var(--pluto-output-h-color); margin: 0px; - border-bottom: solid 2px hsl(0, 0%, 88%); -} - -#title h2 { - font-size: 1.4em; + padding: 4rem 1rem 3rem 1rem; + /* flex: 1 1 auto; */ /* max-width: 920px; */ + text-align: center; } -#title img { +#title h1 img { height: 1.2em; + width: 4.9em; margin-bottom: -0.27em; /* margin-right: -1.5em; */ margin-left: 0.1em; + filter: var(--image-filters); } body { @@ -53,43 +43,28 @@ body { position: absolute; width: 100%; min-height: 100%; - background: white; -} - -main { - width: 15em; - margin: 0 auto; - margin-top: 20vh; - text-align: left; - font-family: "Roboto Mono", monospace; - color: hsl(0, 0%, 60%); -} - -body.error main { - width: unset; - max-width: 40em; - padding: 0.5em; - margin-top: 5vh; - font-size: 14px; + background: var(--main-bg-color); } p { - color: hsl(0, 0%, 30%); + color: var(--index-text-color); } ul { - padding-left: 0.5em; + padding-left: 0; list-style: none; } li { white-space: nowrap; - margin-bottom: 0.9em; + padding: 0.4em; + border-bottom: 1px solid var(--welcome-recentnotebook-border); } a { color: inherit; - color: hsl(0, 0%, 30%); + + color: var(--index-clickable-text-color); } /* input { @@ -105,7 +80,14 @@ a { pluto-filepicker { display: flex; flex-direction: row; - margin-top: 0.3rem; + /* margin-top: 0.3rem; */ + background: var(--white); +} + +.desktop_picker { + display: flex; + flex-direction: row; + margin-left: 5px; } pluto-filepicker .cm-editor { @@ -114,16 +96,19 @@ pluto-filepicker .cm-editor { width: 100%; font-style: normal; font-weight: 500; - font-family: "Roboto Mono", monospace; + font-family: var(--inter-ui-font-stack); font-size: 0.75rem; letter-spacing: 1px; background: none; - color: #6f6f6f; - border: 2px solid #b2b2b2; + color: var(--nav-filepicker-color); + border: 2px solid var(--footer-filepicker-focus-color); border-radius: 3px; border-right: none; border-top-right-radius: 0; border-bottom-right-radius: 0; + flex: 1 1 auto; + width: 0px; + /* min-width: 0px; */ } pluto-filepicker .cm-scroller { @@ -133,36 +118,62 @@ pluto-filepicker .cm-scroller::-webkit-scrollbar { display: none; /* Safari and Chrome */ } -pluto-filepicker button { +pluto-filepicker button, +.desktop_picker button { margin: 0px; - background: #6c8489; + background: var(--footer-filepicker-focus-color); border-radius: 3px; - border: 2px solid #6c8489; - color: white; + border: 2px solid var(--nav-filepicker-focus-color); + color: var(--white); /* border: none; */ font-family: "Roboto Mono", monospace; font-weight: 600; font-size: 0.75rem; } +.desktop_picker_group { + display: inline-flex; +} + +.desktop_picker_group > input { + margin-left: 1em; +} + +.desktop_picker > button { + cursor: pointer; +} + +.desktop_picker > button.full_width { + width: 100%; +} + pluto-filepicker button { cursor: pointer; border-top-left-radius: 0; border-bottom-left-radius: 0; + flex: 0 1 auto; +} + +pluto-filepicker button:disabled { + cursor: not-allowed; + opacity: 0.7; } .cm-editor .cm-tooltip { - border: 1px solid rgba(0, 0, 0, 0.2); + border: 1px solid var(--cm-editor-tooltip-border-color); box-shadow: 3px 3px 4px rgb(0 0 0 / 20%); border-radius: 4px; } .cm-tooltip-autocomplete { - max-height: calc(20 * 16px); box-sizing: content-box; z-index: 100; } +.cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul { + max-height: max(3em, min(50dvh, 20em)); +} + .cm-tooltip.cm-completionInfo.cm-completionInfo-right:empty { /* https://github.com/codemirror/codemirror.next/issues/574 */ display: none; @@ -170,22 +181,21 @@ pluto-filepicker button { .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li { /* this is the line height rounded to an integer to prevent jiggle */ - height: 16px; + height: 18px; + overflow-y: hidden; /* font-size: 16px; */ - line-height: 16px; + /* line-height: 16px; */ border-radius: 3px; margin-bottom: unset; } .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] { - color: white; - background: #16659d; + color: var(--cm-editor-li-aria-selected-color); + background: var(--cm-editor-li-aria-selected-bg-color); } .cm-editor .cm-completionIcon { - opacity: 1; - width: 1em; - transform: translateY(-1.5px); + display: none; } .cm-completionIcon::before { @@ -198,7 +208,7 @@ pluto-filepicker button { .cm-tooltip.cm-tooltip-autocomplete { padding: 0; margin-left: -1.5em; - background: white; + background: var(--autocomplete-menu-bg-color); } .cm-tooltip-autocomplete li.file.new:before { @@ -218,9 +228,10 @@ pluto-filepicker button { } .cm-editor .cm-tooltip-autocomplete .cm-completionLabel { - font-family: JuliaMono, monospace !important; + font-family: var(--inter-ui-font-stack); + font-weight: 400; font-variant-ligatures: none; - font-size: 0.75rem; + font-size: 0.8rem; } body.nosessions ul#new ~ * { @@ -228,7 +239,14 @@ body.nosessions ul#new ~ * { } #recent { - margin-bottom: 8em; + scrollbar-gutter: stable; + background: var(--welcome-recentnotebook-bg); /* margin-bottom: 8em; */ + max-height: 16em; + overflow-y: auto; + overflow-x: hidden; + border-radius: 0.4rem; + box-shadow: -2px 4px 9px 0px #00000012; + border: 0.2rem solid #d5d5d5; } #recent > li.recent { @@ -244,16 +262,17 @@ body.nosessions ul#new ~ * { background: none; cursor: pointer; /* color: hsl(204, 86%, 35%); */ - color: black; + color: var(--ui-button-color); } -#recent button > span::after { - display: block; +span.ionicon::after { + display: inline-block; content: " "; - background-size: 17px 17px; - height: 17px; - width: 17px; - margin-bottom: -3px; + background-size: 1rem 1rem; + height: 1rem; + width: 1rem; + margin-bottom: -0.17rem; + filter: var(--image-filters); } #recent li.running button > span::after { @@ -268,10 +287,14 @@ body.nosessions ul#new ~ * { background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/ellipsis-horizontal-outline.svg"); } +#recent li.new span::after { + background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/add-outline.svg"); +} + loading-bar { height: 6px; width: 100vw; - background-color: #b1c9dd; + background-color: var(--loading-grad-color-1); position: fixed; top: 0px; display: none; @@ -294,3 +317,27 @@ body.loading loading-bar { right: 0vw; } } + +.card-list { + display: grid; + /* grid-auto-columns: 50px; */ + place-items: center; + align-items: stretch; + grid-template-columns: repeat(auto-fit, minmax(var(--card-width), 1fr)); + gap: 0rem; + justify-items: stretch; +} + +.navigating-away-banner { + width: 100vw; + min-height: 70vh; + place-content: center; + display: grid; + padding: 3em; +} + +.navigating-away-banner h2 { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} diff --git a/frontend/index.html b/frontend/index.html index 5710112c8c..0c235dc91b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,47 +3,72 @@ - ⚡ Pluto.jl ⚡ - + + + + Pluto.jl - + + + + + + - - - - + + + + + + + + + - + -

-

welcome to

-
-

New session:

-
-
+
+
+

welcome to

+
+
+
+

My work

+ +
+
+
+
+

Open a notebook

+

Loading...

+
+
+
diff --git a/frontend/index.js b/frontend/index.js index aef83726c1..fc485b3e05 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -1,6 +1,33 @@ import { html, render } from "./imports/Preact.js" import "./common/NodejsCompatibilityPolyfill.js" -import { Welcome } from "./components/Welcome.js" +import { Welcome } from "./components/welcome/Welcome.js" -render(html`<${Welcome} />`, document.querySelector("main")) +const url_params = new URLSearchParams(window.location.search) + +/** + * + * @type {import("./components/welcome/Welcome.js").LaunchParameters} + */ +const launch_params = { + //@ts-ignore + featured_direct_html_links: !!(url_params.get("featured_direct_html_links") ?? window.pluto_featured_direct_html_links), + + //@ts-ignore + featured_sources: window.pluto_featured_sources, + + // Setting the featured_sources object is preferred, but you can also specify a single featured source using the URL (and integrity), which also supports being set as a URL parameter. + + //@ts-ignore + featured_source_url: url_params.get("featured_source_url") ?? window.pluto_featured_source_url, + //@ts-ignore + featured_source_integrity: url_params.get("featured_source_integrity") ?? window.pluto_featured_source_integrity, + + //@ts-ignore + pluto_server_url: url_params.get("pluto_server_url") ?? window.pluto_server_url, +} + +console.log("Launch parameters: ", launch_params) + +// @ts-ignore +render(html`<${Welcome} launch_params=${launch_params} />`, document.querySelector("#app")) diff --git a/frontend/juliamono.css b/frontend/juliamono.css index 33535553c7..cd3d10d465 100644 --- a/frontend/juliamono.css +++ b/frontend/juliamono.css @@ -1,6 +1,6 @@ @font-face { font-family: JuliaMono; - src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.043/webfonts/JuliaMono-RegularLatin.woff2") format("woff2"); + src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.047/webfonts/JuliaMono-RegularLatin.woff2") format("woff2"); font-display: swap; font-weight: 400; unicode-range: U+00-7F; /* Basic Latin characters */ @@ -8,7 +8,7 @@ @font-face { font-family: JuliaMono; - src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.043/webfonts/JuliaMono-BoldLatin.woff2") format("woff2"); + src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.047/webfonts/JuliaMono-BoldLatin.woff2") format("woff2"); font-display: swap; font-weight: 700; unicode-range: U+00-7F; /* Basic Latin characters */ @@ -16,21 +16,21 @@ @font-face { font-family: JuliaMono; - src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.043/webfonts/JuliaMono-Regular.woff2") format("woff2"); + src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.047/webfonts/JuliaMono-Regular.woff2") format("woff2"); font-display: swap; font-weight: 400; } @font-face { font-family: JuliaMono; - src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.043/webfonts/JuliaMono-Bold.woff2") format("woff2"); + src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.047/webfonts/JuliaMono-Bold.woff2") format("woff2"); font-display: swap; font-weight: 700; } @font-face { font-family: JuliaMono; - src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.043/webfonts/JuliaMono-RegularItalic.woff2") format("woff2"); + src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono@0.047/webfonts/JuliaMono-RegularItalic.woff2") format("woff2"); font-display: swap; font-weight: 400; font-style: italic; diff --git a/frontend/light_color.css b/frontend/light_color.css new file mode 100644 index 0000000000..c2c59224d5 --- /dev/null +++ b/frontend/light_color.css @@ -0,0 +1,238 @@ +@media (prefers-color-scheme: light) { + :root { + --image-filters: none; + --out-of-focus-opacity: 0.25; + + /* Color scheme */ + --main-bg-color: white; + --rule-color: rgba(0, 0, 0, 0.15); + --kbd-border-color: #dfdfdf; + --header-bg-color: white; + --header-border-color: rgba(0, 0, 0, 0.1); + --ui-button-color: #2a2a2b; + --cursor-color: black; + --normal-cell: 0, 0, 0; + --code-differs: 160, 130, 28; + --error-color: 240, 168, 168; + + /*Cells*/ + --normal-cell-color: rgba(var(--normal-cell), 0.1); + --dark-normal-cell-color: rgba(var(--normal-cell), 0.2); + --selected-cell-color: rgba(40, 78, 189, 0.4); + --code-differs-cell-color: rgba(var(--code-differs), 0.68); + --error-cell-color: rgba(var(--error-color), 0.7); + --bright-error-cell-color: rgb(var(--error-color)); + --light-error-cell-color: rgba(var(--error-color), 0.05); + + /*Export styling*/ + --export-bg-color: rgb(60, 67, 101); + --export-color: rgb(228, 228, 228); + --export-card-bg-color: rgba(255, 255, 255, 0.8); + --export-card-title-color: rgba(0, 0, 0, 0.7); + --export-card-text-color: rgba(0, 0, 0, 0.5); + --export-card-shadow-color: #00000029; + + /*Frontmatter styling*/ + --frontmatter-button-bg-color: white; + --frontmatter-outline-color: hsl(230, 14%, 11%); + --frontmatter-input-bg-color: #fbfbfb; + --frontmatter-input-border-color: hsl(207deg 24% 87%); + + /*Pluto output styling */ + --pluto-schema-types-color: rgba(0, 0, 0, 0.4); + --pluto-schema-types-border-color: rgba(0, 0, 0, 0.2); + --pluto-output-color: hsl(0, 0%, 25%); + --pluto-output-h-color: hsl(0, 0%, 12%); + --pluto-output-bg-color: white; + --a-underline: #00000059; + --blockquote-color: #555; + --blockquote-bg: #f2f2f2; + --admonition-title-color: white; + --jl-message-color: rgb(219 233 212); + --jl-message-accent-color: rgb(158, 200, 137); + --jl-info-color: rgb(214 227 244); + --jl-info-accent-color: rgb(148, 182, 226); + --jl-warn-color: rgb(236 234 213); + --jl-warn-accent-color: rgb(207, 199, 138); + --jl-danger-color: rgb(245 218 215); + --jl-danger-accent-color: rgb(226, 157, 148); + --jl-debug-color: rgb(245 218 215); + --jl-debug-accent-color: rgb(226, 157, 148); + --footnote-border-color: rgba(23, 115, 119, 0.15); + --table-border-color: rgba(0, 0, 0, 0.2); + --table-bg-hover-color: rgba(159, 158, 224, 0.15); + --pluto-tree-color: rgb(0 0 0 / 38%); + + /*pluto cell styling*/ + --disabled-cell-bg-color: rgba(139, 139, 139, 0.25); + --selected-cell-bg-color: rgba(40, 78, 189, 0.24); + --hover-scrollbar-color-1: rgba(0, 0, 0, 0.15); + --hover-scrollbar-color-2: rgba(0, 0, 0, 0.05); + --skip-as-script-background-color: #ccc; + --depends-on-skip-as-script-background-color: #eee; + + /* Pluto shoulders */ + --shoulder-hover-bg-color: rgba(0, 0, 0, 0.05); + + /* Logs */ + --pluto-logs-bg-color: hsl(0deg 0% 98%); + --pluto-logs-key-color: rgb(0 0 0 / 51%); + --pluto-logs-progress-fill: #ffffff; + --pluto-logs-progress-bg: #e7e7e7; + --pluto-logs-progress-border: hsl(210deg 16% 74%); + + --pluto-logs-info-color: white; + --pluto-logs-info-accent-color: inherit; + --pluto-logs-warn-color: rgb(236 234 213); + --pluto-logs-warn-accent-color: #665f26; + --pluto-logs-danger-color: rgb(245 218 215); + --pluto-logs-danger-accent-color: rgb(172 66 52); + --pluto-logs-debug-color: rgb(236 223 247); + --pluto-logs-debug-accent-color: rgb(100 50 179); + + /*Top navbar styling*/ + --nav-h1-text-color: black; + --nav-filepicker-color: #6f6f6f; + --nav-filepicker-border-color: #b2b2b2; + --nav-process-status-bg-color: white; + --nav-process-status-color: var(--pluto-output-h-color); + + /*header*/ + --restart-recc-header-color: rgba(114, 192, 255, 0.56); + --restart-recc-accent-color: rgba(114, 192, 255); + --restart-req-header-color: rgba(170, 41, 32, 0.56); + --dead-process-header-color: rgb(230 88 46 / 38%); + --loading-header-color: hsla(290, 10%, 80%, 0.5); + --disconnected-header-color: rgba(255, 169, 114, 0.56); + --binder-loading-header-color: hsl(51deg 64% 90% / 50%); + + /*loading bar*/ + --loading-grad-color-1: #f1dba9; + --loading-grad-color-2: #d7d7d0; + + /*saveall container*/ + --overlay-button-bg: #ffffff; + --overlay-button-border: hsl(0 4% 91% / 1); + --overlay-button-border-save: #f3f2f2; + + /*input_context_menu*/ + --input-context-menu-border-color: rgba(0, 0, 0, 0.1); + --input-context-menu-bg-color: white; + --input-context-menu-soon-color: #55555544; + --input-context-menu-hover-bg-color: rgba(0, 0, 0, 0.1); + --input-context-menu-li-color: #6b6a6a; + + /*Pkg status*/ + --pkg-popup-bg: white; + --pkg-popup-border-color: #f0e4ee; + --pkg-popup-buttons-bg-color: white; + --black: black; + --white: white; + --pkg-terminal-bg-color: #232433; + --pkg-terminal-border-color: #c3c3c3; + + /* run area*/ + --pluto-runarea-bg-color: hsl(0, 0, 97%); + --pluto-runarea-span-color: hsl(353, 5%, 64%); + + /*drop ruler*/ + --dropruler-bg-color: rgba(0, 0, 0, 0.5); + + /* jlerror */ + --jlerror-header-color: #4f1616; + --jlerror-mark-bg-color: rgb(243 243 243); + --jlerror-a-bg-color: #f5efd9; + --jlerror-a-border-left-color: #704141; + --jlerror-mark-color: black; + + /* helpbox */ + --helpbox-bg-color: white; + --helpbox-box-shadow-color: #00000010; + --helpbox-header-bg-color: hsl(0deg 0% 92%); + --helpbox-header-tab-bg-color: white; + --helpbox-header-color: hsl(230, 14%, 11%); + --helpbox-search-bg-color: #fbfbfb; + --helpbox-search-border-color: hsl(207deg 24% 87%); + --helpbox-notfound-search-color: rgb(139, 139, 139); + --helpbox-text-color: black; + --code-section-bg-color: whitesmoke; + --code-section-bg-color: #f3f3f3; + + --process-item-bg: #f2f2f2; + --process-busy: #ffcd70; + --process-finished: hsl(126deg 30% 60%); + --process-undefined: rgb(151, 151, 151); + --process-notify-bg: hsl(44.86deg 50% 94%); + + /*footer*/ + --footer-color: #333333; + --footer-bg-color: #d7dcd3; + --footer-atag-color: black; + --footer-input-border-color: #818181; + --footer-filepicker-button-color: white; + --footer-filepicker-focus-color: #896c6c; + --footnote-border-color: rgba(23, 115, 119, 0.15); + + /* undo delete cell*/ + --undo-delete-box-shadow-color: #0083; + + /*codemirror hints*/ + --cm-editor-tooltip-border-color: rgba(0, 0, 0, 0.2); + --cm-editor-li-aria-selected-bg-color: #16659d; + --cm-editor-li-aria-selected-color: white; + --cm-editor-li-notexported-color: rgba(0, 0, 0, 0.5); + --code-background: hsla(46, 90%, 98%, 1); + --cm-code-differs-gutters-color: rgba(214, 172, 35, 0.2); + --cm-line-numbers-color: #8d86875e; + --cm-selection-background: hsl(214deg 100% 73% / 48%); + --cm-selection-background-blurred: hsl(214deg 0% 73% / 48%); + + /* code highlighting */ + --cm-editor-text-color: #41323f; + --cm-comment-color: #e96ba8; + --cm-atom-color: #815ba4; + --cm-number-color: #815ba4; + --cm-property-color: #b67a48; + --cm-keyword-color: #ef6155; + --cm-string-color: #da5616; + --cm-var-color: #5668a4; + --cm-macro-color: #5c8c5f; + --cm-var2-color: #37768a; + --cm-builtin-color: #5e7ad3; + --cm-function-color: #cc80ac; + --cm-type-color: hsl(170deg 7% 56%); + --cm-bracket-color: #41323f; + --cm-tag-color: #ef6155; + --cm-link-color: #815ba4; + --cm-error-bg-color: #ef6155; + --cm-error-color: #f7f7f7; + --cm-matchingBracket-color: black; + --cm-matchingBracket-bg-color: #1b4bbb21; + --cm-placeholder-text-color: rgba(0, 0, 0, 0.2); + + /*autocomplete menu*/ + --autocomplete-menu-bg-color: white; + + /* Landing colors */ + --index-text-color: hsl(0, 0, 60); + --index-light-text-color: #838383; + --index-clickable-text-color: hsl(0, 0, 30); + --docs-binding-bg: #8383830a; + --index-card-bg: white; + --welcome-mywork-bg: hsl(35deg 66% 93%); + --welcome-newnotebook-bg: whitesmoke; + --welcome-recentnotebook-bg: white; + --welcome-recentnotebook-border: #dfdfdf; + --welcome-open-bg: #fbfbfb; + --welcome-card-author-backdrop: #ffffffb0; + + /* HTML in codemirror! */ + --cm-html-color: #48b685; + --cm-html-accent-color: #00ab85; + --cm-css-color: #876800; + --cm-css-accent-color: #696200; + --cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa: #3b3700; + --cm-md-color: #005a9b; + --cm-md-accent-color: #00a9d1; + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000000..6191135789 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6" + } +} diff --git a/frontend/sample.html b/frontend/sample.html deleted file mode 100644 index faf7ca189d..0000000000 --- a/frontend/sample.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - ⚡ Pluto.jl ⚡ - - - - - - - - - - - - - - -
-

welcome to

-
-

Samples:

- -
-
-
- - - \ No newline at end of file diff --git a/frontend/sw.js b/frontend/sw.js deleted file mode 100644 index 30d90d2eb7..0000000000 --- a/frontend/sw.js +++ /dev/null @@ -1,67 +0,0 @@ -// mostly based on https://developers.google.com/web/fundamentals/primers/service-workers - -const DEBUG = false -const noop = () => {} -const logger = { - log: DEBUG ? console.log : noop, - warn: DEBUG ? console.warn : noop, - info: DEBUG ? console.info : noop, -} -var CACHE_NAME = "pluto-cache-v2" - -self.addEventListener("install", (event) => { - logger.log("Hello from service worker 👋") - // Perform install steps - event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - logger.log("Opened cache") - }) - ) -}) - -const allowList = ["www.gstatic.com", "fonts.gstatic.com", "fonts.googleapis.com", "cdn.jsdelivr.net", "cdnjs.cloudflare.com", "unpkg.com"] - -function shouldCache(request) { - const url = new URL(request.url) - return request.method === "GET" && allowList.includes(url.host) && !url.toString().includes("skip_sw") -} - -self.addEventListener("fetch", (event) => { - // if (navigator.userAgent.includes("Firefox")) { - // return - // } - if (!shouldCache(event.request)) { - logger.log("skipping cache") - return - } - event.respondWith( - caches.open(CACHE_NAME).then((cache) => - cache.match(event.request).then((response) => { - if (response != null) { - logger.info("CACHE HIT", event.request) - return response - } else { - logger.warn("Cache miss", event.request.url) - - return fetch(event.request).then(function (response) { - // Check if we received a valid response - if (!response || response.status !== 200) { - return response - } else { - logger.warn("FETCHED") - - // Clone the response. A response is a stream - // and because we want the browser to consume the response - // as well as the cache consuming the response, we need - // to clone it so we have two streams. - var responseToCache = response.clone() - cache.put(event.request, responseToCache) - - return response - } - }) - } - }) - ) - ) -}) diff --git a/frontend/treeview.css b/frontend/treeview.css index 1059ecedec..ce4e3aa023 100644 --- a/frontend/treeview.css +++ b/frontend/treeview.css @@ -8,11 +8,11 @@ pluto-tree, pluto-tree-pair { - font-family: JuliaMono, monospace; + font-family: var(--julia-mono-font-stack); font-size: 0.75rem; } pluto-tree { - color: hsl(0, 0%, 25%, 0.7); + color: var(--pluto-tree-color); white-space: pre; cursor: pointer; } @@ -21,12 +21,13 @@ pluto-tree, pluto-tree-items { display: inline-flex; flex-direction: column; - align-items: baseline; + align-items: flex-start; } pluto-tree.collapsed, pluto-tree.collapsed pluto-tree, pluto-tree.collapsed pluto-tree-items { flex-direction: row; + align-items: baseline; } pluto-tree-items { @@ -50,6 +51,7 @@ pluto-tree > pluto-tree-prefix::before { opacity: 0.5; cursor: pointer; background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/caret-down-outline.svg"); + filter: var(--image-filters); } pluto-tree.collapsed pluto-tree > pluto-tree-prefix::before { @@ -62,7 +64,7 @@ pluto-tree.collapsed > pluto-tree-prefix::before { pluto-tree p-r > p-v { display: inline-flex; - color: hsl(0, 0%, 25%, 1); + color: var(--pluto-output-color); } pluto-tree.collapsed pluto-tree-items.Array > p-r > p-k, @@ -184,6 +186,7 @@ pluto-tree-more::before { height: 1em; width: 1em; opacity: 0.5; + filter: var(--image-filters); background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/ellipsis-vertical.svg"); } @@ -242,7 +245,7 @@ jlerror { } jlerror > header { - color: #330000; + color: var(--jlerror-header-color); } jlerror > header > p { margin-block-end: 0.2em; @@ -251,17 +254,18 @@ jlerror > header > p:first-child { font-weight: bold; } jlerror > section > ol > li > mark { - background: #f3f2f1; + background: var(--jlerror-mark-bg-color); border-radius: 6px; - font-family: JuliaMono, monospace; + color: var(--jlerror-mark-color); + font-family: var(--julia-mono-font-stack); font-variant-ligatures: none; } jlerror > section > ol > li > em > a { - background: #f5efd9; + background: var(--jlerror-a-bg-color); border-radius: 4px; padding: 1px 7px; text-decoration: none; - border-left: 3px solid #9a7575; + border-left: 3px solid var(--jlerror-a-border-left-color); } jlerror > section > ol > li > span { opacity: 0.8; @@ -274,19 +278,19 @@ table.pluto-table { table.pluto-table td { max-width: 300px; - overflow: hidden; + overflow: auto; } table.pluto-table .schema-types { - color: rgba(0, 0, 0, 0.4); - font-family: "JuliaMono", monospace; + color: var(--pluto-schema-types-color); + font-family: var(--julia-mono-font-stack); font-size: 0.75rem; opacity: 0; } table.pluto-table .schema-types th { - border-bottom: 1px solid rgba(0, 0, 0, 0.2); - background-color: white; + border-bottom: 1px solid var(--pluto-schema-types-border-color); + background-color: var(--main-bg-color); height: 2rem; } @@ -306,7 +310,7 @@ table.pluto-table .schema-types th:first-child { table.pluto-table .schema-names th, table.pluto-table .schema-types th:first-child { - background-color: white; + background-color: var(--main-bg-color); position: sticky; top: calc(0.25rem - var(--pluto-cell-spacing)); height: 2rem; @@ -318,7 +322,7 @@ table.pluto-table thead:hover .schema-names th { } table.pluto-table tbody th:first-child { - background-color: white; + background-color: var(--main-bg-color); position: sticky; left: -10px; /* padding-left of pluto-output*/ } @@ -335,3 +339,20 @@ table.pluto-table .pluto-tree-more-td pluto-tree-more { top: 2rem; max-width: 650px; } + +table.pluto-table tr.empty div { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + font-size: 1.5rem; + flex-flow: column nowrap; +} +table.pluto-table tr.empty small { + font-size: 0.5rem; +} + +pluto-tree.collapsed p-v > pre { + max-height: 2em; + overflow-y: hidden; +} diff --git a/frontend/warn_old_browsers.js b/frontend/warn_old_browsers.js index 0cf3f484b8..cce168f5bf 100644 --- a/frontend/warn_old_browsers.js +++ b/frontend/warn_old_browsers.js @@ -1,13 +1,22 @@ -function ismodern(){ - try{ - return eval("let {a, ...r} = {a:1,b:1}; r?.a != r.b; 1 ?? 2") - } catch(ex) { +function ismodern() { + try { + // See: https://kangax.github.io/compat-table/es2016plus/ + + // 2020 check: + // return eval("let {a, ...r} = {a:1,b:1}; r?.a != r.b; 1 ?? 2") + // 2021 check: + // return eval("let {a, ...r} = {a:1,b:1}; r?.a != r.b; 1 ?? 2; a ||= false") + // 2021 check (Chrome 85+, Firefox 77+, Safari 13.1+) + // Please check with macs + return Boolean(String.prototype.replaceAll) + } catch (ex) { return false } } -window.addEventListener("DOMContentLoaded", function(){ - if(!ismodern()){ - document.body.innerHTML = "

You need a shiny new browser to use Pluto!

The latest versions of Firefox and Chrome will work best.

" +window.addEventListener("DOMContentLoaded", function () { + if (!ismodern()) { + document.body.innerHTML = + "

You need a shiny new browser to use Pluto!

The latest versions of Firefox and Chrome will work best.

" } -}) \ No newline at end of file +}) diff --git a/frontend/welcome.css b/frontend/welcome.css new file mode 100644 index 0000000000..c1e76db4f2 --- /dev/null +++ b/frontend/welcome.css @@ -0,0 +1,251 @@ +@import url("https://cdn.jsdelivr.net/npm/inter-ui@3.19.3/inter-latin.css"); + +:root { + --pluto-cell-spacing: 17px; + /* use the value "contextual" to enable contextual ligatures `document.documentElement.style.setProperty('--pluto-operator-ligatures', 'contextual');` + for julia mono see here: https://cormullion.github.io/pages/2020-07-26-JuliaMono/#contextual_and_stylistic_alternates_and_ligatures */ + --pluto-operator-ligatures: none; + --julia-mono-font-stack: JuliaMono, Menlo, "Roboto Mono", "Lucida Sans Typewriter", "Source Code Pro", monospace; + --sans-serif-font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + --lato-ui-font-stack: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Helvetica, Arial, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", system-ui, sans-serif; + --inter-ui-font-stack: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Helvetica, Arial, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", system-ui, sans-serif; + + color-scheme: light dark; +} + +html { + font-family: var(--inter-ui-font-stack); + font-size: 17px; +} + +main { + display: block; + max-width: 1200px; + padding: 1rem; + margin: 0 auto; +} +/* font-size: 1.7em; */ + +header { + background-color: #f5efd2; /* background-image: linear-gradient(to top, white, #fff0), var(--noise-4); */ + /* filter: var(--noise-filter-1); */ + display: flex; + background-size: cover; + justify-content: center; + padding: 1.3rem; +} +header h1 { + font-weight: 500; + + /* font-style: italic; */ + text-align: center; + /* color: white; */ +} + +section#mywork, +section#open { + /* --c1: rgb(255 255 255 / 20%); */ + /* --c2: rgb(255 255 255 / 7%); */ + /* background-color: #92add9; */ + /* --grad-stops: transparent 9%, var(--c1) 10%, var(--c1) 12%, transparent 13%, transparent 29%, var(--c2) 30%, var(--c2) 31%, transparent 32%, transparent 49%, + var(--c2) 50%, var(--c2) 51%, transparent 52%, transparent 69%, var(--c2) 70%, var(--c2) 71%, transparent 72%, transparent 89%, var(--c2) 90%, + var(--c2) 91%, transparent 92%, transparent; */ + /* background-size: 40px 40px; */ + /* background-position: 20px 20px; */ + /* background-image: linear-gradient(360deg, var(--grad-stops)), linear-gradient(90deg, var(--grad-stops)); */ + /* background: #f5f5f6; */ + /* position: relative; */ + /* background: url("https://computationalthinking.mit.edu/Spring21/homepage/bg.svg"); */ /* background-size: cover; */ /* background-position: 0% 70%; */ + background: var(--welcome-mywork-bg); + /* background: var(--header-bg-color); */ + position: relative; +} + +.pluto-logo { + font-style: normal; + font-weight: 800; + color: inherit; + /* padding: 0.3em; */ + display: flex; + flex-direction: row; + padding: 0.5em; + align-items: center; + gap: 0.5ch; + font-family: var(--inter-ui-font-stack); + transform: translateY(0.23em); +} + +.pluto-logo img { + height: 1.2em; + width: 1.2em; +} + +#new { + background: var(--welcome-open-bg); + box-shadow: -2px 4px 9px 0px #00000012; + padding: 1.3rem; + border-radius: 0.6rem; + margin: 1rem; + /* border: 0.3rem solid #d6e0d8; */ +} + +#new.desktop_opener { + display: flex; + flex-direction: row; + align-content: center; + justify-content: space-around; + box-shadow: none; + position: relative; +} + +#new.desktop_opener .desktop_picker { + width: 100%; +} + +section { + display: flex; /* overflow: hidden; */ /* place-items: center; */ /* margin: 0rem 0rem; */ + + flex-direction: row; + justify-content: center; +} + +section > div { + margin: 1rem 1rem; + max-width: 614px; + /* margin: auto; */ + flex: 1 1 auto; + min-width: 0; +} + +.pluto-logo { + background: white; + border-radius: 0.4em; + display: flex; + flex: 0 1 auto; + transform: none; + font-size: 1.6rem; +} + +section#open { + /* background: #f5f5f6; */ + /* box-shadow: inset 1px 1px 20px red; */ + position: relative; +} + +section#featured > div { + max-width: 900px; +} + +header > div { + max-width: 62rem; /* margin: 0 auto; */ + flex: 1 1 auto; + display: flex; + z-index: 1; +} + +section#mywork::before, +section#open::after { + --c: hsl(196deg 20% 26% / 6%); + content: ""; + height: 50px; + top: 0px; + left: 0; + right: 0; + position: absolute; + display: block; + background: linear-gradient(0deg, transparent, var(--c)); + pointer-events: none; + z-index: 0; +} + +:where(#mywork, #open) h2 { + /* color: black; */ + --off: 4px; + --offm: -4px; + --oc: #ffffff; + /* text-shadow: var(--off) 0 var(--oc), var(--off) var(--off) var(--oc), 0 var(--off) var(--oc), var(--offm) var(--off) var(--oc), var(--offm) 0 var(--oc), + var(--offm) var(--offm) var(--oc), 0 var(--offm) var(--oc), var(--off) var(--offm) var(--oc); */ + display: inline-block; /* background: #fffffffc; */ /* padding: 0.4em; */ + border-radius: 0.4em; + /* color: white; */ /* text-transform: uppercase; */ + margin: 2rem 0rem 0rem 0; +} + +section#open::after { + top: unset; + bottom: 0; + background: linear-gradient(0deg, var(--c), transparent); +} + +div#app { + /* background: url(https://computationalthinking.mit.edu/Spring21/homepage/bg.svg); */ + background-size: cover; + background-position: 0% 77%; +} + +section#featured { + /* background: white; */ +} + +.new a { + text-decoration: none; /* font-weight: 700; */ + font-weight: 500; + font-style: italic; +} + +li.new { + position: sticky; + background: var(--welcome-newnotebook-bg); + top: 0; + z-index: 2; +} + +h1 { + font-size: 2.8rem; + margin-block-end: 0em; +} + +.collection { + margin: 6em 0; +} + +.collection h2 { + font-size: 2.5rem; + font-weight: 600; + margin: 0; +} + +#featured p { + max-width: 54ch; +} + +#github img { + aspect-ratio: 1; + filter: var(--image-filters); + width: 2rem; +} + +a#github { + display: block; + position: absolute; + top: 0.5rem; + right: 0.5rem; +} + +.show_scrollbar::-webkit-scrollbar { + width: 10px; + opacity: 0.1; +} +.show_scrollbar::-webkit-scrollbar-track { +} +.show_scrollbar::-webkit-scrollbar-thumb { + /* height: 11px; */ + background-color: var(--black); + opacity: 0.6; + border-radius: 1000px; +} +.show_scrollbar::-webkit-scrollbar-thumb:hover { + opacity: 1; +} diff --git a/sample/Basic mathematics.jl b/sample/Basic mathematics.jl index c60f2d467c..e4739fa32a 100644 --- a/sample/Basic mathematics.jl +++ b/sample/Basic mathematics.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.11.4 +# v0.19.9 using Markdown using InteractiveUtils @@ -7,102 +7,13 @@ using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) - global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end -# ╔═╡ e5e0a0da-d45c-11ea-1042-e9b5d0654d4f -md"Fix the value of `c` below to make it `c = a * b`" - -# ╔═╡ 4dff4b5e-d461-11ea-29c8-d548fdb5f08b -md"Edit the equation below to calculate the number of pizzas to order using the variables above for **people**, **avg**, and **slices**:" - -# ╔═╡ f907e46a-d471-11ea-07e5-f30e2aab3d08 -md"""The diameter of a pizza is often stated on a menu so let's define a **formula** to calculate the area of a pizza given the diameter **d**. - -We do this by writing a formula like this: `area(d) = pi * (d/2)^2` - -Let's write that below: -""" - -# ╔═╡ d9575e9c-d472-11ea-1eda-2d335d039f28 -md"""Now we have a function called **area** that we can pass any diameter and it will return the area of a pizza (or circle), let's try that with the pizza from before with `area(2*r)` to get the area of the pizza: -""" - -# ╔═╡ edb95b14-d473-11ea-3a5a-77382d31f941 -md"""## Finding the best pizza deal - -Let's see if a larger pizza is a better value by calculating the price per area. There are 4 sizes: small, medium, large, extra large with the following prices: - -Size | Diameter (inches) | Price ($) -:------- | :---------------: | --------: -small | 9 | 13.10 -medium | 13 | 20.95 -large | 15 | 24.90 -XL | 17 | 30.95 - -### 1. How many small pizzas is the same as one XL pizza? - -Edit the expression below: -""" - -# ╔═╡ 5b07b8fe-d475-11ea-01aa-6b88d6ed8a05 -md"""### 2. Calculate the cost per area of each pizza: -""" - -# ╔═╡ a42e4eb0-d474-11ea-316a-3d864451bc01 -md"Which size of pizza is the best deal? Write your answer below and assign it to the variable **best_value**." - -# ╔═╡ cb419286-d4ff-11ea-1d7f-af5c8574b775 -md"""### 3. Is this a good deal? - -San Marinos has a special **\"Buy two medium pizzas and save \$5\"**. Is this a better deal than buying a extra-large pizza? - -Calculate the total cost of two medium pizzas deal (saving \$5):""" - -# ╔═╡ 0d76d97c-d500-11ea-2433-e96c6fc43b05 -md"Calculate the total area of two medium pizzas:" - -# ╔═╡ 20a1e9cc-d500-11ea-3d9b-279c71bc20f1 -md"Now calculate cost per area by taking the total cost of two medium pizzas and divide by the total area:" - -# ╔═╡ 57f024ae-d500-11ea-1cc4-ed28348fdf93 -md"""Is it a better deal to get two medium pizzas for \$5 off or to just buy an extra-large?""" - -# ╔═╡ 180c8fdc-d503-11ea-04ca-bf2c07fd1c17 -md"""### 4. Advanced Problem - -A new worker at a pizza shop was getting paid for cutting pizza into pieces. The pieces of pizza could be any size. Calculate the maximum number of pieces the worker could make with two cuts of the pizza.""" - -# ╔═╡ 92b4a012-d503-11ea-15a2-1f3a446d3284 -md"Now what about 3 cuts across the pizza? What is the maximum number of pieces that can be made with **3 cuts**?" - -# ╔═╡ 2eb9a560-d507-11ea-3b8b-9d06678fe131 -md"Now, how many pieces can be made with **4 cuts**?" - -# ╔═╡ d1e3dec0-d507-11ea-1213-d37a9325ee2f -md"Are you starting to see a pattern? Can you figure out a formula for how many pieces of pizza can be made with \"n\" cuts? Make a table and fill in the number of pieces for a number of cuts and see if you can find the pattern: - -Cuts | Pieces -:--- | ------: -0 | 1 -1 | 2 -2 | 4 -3 | -4 | -" - -# ╔═╡ 97bfd13c-dcc2-11ea-0067-ad8c2c6517fc -md"To get an extra hint, figure out how many slices we can get from **5 cuts**:" - -# ╔═╡ e0cb2822-dcc2-11ea-2c85-5748bfe526dc -md"Have you found the pattern? Write down the formula below:" - -# ╔═╡ 03249876-d508-11ea-16bb-fd5afed37a1f -md"""##### Let's test your formula!""" - # ╔═╡ 14158eb0-d45c-11ea-088f-330e45412320 a = 2 @@ -119,6 +30,9 @@ First let's do some simple math with setting **a = $a**, **b = $b** and **c = a Type in the cells (with the coloured background) below and press **`Shift-Enter`** or the click the right-arrow button (▶️) to the right to execute the cell after changing the values." +# ╔═╡ e5e0a0da-d45c-11ea-1042-e9b5d0654d4f +md"Fix the value of `c` below to make it `c = a * b`" + # ╔═╡ 30f0f882-d45c-11ea-2adc-7d84ecf8a7a6 c = 10 @@ -156,6 +70,9 @@ Number of slices on a piece of pizza | slices """ +# ╔═╡ 4dff4b5e-d461-11ea-29c8-d548fdb5f08b +md"Edit the equation below to calculate the number of pizzas to order using the variables above for **people**, **avg**, and **slices**:" + # ╔═╡ 444e2fa4-d460-11ea-12aa-57e0576c2d66 pizzas = 1 @@ -171,15 +88,48 @@ The area of a pizza is ``A = \pi r^2``. Lets try calculating the area of a pizz # ╔═╡ 50f0f6d6-d471-11ea-304e-8f72e7ef9d7e A = r^2 +# ╔═╡ f907e46a-d471-11ea-07e5-f30e2aab3d08 +md"""The diameter of a pizza is often stated on a menu so let's define a **formula** to calculate the area of a pizza given the diameter **d**. + +We do this by writing a formula like this: `area(d) = pi * (d/2)^2` + +Let's write that below: +""" + # ╔═╡ cb36a9ee-d472-11ea-1835-bf7963137e18 area(d) = pi * (d / 2)^2 +# ╔═╡ d9575e9c-d472-11ea-1eda-2d335d039f28 +md"""Now we have a function called **area** that we can pass any diameter and it will return the area of a pizza (or circle), let's try that with the pizza from before with `area(2*r)` to get the area of the pizza: +""" + # ╔═╡ 04b010c0-d473-11ea-1767-136c7e26e122 A2 = area(r) +# ╔═╡ edb95b14-d473-11ea-3a5a-77382d31f941 +md"""## Finding the best pizza deal + +Let's see if a larger pizza is a better value by calculating the price per area. There are 4 sizes: small, medium, large, extra large with the following prices: + +Size | Diameter (inches) | Price ($) +:------- | :---------------: | --------: +small | 9 | 13.10 +medium | 13 | 20.95 +large | 15 | 24.90 +XL | 17 | 30.95 + +### 1. How many small pizzas is the same as one XL pizza? + +Edit the expression below: +""" + # ╔═╡ 637c26fa-d475-11ea-2c5b-2b0f4775b119 smalls_in_xl = 1 +# ╔═╡ 5b07b8fe-d475-11ea-01aa-6b88d6ed8a05 +md"""### 2. Calculate the cost per area of each pizza: +""" + # ╔═╡ 3823d09e-d474-11ea-194e-59b5805f303b small = 13.10 / area(9) @@ -192,35 +142,86 @@ large = 24.90 / area(15) # ╔═╡ 962e6b86-d474-11ea-11a6-a1d11e33ae42 xl = 30.95 / area(17) +# ╔═╡ a42e4eb0-d474-11ea-316a-3d864451bc01 +md"Which size of pizza is the best deal? Write your answer below and assign it to the variable **best_value**." + # ╔═╡ 16ec3f32-d4ff-11ea-20e2-5bc6dd5db083 best_value = small +# ╔═╡ cb419286-d4ff-11ea-1d7f-af5c8574b775 +md"""### 3. Is this a good deal? + +San Marinos has a special **\"Buy two medium pizzas and save \$5\"**. Is this a better deal than buying a extra-large pizza? + +Calculate the total cost of two medium pizzas deal (saving \$5):""" + # ╔═╡ f147b6cc-d4ff-11ea-05ad-6f5b441e5d1b two_medium_cost = 20.95 * 1 - 0 +# ╔═╡ 0d76d97c-d500-11ea-2433-e96c6fc43b05 +md"Calculate the total area of two medium pizzas:" + # ╔═╡ 19eb2a82-d500-11ea-3782-596adc689382 two_medium_area = 1 * area(13) +# ╔═╡ 20a1e9cc-d500-11ea-3d9b-279c71bc20f1 +md"Now calculate cost per area by taking the total cost of two medium pizzas and divide by the total area:" + # ╔═╡ 70e85498-d500-11ea-35af-474574f5c011 two_medium_deal = 1 +# ╔═╡ 57f024ae-d500-11ea-1cc4-ed28348fdf93 +md"""Is it a better deal to get two medium pizzas for \$5 off or to just buy an extra-large?""" + +# ╔═╡ 180c8fdc-d503-11ea-04ca-bf2c07fd1c17 +md"""### 4. Advanced Problem + +A new worker at a pizza shop was getting paid for cutting pizza into pieces. The pieces of pizza could be any size. Calculate the maximum number of pieces the worker could make with two cuts of the pizza.""" + # ╔═╡ 6494e270-d503-11ea-38a7-df96e7f0a241 cuts2 = 1 +# ╔═╡ 92b4a012-d503-11ea-15a2-1f3a446d3284 +md"Now what about 3 cuts across the pizza? What is the maximum number of pieces that can be made with **3 cuts**?" + # ╔═╡ a05aae8e-d506-11ea-190f-57e9ce53b8b9 cuts3 = 1 +# ╔═╡ 2eb9a560-d507-11ea-3b8b-9d06678fe131 +md"Now, how many pieces can be made with **4 cuts**?" + # ╔═╡ 5a8ede88-d507-11ea-30d9-c99a67243781 cuts4 = 1 +# ╔═╡ d1e3dec0-d507-11ea-1213-d37a9325ee2f +md"Are you starting to see a pattern? Can you figure out a formula for how many pieces of pizza can be made with \"n\" cuts? Make a table and fill in the number of pieces for a number of cuts and see if you can find the pattern: + +Cuts | Pieces +:--- | ------: +0 | 1 +1 | 2 +2 | 4 +3 | +4 | +" + +# ╔═╡ 97bfd13c-dcc2-11ea-0067-ad8c2c6517fc +md"To get an extra hint, figure out how many slices we can get from **5 cuts**:" + # ╔═╡ bae0cb62-dcc2-11ea-0667-512e1c407d40 cuts5 = 1 +# ╔═╡ e0cb2822-dcc2-11ea-2c85-5748bfe526dc +md"Have you found the pattern? Write down the formula below:" + # ╔═╡ f5f89724-d507-11ea-0a93-6d904f36bbe4 function pieces(n) return n end +# ╔═╡ 03249876-d508-11ea-16bb-fd5afed37a1f +md"""##### Let's test your formula!""" + # ╔═╡ bd9f3d24-d509-11ea-165d-3d465a0b4542 md"""Move the slider to change the number of cuts: diff --git a/sample/Getting started.jl b/sample/Getting started.jl index 3fba0f7f7b..cf3c51ccea 100644 --- a/sample/Getting started.jl +++ b/sample/Getting started.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.11.14 +# v0.19.9 using Markdown using InteractiveUtils @@ -7,8 +7,9 @@ using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) - global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end diff --git a/sample/JavaScript.jl b/sample/JavaScript.jl index cfa36d2273..cc59d97a7e 100644 --- a/sample/JavaScript.jl +++ b/sample/JavaScript.jl @@ -1,5 +1,13 @@ ### A Pluto.jl notebook ### -# v0.17.3 +# v0.19.9 + +#> [frontmatter] +#> author_url = "https://github.com/JuliaPluto" +#> image = "https://upload.wikimedia.org/wikipedia/commons/9/99/Unofficial_JavaScript_logo_2.svg" +#> tags = ["javascript", "web", "classic"] +#> author_name = "Pluto.jl" +#> description = "Use HTML, CSS and JavaScript to make your own interactive visualizations!" +#> license = "Unlicense" using Markdown using InteractiveUtils @@ -53,7 +61,7 @@ This document assumes that you have used HTML, CSS and JavaScript before in anot @@ -284,19 +293,13 @@ my_data = [ .join("text") .attr("x", d => d.coordinate[0]) .attr("y", d => d.coordinate[1]) + .style("fill", "red") .text(d => d.name) return svg """) -# ╔═╡ 7d9d6c28-131a-4b2a-84f8-5c085f387e85 -md""" -#### Future: directly embedding data - -In the future, you will be able to embed data directly into JavaScript, using Pluto's built-in, optimized data transfer. See [the Pull Request](https://github.com/fonsp/Pluto.jl/pull/1124) for more info. -""" - # ╔═╡ 0866afc2-fd42-42b7-a572-9d824cf8b83b md""" ## Custom `@bind` output @@ -323,12 +326,12 @@ ClickCounter(text="Click") = @htl(""" @@ -443,7 +446,7 @@ md""" In the example above, it would have been easier to just select the button directly, using: ```javascript // ⛔ do no use: -var first_button = document.body.querySelector("button#first") +const first_button = document.body.querySelector("button#first") ``` However, this becomes a problem when **combining using the widget multiple times in the same notebook**, since all selectors will point to the first instance. @@ -457,27 +460,29 @@ md""" To use external javascript dependencies, you can load them from a CDN, such as: - [jsdelivr.com](https://www.jsdelivr.com/) -- [skypack.dev](https://www.skypack.dev/) +- [esm.sh](https://esm.sh) Just like when writing a browser app, there are two ways to import JS dependencies: a ` + \"\"\") +end +``` + +In this example, the `const d` is populated from a hook into Pluto's data transfer. For large amounts of typed vector data (e.g. `Vector{UInt8}` or `Vector{Float64}`), this is *much* more efficient than interpolating the data directly with HypertextLiteral using `$(d)`, which would use a JSON-like string serialization. + +**Note:** this API is still *experimental*, and might change in the future. +""" + # ╔═╡ da7091f5-8ba2-498b-aa8d-bbf3b4505b81 md""" # Appendix @@ -763,7 +820,7 @@ details(md""" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.8.3" +manifest_format = "2.0" +project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + +[deps] +""" + +# ╔═╡ Cell order: +# ╟─ce092665-e18d-4314-a43e-51a04e25cd30 +# ╟─02b26da6-40d1-4b3c-a594-aff8016b0945 +# ╠═1adedccd-db89-40ec-ab77-a92c2976fc2c +# ╟─2f8d4781-a364-4803-ba5f-69f85ef1c055 +# ╟─50891330-1c60-4020-b4f6-f1200ca2b71d +# ╟─8f45d098-4041-4449-83c3-79280232691e +# ╠═57e3bfde-b692-44e6-a764-7459626a8919 +# ╟─688a8ea9-1bff-45c5-8942-f8e96ed0ef79 +# ╟─50fa8a8b-2c55-45b6-b4e0-8f510294586c +# ╟─76b5db23-8174-445d-927e-ef2d92bbf32f +# ╟─e548c2ce-0e77-43b2-acaa-97005d67801f +# ╠═f953ef79-b3a5-4adb-8467-b92b5f5bfbce +# ╟─c16b0170-5b0b-4618-b028-b6278bd6319d +# ╟─4dbbfcee-37d0-4361-9058-ea3f9354e2de +# ╟─49fd22a1-63d7-48c3-a1de-67087b77e347 +# ╟─9a7e812e-f6bd-47b8-ac36-124a2a233354 +# ╟─838cb47d-db5e-4182-b7a1-164f0552bd02 +# ╟─9cae62be-7591-4ebe-9fbc-c39be4e479c4 +# ╟─dfb656e4-94bc-4b3b-bd09-979d937246b8 +# ╟─af97612d-832e-431a-b096-be8d7c94228f +# ╠═99f3bca7-5314-4e86-8f28-bb5a6358bdbd +# ╠═cd5b10ac-0618-4220-b7e3-b1beeea43eff +# ╠═8b622d0d-def6-4a2c-af3b-fdf91240fb90 +# ╠═5a399dae-5756-4614-a64f-214e812ee069 +# ╠═cca6c895-7974-4c3e-9170-ed85ae127478 +# ╠═65b31de3-fe0b-4e2a-97ad-39e4cd17962f +# ╠═3b8ae605-025f-485e-a5a2-1f823319a67a +# ╠═6e315f3b-1a46-483e-86bc-931023a8ac54 +# ╠═cb3b24f4-10d1-4de9-bd82-813af622f79b +# ╠═dd004d6c-54f6-4dd7-9aea-910adf0b22a5 +# ╟─5b08043c-302b-4b9b-982d-4ba1da41ff9f +# ╟─e7626671-ff5d-45f1-b8df-853d1d9bc1ac +# ╟─4428fe55-7d65-487b-864b-b566e7ecee9e +# ╠═7e5644fd-75ff-4f70-9981-ddb7d9ad470c +# ╠═445eddb1-ccee-45d9-be5b-3f5fec9e2c7a +# ╟─51e38551-742c-48dd-aaea-ffe479b9621b +# ╠═1a2f37ec-9be2-4fd5-8f0b-b6579a241b55 +# ╟─d2451923-6487-497c-a169-9815702c42fc +# ╟─64a23ad5-0fa1-48dd-9786-dcfbc73a3b52 +# ╟─e392d442-5c83-4711-bc45-c2dbedf62b7f +# ╟─d6def1a3-cc96-4eb9-bfce-949d29ffe31f +# ╟─58eb1225-6521-45ef-827a-78cdafbaf784 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/sample/Plots.jl.jl b/sample/Plots.jl.jl index 54fe6d3666..833cbfdd95 100644 --- a/sample/Plots.jl.jl +++ b/sample/Plots.jl.jl @@ -1,5 +1,13 @@ ### A Pluto.jl notebook ### -# v0.17.3 +# v0.19.9 + +#> [frontmatter] +#> author_url = "https://github.com/JuliaPluto" +#> image = "https://user-images.githubusercontent.com/6933510/174067386-c0a1296f-dba8-4dbf-b936-1c7f81933f94.png" +#> tags = ["basic", "classic", "plotting"] +#> author_name = "Pluto.jl" +#> description = "An introduction to Plots.jl" +#> license = "Unlicense" using Markdown using InteractiveUtils @@ -22,6 +30,7 @@ Let's start by importing the `Plots` package. _(Pluto's package manager automati md"We need to choose a _backend_ for Plots.jl. We choose `plotly` because it works with no additional dependencies. You can [read more about backends](http://docs.juliaplots.org/latest/backends/#backends) in Plots.jl - it's one of its coolest features!" # ╔═╡ 9414a092-f105-11ea-10cd-23f84e47d876 +# ╠═╡ show_logs = false plotly() # ╔═╡ 5ae65950-9ad9-11ea-2e14-35119d369acd @@ -38,7 +47,7 @@ apples = [15, 25, 80, 75, 50, 30, 35, 15, 25, 35] # ╔═╡ a405ae4c-9ad9-11ea-0008-f763e098846d md""" -Great, let's plot them! The basic syntax of of `Plots` is very simple. +Great, let's plot them! The basic syntax of `Plots` is very simple. """ # ╔═╡ 12a8c222-9ad9-11ea-2544-355bd080367f @@ -215,7 +224,7 @@ PLUTO_PROJECT_TOML_CONTENTS = """ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" [compat] -Plots = "~1.25.2" +Plots = "~1.31.4" """ # ╔═╡ 00000000-0000-0000-0000-000000000002 @@ -224,9 +233,9 @@ PLUTO_MANIFEST_TOML_CONTENTS = """ [[Adapt]] deps = ["LinearAlgebra"] -git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7" +git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "3.3.1" +version = "3.3.3" [[ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" @@ -245,33 +254,45 @@ version = "1.0.8+0" [[Cairo_jll]] deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99" +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.16.1+0" +version = "1.16.1+1" [[ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "4c26b4e9e91ca528ea212927326ece5918a04b47" +git-tree-sha1 = "80ca332f6dcb2508adba68f22f551adb2d00a624" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.11.2" +version = "1.15.3" [[ChangesOfVariables]] deps = ["ChainRulesCore", "LinearAlgebra", "Test"] -git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1" +git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8" uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" -version = "0.1.2" +version = "0.1.4" + +[[CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.0" [[ColorSchemes]] -deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"] -git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a" +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "1fd869cc3875b57347f7027521f561cf46d1fcd8" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.15.0" +version = "3.19.0" [[ColorTypes]] deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.0" +version = "0.11.4" + +[[ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] +git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.9.9" [[Colors]] deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] @@ -280,31 +301,30 @@ uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" version = "0.12.8" [[Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "dce3e3fea680869eaa0b774b2e8343e9ff442313" +deps = ["Dates", "LinearAlgebra", "UUIDs"] +git-tree-sha1 = "924cdca592bc16f14d2f7006754a621735280b74" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.40.0" +version = "4.1.0" [[CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" [[Contour]] -deps = ["StaticArrays"] -git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" +git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" -version = "0.5.7" +version = "0.6.2" [[DataAPI]] -git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" +git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.9.0" +version = "1.10.0" [[DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d" +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.11" +version = "0.18.13" [[DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" @@ -319,18 +339,14 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" deps = ["Mmap"] uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - [[DocStringExtensions]] deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +git-tree-sha1 = "c5544d8abb854e306b7b2f799ab31cdba527ccae" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" +version = "0.9.0" [[Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" [[EarCut_jll]] @@ -341,9 +357,9 @@ version = "2.2.3+0" [[Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f" +git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.2.10+0" +version = "2.4.8+0" [[FFMPEG]] deps = ["FFMPEG_jll"] @@ -352,10 +368,13 @@ uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" version = "0.4.1" [[FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "ccd479984c7838684b3ac204b716c89955c76623" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.4.0+0" +version = "4.4.2+0" + +[[FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" [[FixedPointNumbers]] deps = ["Statistics"] @@ -389,27 +408,27 @@ version = "1.0.10+0" [[GLFW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] -git-tree-sha1 = "0c603255764a1fa0b61752d2bec14cfbd18f7fe8" +git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01" uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" -version = "3.3.5+1" +version = "3.3.6+0" [[GR]] -deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"] -git-tree-sha1 = "30f2b340c2fff8410d89bfcdc9c0a6dd661ac5f7" +deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] +git-tree-sha1 = "037a1ca47e8a5989cc07d19729567bb71bfabd0c" uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.62.1" +version = "0.66.0" [[GR_jll]] deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "fd75fa3a2080109a2c0ec9864a6e14c60cca3866" +git-tree-sha1 = "c8ab731c9127cd931c93221f65d6a1008dad7256" uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.62.0+0" +version = "0.66.0+0" [[GeometryBasics]] deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] -git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c" +git-tree-sha1 = "83ea630384a13fc4f002b77690bc0afeb4255ac9" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -version = "0.4.1" +version = "0.4.2" [[Gettext_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] @@ -419,9 +438,9 @@ version = "0.21.0+0" [[Glib_jll]] deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "74ef6288d071f58033d54fd6708d4bc23a8b8972" +git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.68.3+1" +version = "2.68.3+2" [[Graphite2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -435,10 +454,10 @@ uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" version = "1.0.2" [[HTTP]] -deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] -git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" +deps = ["Base64", "CodecZlib", "Dates", "IniFile", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "ed47af35905b7cc8f1a522ca684b35a212269bd8" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.9.17" +version = "1.2.0" [[HarfBuzz_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] @@ -447,10 +466,9 @@ uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" version = "2.8.1+1" [[IniFile]] -deps = ["Test"] -git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" +git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625" uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" -version = "0.5.0" +version = "0.5.1" [[InteractiveUtils]] deps = ["Markdown"] @@ -458,9 +476,9 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[InverseFunctions]] deps = ["Test"] -git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65" +git-tree-sha1 = "b3364212fb5d870f724876ffcd34dd8ec6d98918" uuid = "3587e190-3f89-42d0-90ee-14403ec27112" -version = "0.1.2" +version = "0.1.7" [[IrrationalConstants]] git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" @@ -479,21 +497,21 @@ version = "1.0.0" [[JLLWrappers]] deps = ["Preferences"] -git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e" +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.3.0" +version = "1.4.1" [[JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.2" +version = "0.21.3" [[JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943" +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "2.1.0+0" +version = "2.1.2+0" [[LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -501,6 +519,12 @@ git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" version = "3.100.1+0" +[[LERC_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +uuid = "88015f11-f218-50d7-93a8-a6af411a945d" +version = "3.0.0+1" + [[LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" @@ -514,9 +538,9 @@ version = "1.3.0" [[Latexify]] deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] -git-tree-sha1 = "a8f4f279b6fa3c3c4f1adadd78a621b13a506bce" +git-tree-sha1 = "1a43be956d433b5d0321197150c2f94e16c0aaa0" uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.15.9" +version = "0.15.16" [[LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] @@ -574,10 +598,10 @@ uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" version = "2.35.0+0" [[Libtiff_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9" +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "3eb79b0ca5764d4799c06699573fd8f533259713" uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.3.0+0" +version = "4.4.0+0" [[Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -586,18 +610,24 @@ uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" version = "2.36.0+0" [[LinearAlgebra]] -deps = ["Libdl"] +deps = ["Libdl", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[LogExpFunctions]] deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "be9eef9f9d78cecb6f262f3c10da151a6c5ab827" +git-tree-sha1 = "7c88f63f9f0eb5929f15695af9a4d7d3ed278a91" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.5" +version = "0.3.16" [[Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" +[[LoggingExtras]] +deps = ["Dates", "Logging"] +git-tree-sha1 = "5d4d2d9904227b8bd66386c1138cf4d5ffa826bf" +uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" +version = "0.4.9" + [[MacroTools]] deps = ["Markdown", "Random"] git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" @@ -609,10 +639,10 @@ deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" +deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "Random", "Sockets"] +git-tree-sha1 = "9f4f5a42de3300439cb8300236925670f844a555" uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.3" +version = "1.1.1" [[MbedTLS_jll]] deps = ["Artifacts", "Libdl"] @@ -636,24 +666,39 @@ uuid = "a63ad114-7e13-5084-954f-fe012c677804" uuid = "14a3606d-f60d-562e-9121-12d972cd8159" [[NaNMath]] -git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" +deps = ["OpenLibm_jll"] +git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "0.3.5" +version = "1.0.1" [[NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" [[Ogg_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f" +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.5+0" +version = "1.3.5+1" + +[[OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" + +[[OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" [[OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a" +git-tree-sha1 = "e60321e3f2616584ff98f0a4f18d98ae6f89bbb3" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "1.1.10+0" +version = "1.1.17+0" + +[[OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" [[Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -674,9 +719,9 @@ version = "8.44.0+0" [[Parsers]] deps = ["Dates"] -git-tree-sha1 = "ae4bbcadb2906ccc085cf52ac286dc1377dceccc" +git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.1.2" +version = "2.3.2" [[Pixman_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -689,28 +734,28 @@ deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markd uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [[PlotThemes]] -deps = ["PlotUtils", "Requires", "Statistics"] -git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" +deps = ["PlotUtils", "Statistics"] +git-tree-sha1 = "8162b2f8547bc23876edd0c5181b27702ae58dce" uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "2.0.1" +version = "3.0.0" [[PlotUtils]] deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] -git-tree-sha1 = "b084324b4af5a438cd63619fd006614b3b20b87b" +git-tree-sha1 = "9888e59493658e476d3073f1ce24348bdc086660" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.0.15" +version = "1.3.0" [[Plots]] -deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun"] -git-tree-sha1 = "65ebc27d8c00c84276f14aaf4ff63cbe12016c70" +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] +git-tree-sha1 = "0a0da27969e8b6b2ee67c112dcf7001a659049a0" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.25.2" +version = "1.31.4" [[Preferences]] deps = ["TOML"] -git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.2.2" +version = "1.3.0" [[Printf]] deps = ["Unicode"] @@ -718,16 +763,16 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[Qt5Base_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] -git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8" +git-tree-sha1 = "c6c0f690d0cc7caddb74cef7aa847b824a16b256" uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" -version = "5.15.3+0" +version = "5.15.3+1" [[REPL]] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[Random]] -deps = ["Serialization"] +deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[RecipesBase]] @@ -737,43 +782,50 @@ version = "1.2.1" [[RecipesPipeline]] deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] -git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8" +git-tree-sha1 = "2690681814016887462cf5ac37102b51cd9ec781" uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.4.1" +version = "0.6.2" [[Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" version = "1.2.2" +[[RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "22c5201127d7b243b9ee1de3b43c408879dff60f" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "0.3.0" + [[Requires]] deps = ["UUIDs"] -git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621" +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.1.3" +version = "1.3.0" [[SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" [[Scratch]] deps = ["Dates"] -git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" +git-tree-sha1 = "f94f779c94e58bf9ea243e77a37e16d9de9126bd" uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.1.0" +version = "1.1.1" [[Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -[[SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - [[Showoff]] deps = ["Dates", "Grisu"] git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" version = "1.0.3" +[[SimpleBufferStream]] +git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" +uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" +version = "1.1.0" + [[Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" @@ -787,32 +839,44 @@ version = "1.0.1" deps = ["LinearAlgebra", "Random"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +[[SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.1.7" + [[StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "3c76dde64d03699e074ac02eb2e8ba8254d428da" +deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "23368a3313d12a2326ad0035f0db0c0966f438ef" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.2.13" +version = "1.5.2" + +[[StaticArraysCore]] +git-tree-sha1 = "66fe9eb253f910fe8cf161953880cfdaef01cdf0" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.0.1" [[Statistics]] deps = ["LinearAlgebra", "SparseArrays"] uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [[StatsAPI]] -git-tree-sha1 = "0f2aa8e32d511f758a2ce49208181f7733a0936a" +deps = ["LinearAlgebra"] +git-tree-sha1 = "2c11d7290036fe7aac9038ff312d3b3a2a5bf89e" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.1.0" +version = "1.4.0" [[StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "2bb0cb32026a66037360606510fca5984ccc6b75" +git-tree-sha1 = "472d044a1c8df2b062b23f222573ad6837a615ba" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.13" +version = "0.33.19" [[StructArrays]] deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] -git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3" +git-tree-sha1 = "ec47fb6069c57f1cee2f67541bf8f23415146de7" uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" -version = "0.6.3" +version = "0.6.11" [[TOML]] deps = ["Dates"] @@ -825,23 +889,35 @@ uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" version = "1.0.1" [[Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] -git-tree-sha1 = "fed34d0e71b91734bf0a7e10eb1bb05296ddbcd0" +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] +git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.6.0" +version = "1.7.0" [[Tar]] deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +[[TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + [[Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[[TranscodingStreams]] +deps = ["Random", "Test"] +git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.9.6" + [[URIs]] -git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" +git-tree-sha1 = "e59ecc5a41b000fa94423a578d29290c7266fc10" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.3.0" +version = "1.4.0" [[UUIDs]] deps = ["Random", "SHA"] @@ -856,6 +932,11 @@ git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" version = "0.4.1" +[[Unzip]] +git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.1.2" + [[Wayland_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" @@ -864,15 +945,15 @@ version = "1.19.0+0" [[Wayland_protocols_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "66d72dc6fcc86352f01676e8f0f698562e60510f" +git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" -version = "1.23.0+0" +version = "1.25.0+0" [[XML2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" +git-tree-sha1 = "58443b63fb7e465a8a7210828c91c08b92132dff" uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.9.12+0" +version = "2.9.14+0" [[XSLT_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] @@ -1012,9 +1093,15 @@ uuid = "83775a58-1f1d-513f-b197-d71354ab007a" [[Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6" +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.0+0" +version = "1.5.2+0" + +[[libaom_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" +uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" +version = "3.4.0+0" [[libass_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] @@ -1022,6 +1109,10 @@ git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" version = "0.15.1+0" +[[libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" + [[libfdk_aac_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" @@ -1036,9 +1127,9 @@ version = "1.6.38+0" [[libvorbis_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb" +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.7+0" +version = "1.3.7+1" [[nghttp2_jll]] deps = ["Artifacts", "Libdl"] diff --git a/sample/PlutoUI.jl.jl b/sample/PlutoUI.jl.jl index 73ef79ec79..c3365c47f3 100644 --- a/sample/PlutoUI.jl.jl +++ b/sample/PlutoUI.jl.jl @@ -1,5 +1,14 @@ ### A Pluto.jl notebook ### -# v0.17.3 +# v0.19.9 + +#> [frontmatter] +#> author_url = "https://github.com/JuliaPluto" +#> image = "https://user-images.githubusercontent.com/6933510/174067690-50c8128d-748b-4f50-8a76-2ce18166642b.png" +#> order = "3" +#> tags = ["basic", "interactivity", "classic"] +#> author_name = "Pluto.jl" +#> description = "Slider, buttons, dropdowns and more from PlutoUI.jl!" +#> license = "Unlicense" using Markdown using InteractiveUtils @@ -620,7 +629,7 @@ PLUTO_PROJECT_TOML_CONTENTS = """ PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" [compat] -PlutoUI = "~0.7.24" +PlutoUI = "~0.7.39" """ # ╔═╡ 00000000-0000-0000-0000-000000000002 @@ -629,9 +638,9 @@ PLUTO_MANIFEST_TOML_CONTENTS = """ [[AbstractPlutoDingetjes]] deps = ["Pkg"] -git-tree-sha1 = "abb72771fd8895a7ebd83d5632dc4b989b022b5b" +git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" uuid = "6e696c72-6542-2067-7265-42206c756150" -version = "1.1.2" +version = "1.1.4" [[ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" @@ -644,18 +653,25 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[ColorTypes]] deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.0" +version = "0.11.4" + +[[CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" [[Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +[[FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + [[FixedPointNumbers]] deps = ["Statistics"] git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" @@ -669,9 +685,10 @@ uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" version = "0.0.4" [[HypertextLiteral]] -git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238" +deps = ["Tricks"] +git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" -version = "0.9.3" +version = "0.9.4" [[IOCapture]] deps = ["Logging", "Random"] @@ -685,9 +702,9 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.2" +version = "0.21.3" [[LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] @@ -709,7 +726,7 @@ uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" [[LinearAlgebra]] -deps = ["Libdl"] +deps = ["Libdl", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[Logging]] @@ -732,11 +749,15 @@ uuid = "14a3606d-f60d-562e-9121-12d972cd8159" [[NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +[[OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" + [[Parsers]] deps = ["Dates"] -git-tree-sha1 = "d7fa6237da8004be601e19bd6666083056649918" +git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.1.3" +version = "2.3.2" [[Pkg]] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] @@ -744,9 +765,9 @@ uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [[PlutoUI]] deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"] -git-tree-sha1 = "6c9fa3e4880242c666dafa4901a34d8e1cd1b243" +git-tree-sha1 = "8d1f54886b9037091edf146b517989fc4a09efec" uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" -version = "0.7.24" +version = "0.7.39" [[Printf]] deps = ["Unicode"] @@ -757,7 +778,7 @@ deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[Random]] -deps = ["Serialization"] +deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[Reexport]] @@ -794,6 +815,11 @@ uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[[Tricks]] +git-tree-sha1 = "6bac775f2d42a611cdfcd1fb217ee719630c4175" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.6" + [[UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" @@ -805,6 +831,10 @@ uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +[[libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" + [[nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" diff --git a/sample/Tower of Hanoi.jl b/sample/Tower of Hanoi.jl index b22f1e6787..d6ad6a8ffb 100644 --- a/sample/Tower of Hanoi.jl +++ b/sample/Tower of Hanoi.jl @@ -165,7 +165,7 @@ This is where we can check a solution. We start with a function that takes our r function run_solution(solver::Function, start = starting_stacks) moves = solver(deepcopy(start)) #apply the solver - all_states = Array{Any,1}(undef, length(moves) + 1) + all_states = Vector{Any}(undef, length(moves) + 1) all_states[1] = start for (i, m) in enumerate(moves) diff --git a/sample/notebook_with_metadata.jl b/sample/notebook_with_metadata.jl new file mode 100644 index 0000000000..3d111574f9 --- /dev/null +++ b/sample/notebook_with_metadata.jl @@ -0,0 +1,48 @@ +### A Pluto.jl notebook ### +# v0.18.0 + +using Markdown +using InteractiveUtils + +# ╔═╡ 8399ed34-7dc4-11eb-16ec-e572834e149d +# ╠═╡ disabled = true +#=╠═╡ +x = 7 + ╠═╡ =# + +# ╔═╡ 88c83d42-7dc4-11eb-1b5e-a1ecad4b6ff1 +# ╠═╡ disabled = true +#=╠═╡ +x + ╠═╡ =# + +# ╔═╡ 48f7cf80-c1f6-4002-8639-a0addb8e6780 +#=╠═╡ +x + 1 + ╠═╡ =# + +# ╔═╡ 18f57a3f-3b1f-4346-9686-752438f6067f +z = 14 + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.7.1" +manifest_format = "2.0" + +[deps] +""" + +# ╔═╡ Cell order: +# ╠═88c83d42-7dc4-11eb-1b5e-a1ecad4b6ff1 +# ╠═8399ed34-7dc4-11eb-16ec-e572834e149d +# ╠═48f7cf80-c1f6-4002-8639-a0addb8e6780 +# ╠═18f57a3f-3b1f-4346-9686-752438f6067f +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/sample/test1.jl b/sample/test1.jl index ac3fffb6a6..2972e4334f 100644 --- a/sample/test1.jl +++ b/sample/test1.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.11.3 +# v0.19.8 using Markdown using InteractiveUtils @@ -7,12 +7,16 @@ using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) - global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end +# ╔═╡ 878a4750-b15e-11ea-2584-8feba490699f +using Test + # ╔═╡ fd0763a0-b163-11ea-23b4-a7bae7052e19 md"# File picker" @@ -22,6 +26,15 @@ md"# Notebook interaction" # ╔═╡ 6dde0352-b15e-11ea-2fa8-7327cc366c1a md"## Running multiple cells" +# ╔═╡ 7370dcc0-b15e-11ea-234b-23584c864b61 +ma = 1 + +# ╔═╡ 75b21a30-b15e-11ea-3046-2170ec097e63 +mb = 2 + +# ╔═╡ 7b74dd40-b15e-11ea-291a-d7e10a185718 +@test ma + mb == 3 + # ╔═╡ f0b821b0-b15f-11ea-1f64-dd33aa85b54e md"## Moving cells" @@ -31,6 +44,67 @@ md"## Stopping cells" # ╔═╡ d2c1d090-b162-11ea-0c17-2b234c098cf9 md"# CodeMirror" +# ╔═╡ bc5bf64e-8b47-45ac-baf2-3cbb8e35d916 +# (this code should error) +""" +Some sample code from https://juliamono.netlify.app/ +""" +function T(𝛉::AbstractArray, + 𝒞::Tuple{AbstractArray, + Vararg{AbstractArray}}, + 𝒟::Tuple{AbstractArray, Vararg{AbstractArray}}) + ⊗ = kron + l = length(𝛉) + 𝐈ₗ = SMatrix{l,l}(1.0I) + 𝐈ₘ = SMatrix{1,1}(1.0I) + 𝐓 = @SMatrix zeros(l,l) + N = length(𝒟[1]) + ℳ, ℳʹ = 𝒟 + Λ₁, Λ₂ = 𝒞 + 𝚲ₙ = @MMatrix zeros(4,4) + 𝐞₁ = @SMatrix [1.0; 0.0; 0.0] + 𝐞₂ = @SMatrix [0.0; 1.0; 0.0] + for n = 1:N + index = SVector(1,2) + 𝚲ₙ[1:2,1:2] .= Λ₁[n][index,index] + 𝚲ₙ[3:4,3:4] .= Λ₂[n][index,index] + 𝐦 = hom(ℳ[n]) + 𝐦ʹ = hom(ℳʹ[n]) + 𝐔ₙ = (𝐦 ⊗ 𝐦ʹ) + ∂ₓ𝐮ₙ = [(𝐞₁ ⊗ 𝐦ʹ) (𝐞₂ ⊗ 𝐦ʹ) (𝐦 ⊗ 𝐞₁) (𝐦 ⊗ 𝐞₂)] + 𝐁ₙ = ∂ₓ𝐮ₙ * 𝚲ₙ * ∂ₓ𝐮ₙ' + 𝚺ₙ = 𝛉' * 𝐁ₙ * 𝛉 + 𝚺ₙ⁻¹ = inv(𝚺ₙ) + 𝐓₁ = @SMatrix zeros(Float64,l,l) + for k = 1:l + 𝐞ₖ = 𝐈ₗ[:,k] + ∂𝐞ₖ𝚺ₙ = (𝐈ₘ ⊗ 𝐞ₖ') * 𝐁ₙ * (𝐈ₘ ⊗ 𝛉) + (𝐈ₘ ⊗ 𝛉') * 𝐁ₙ * (𝐈ₘ ⊗ 𝐞ₖ) + # Accumulating the result in 𝐓₁ allocates memory, + # even though the two terms in the + # summation are both SArrays. + 𝐓₁ = 𝐓₁ + 𝐔ₙ * 𝚺ₙ⁻¹ * (∂𝐞ₖ𝚺ₙ) * 𝚺ₙ⁻¹ * 𝐔ₙ' * 𝛉 * 𝐞ₖ' + end + 𝐓 = 𝐓 + 𝐓₁ + end + 𝐓 +end + +# ╔═╡ a28395ed-4004-4731-a0bd-be3398505a0e +# Some sample code from https://juliamono.netlify.app/ +quote + using Zygote: @adjoint + function ignore(f) + try return f() + catch e; return 0; end + end + @adjoint function ignore(f) + try Zygote._pullback(__context__, f) + catch e + 0, ȳ -> nothing + end + end +end; + # ╔═╡ d890a190-b162-11ea-31dd-8d603787e5c5 md"## Autocomplete" @@ -62,6 +136,26 @@ md"## Stack traces" # ╔═╡ 84888e20-b160-11ea-1d61-c5934251d6dd html"
" +# ╔═╡ 9dc4a0a0-b15f-11ea-361c-87742cf3f2a2 +function ef(x) + + + sqrt(-x) +end + +# ╔═╡ aab109c0-b15f-11ea-275d-31e21fcda8c4 +ef(1) + +# ╔═╡ 976bc2a0-b160-11ea-3e7a-9f033b0f2daf +function eg(x) + + + sqrt(-x) +end + +# ╔═╡ 9c74f9b2-b160-11ea-35fb-917cb1120f5b +eg(1) + # ╔═╡ ea3f77f0-b166-11ea-046e-ef39bfc57d0f md"## Bad errors" @@ -74,6 +168,21 @@ md"# Bonds" # ╔═╡ 3a14b3f0-b165-11ea-153d-796416ee5ccc md"## Lossy" +# ╔═╡ 41a75500-b165-11ea-2519-bbd0feaef6cf +@bind bl1 html"" + +# ╔═╡ 4ccbf670-b165-11ea-1951-c17ffb8a58cf +sleep(.5); bl1 + +# ╔═╡ 8bb26902-b165-11ea-048c-d7f7a72006ee +@assert bl1 isa Int64 + +# ╔═╡ e559eaf0-b165-11ea-0d81-ffc480afe8f3 +@bind bl2 html"" + +# ╔═╡ e63be680-b165-11ea-0fd3-bd4e0bf92eb8 +bl2 + # ╔═╡ 59966a90-b163-11ea-1786-e56e45f06dd0 md"## Recursive" @@ -83,20 +192,73 @@ md"## Scrolling" # ╔═╡ 431d17c0-cfff-11ea-39b5-394b34438544 md"### `text/html`" +# ╔═╡ f2c0bb90-b162-11ea-24a1-3f864a09e5ee +@bind bw1 html"" + +# ╔═╡ a4d4ac28-cfff-11ea-3f14-15d2928d2c88 +zeros((bw1, bw1)) + +# ╔═╡ 56e6f440-b15e-11ea-1327-09932af5b5bd +HTML("
") + +# ╔═╡ 2296ac80-b163-11ea-3d00-ed366fa9ce3e +@bind bw2 html"" + +# ╔═╡ 20d72230-b163-11ea-39c2-69bf2c422d50 +HTML("
") + +# ╔═╡ 55d116d6-cfff-11ea-25fc-056ce62c8bcd +zeros((bw2, bw2)) + +# ╔═╡ 76c98394-cfff-11ea-0b6c-25260a8a3bb9 +zeros((10,10)); + # ╔═╡ 32b5edc0-b15d-11ea-09d6-3b889f6d397a md"# Rich display ## `image/svg+xml` and `image/jpeg`" +# ╔═╡ 52cb1264-d824-11ea-332a-55964f3d8b90 +begin + struct A end + struct B end + + function Base.show(io::IO, ::MIME"image/svg+xml", x::A) + write(io, read(download("https://raw.githubusercontent.com/fonsp/Pluto.jl/main/frontend/img/logo.svg"))) + end + function Base.show(io::IO, ::MIME"image/jpg", x::B) + write(io, read(download("https://fonsp.com/img/doggoSmall.jpg?raw=true"))) + end + nothing +end + +# ╔═╡ 5d59acfe-d824-11ea-1d7b-07551a2b11d4 +A() + +# ╔═╡ 64d929aa-d824-11ea-2cc1-835fbe38be11 +B() + +# ╔═╡ 661c112e-d824-11ea-3612-4104449c409e +[A(), B()] + # ╔═╡ 3be84600-b166-11ea-1d24-59212363543f md"## `text/plain`" +# ╔═╡ 42f0a872-b166-11ea-0c71-355d62f67fca +ra = 1:100 + +# ╔═╡ 794bc212-b166-11ea-0840-fddb29190841 +1:13 + # ╔═╡ 95898660-b166-11ea-1db1-df7f3c4f1353 "I am not bold" # ╔═╡ 2859a890-b161-11ea-14e9-b7ddaf08195a md"## Tree view" +# ╔═╡ 23f41dd2-b15c-11ea-17d2-45b3e83093ba +Ref(Dict(:a => [1,md"![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/PDS_70.jpg/567px-PDS_70.jpg)", md"# Hello"], [3,4] => (:b, (x=3, y=2)))) + # ╔═╡ 88bd7aae-b15f-11ea-270e-ab00e6a01203 ["asdf", "I am not bold"] @@ -278,6 +440,106 @@ asdfdasd # ╔═╡ 46fc284a-d682-11ea-34b6-69874efcaf65 md"### Text wrapping" +# ╔═╡ 4d452956-d682-11ea-3aeb-cd7d1b2f67dc +s="12345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678056780123456780123456780123456780123456780123456780123456780123456780123456780120123456780\n\n\"\"\n\n5678012345678012 + +7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 + +👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧❤❤❤✔ + +Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + +# ╔═╡ 4e320206-d682-11ea-3dfe-b77f6e96f33a +Text(s) + +# ╔═╡ f16e48a7-f1db-4f15-a013-3d509b2f93ea +md""" +# LaTeX math +""" + +# ╔═╡ c3ae2fd1-628b-4876-9253-053805c47295 +md""" +This should be centered: + +$$T^{n+1}_i = \kappa (T^n_{i-1} - 2 T^n_i + T^n_{i+1}).$$ + +and should look exactly the same as: + +```math +T^{n+1}_i = \kappa (T^n_{i-1} - 2 T^n_i + T^n_{i+1}). +``` + +this should be on the left: + + $T^{n+1}_i = \kappa (T^n_{i-1} - 2 T^n_i + T^n_{i+1}).$ +""" + +# ╔═╡ ae4ab84b-ed29-4e09-b9c3-049d287e8c60 +md""" +This z``\alpha``z and z$\alpha$z should look the same. +""" + +# ╔═╡ 4b44cf5b-cac3-4283-b156-7adfce878228 +md""" +> Calling `T` the current vector, i.e. $\mathbf{T}^n := (T^n_i)_{i=1, \ldots, N_x}$, and `T′` the new vector at the next time step, we have the following basic expression, for the ``i``th element. +""" + +# ╔═╡ a10b9a7c-33d6-447e-99c0-c96a43fb3c6f +md""" +$$\begin{aligned} +\dot{x} &= a + x^2 y - bx - x \\ +\dot{y} &= b x - x^2 y +\end{aligned}$$ +""" + +# ╔═╡ ec741d6c-b148-4929-8805-2cd93ce6fca7 +md""" +## Extensions +""" + +# ╔═╡ 1d10093f-3256-46a8-b0d4-5186092825e2 +md""" +### `mchem` +Here is a chemical reaction: ``\ce{CO2 + C -> 2 CO}``. And another one: + +```math +\ce{Hg^2+ ->[I-] $\underset{\mathrm{red}}{\ce{HgI2}}$ ->[I-] $\underset{\mathrm{red}}{\ce{[Hg^{II}I4]^2-}}$} +``` +""" + +# ╔═╡ 7376d9e9-5740-4b67-9e8e-a2447e2c17cf +html""" +

This should look like a centered, black version of

+image + +""" + +# ╔═╡ d61ed468-4922-4d7b-b7f1-475e17bcd1e4 +md""" +### `cases` +```math +\begin{numcases} {|x|=} +x, & for $x \geq 0$\\ +-x, & for $x < 0$ +\end{numcases} +``` +""" + +# ╔═╡ 9d4c1242-cea0-4e76-8554-de0e05938de3 +md""" +### `physics` +```math +\require{physics} +\principalvalue hysics +``` +""" + +# ╔═╡ fe97e64f-9de6-46aa-bdb4-a1d6e2f61297 +md""" +### `color` +``\color{red}{i\ am\ red}`` +""" + # ╔═╡ 1bb05fc0-b15d-11ea-3dae-7734f66a0c56 md"# Testing machinery" @@ -314,118 +576,6 @@ html""" """ -# ╔═╡ 878a4750-b15e-11ea-2584-8feba490699f -using Test - -# ╔═╡ 7370dcc0-b15e-11ea-234b-23584c864b61 -ma = 1 - -# ╔═╡ 75b21a30-b15e-11ea-3046-2170ec097e63 -mb = 2 - -# ╔═╡ 7b74dd40-b15e-11ea-291a-d7e10a185718 -@test ma + mb == 3 - -# ╔═╡ 9dc4a0a0-b15f-11ea-361c-87742cf3f2a2 -function ef(x) - - - sqrt(-x) -end - -# ╔═╡ aab109c0-b15f-11ea-275d-31e21fcda8c4 -ef(1) - -# ╔═╡ 976bc2a0-b160-11ea-3e7a-9f033b0f2daf -function eg(x) - - - sqrt(-x) -end - -# ╔═╡ 9c74f9b2-b160-11ea-35fb-917cb1120f5b -eg(1) - -# ╔═╡ 41a75500-b165-11ea-2519-bbd0feaef6cf -@bind bl1 html"" - -# ╔═╡ 4ccbf670-b165-11ea-1951-c17ffb8a58cf -sleep(.5); bl1 - -# ╔═╡ 8bb26902-b165-11ea-048c-d7f7a72006ee -@assert bl1 isa Int64 - -# ╔═╡ e559eaf0-b165-11ea-0d81-ffc480afe8f3 -@bind bl2 html"" - -# ╔═╡ e63be680-b165-11ea-0fd3-bd4e0bf92eb8 -bl2 - -# ╔═╡ f2c0bb90-b162-11ea-24a1-3f864a09e5ee -@bind bw1 html"" - -# ╔═╡ a4d4ac28-cfff-11ea-3f14-15d2928d2c88 -zeros((bw1, bw1)) - -# ╔═╡ 56e6f440-b15e-11ea-1327-09932af5b5bd -HTML("
") - -# ╔═╡ 2296ac80-b163-11ea-3d00-ed366fa9ce3e -@bind bw2 html"" - -# ╔═╡ 20d72230-b163-11ea-39c2-69bf2c422d50 -HTML("
") - -# ╔═╡ 55d116d6-cfff-11ea-25fc-056ce62c8bcd -zeros((bw2, bw2)) - -# ╔═╡ 76c98394-cfff-11ea-0b6c-25260a8a3bb9 -zeros((10,10)); - -# ╔═╡ 52cb1264-d824-11ea-332a-55964f3d8b90 -begin - struct A end - struct B end - - function Base.show(io::IO, ::MIME"image/svg+xml", x::A) - write(io, read(download("https://raw.githubusercontent.com/fonsp/Pluto.jl/main/frontend/img/logo.svg"))) - end - function Base.show(io::IO, ::MIME"image/jpg", x::B) - write(io, read(download("https://fonsp.com/img/doggoSmall.jpg?raw=true"))) - end - nothing -end - -# ╔═╡ 5d59acfe-d824-11ea-1d7b-07551a2b11d4 -A() - -# ╔═╡ 64d929aa-d824-11ea-2cc1-835fbe38be11 -B() - -# ╔═╡ 661c112e-d824-11ea-3612-4104449c409e -[A(), B()] - -# ╔═╡ 42f0a872-b166-11ea-0c71-355d62f67fca -ra = 1:100 - -# ╔═╡ 794bc212-b166-11ea-0840-fddb29190841 -1:13 - -# ╔═╡ 23f41dd2-b15c-11ea-17d2-45b3e83093ba -Ref(Dict(:a => [1,md"![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/PDS_70.jpg/567px-PDS_70.jpg)", md"# Hello"], [3,4] => (:b, (x=3, y=2)))) - -# ╔═╡ 4d452956-d682-11ea-3aeb-cd7d1b2f67dc -s="12345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678056780123456780123456780123456780123456780123456780123456780123456780123456780120123456780\n\n\"\"\n\n5678012345678012 - -7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 7801234567801234567801234567 - -👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧‍👦👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧👩‍👩‍👧❤❤❤✔ - -Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." - -# ╔═╡ 4e320206-d682-11ea-3dfe-b77f6e96f33a -Text(s) - # ╔═╡ 7e2cc6c0-b15d-11ea-32b0-15394cdebd35 function ask(kind, str::Markdown.MD) HTML("
" * sprint(show, MIME"text/html"(), str) * "
") @@ -597,10 +747,52 @@ ask("visual", md"Assignment to `低调又牛逼的类型系统` must be visible" # ╔═╡ 21bd9950-b15d-11ea-2632-41b1c66563bd ask("visual", md"These three paragraphs must have equal spacing between them") +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.7.0" +manifest_format = "2.0" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +""" + # ╔═╡ Cell order: # ╟─ce7f9d90-b163-11ea-0ff7-cf7378644741 # ╠═878a4750-b15e-11ea-2584-8feba490699f -# ╟─fd0763a0-b163-11ea-23b4-a7bae7052e19 +# ╠═fd0763a0-b163-11ea-23b4-a7bae7052e19 # ╟─11f3ae90-b164-11ea-1027-0d2e6e7048dd # ╟─26d2b310-b164-11ea-0029-f7b04ee5ba73 # ╟─1c6229f0-b165-11ea-0f1d-674022c43971 @@ -617,6 +809,8 @@ ask("visual", md"These three paragraphs must have equal spacing between them") # ╟─f4015940-b15f-11ea-0f3a-1714c79023c3 # ╟─4980fc10-b163-11ea-081b-c1335699a8f6 # ╟─d2c1d090-b162-11ea-0c17-2b234c098cf9 +# ╠═bc5bf64e-8b47-45ac-baf2-3cbb8e35d916 +# ╠═a28395ed-4004-4731-a0bd-be3398505a0e # ╟─d890a190-b162-11ea-31dd-8d603787e5c5 # ╟─1b569b72-b167-11ea-1462-63674f7e13db # ╠═e141f910-b162-11ea-039b-3ba1414cbd07 @@ -710,6 +904,19 @@ ask("visual", md"These three paragraphs must have equal spacing between them") # ╟─46fc284a-d682-11ea-34b6-69874efcaf65 # ╟─4d452956-d682-11ea-3aeb-cd7d1b2f67dc # ╠═4e320206-d682-11ea-3dfe-b77f6e96f33a +# ╟─f16e48a7-f1db-4f15-a013-3d509b2f93ea +# ╟─c3ae2fd1-628b-4876-9253-053805c47295 +# ╟─ae4ab84b-ed29-4e09-b9c3-049d287e8c60 +# ╟─4b44cf5b-cac3-4283-b156-7adfce878228 +# ╟─a10b9a7c-33d6-447e-99c0-c96a43fb3c6f +# ╟─ec741d6c-b148-4929-8805-2cd93ce6fca7 +# ╟─1d10093f-3256-46a8-b0d4-5186092825e2 +# ╟─7376d9e9-5740-4b67-9e8e-a2447e2c17cf +# ╟─d61ed468-4922-4d7b-b7f1-475e17bcd1e4 +# ╟─9d4c1242-cea0-4e76-8554-de0e05938de3 +# ╟─fe97e64f-9de6-46aa-bdb4-a1d6e2f61297 # ╟─1bb05fc0-b15d-11ea-3dae-7734f66a0c56 # ╠═9ac925d0-b15d-11ea-2abd-7db360900be0 # ╠═7e2cc6c0-b15d-11ea-32b0-15394cdebd35 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/sample/test_go_to_definition.jl b/sample/test_go_to_definition.jl new file mode 100644 index 0000000000..7ddfdea7ea --- /dev/null +++ b/sample/test_go_to_definition.jl @@ -0,0 +1,399 @@ +### A Pluto.jl notebook ### +# v0.17.5 + +using Markdown +using InteractiveUtils + +# ╔═╡ a3865853-58ad-4e27-bfbf-7223760ca026 +md""" +# Methodical testing for the go-to-definition plugin + +### FAQ +**Q:** Wait.. isn't it better to have this as javascript tests, so we can actually automate them and be sure that nothing breaks instead of relying on our flimsy human eyeballs? + +**A:** Yes +""" + +# ╔═╡ c93bd0ce-dffe-4416-a007-79116ab1f1cb +macro >(expr) + nothing +end + +# ╔═╡ 91bd5444-154e-48f1-bd51-fbdcfc5cfc14 +macro +(expr) + return esc(expr) +end + +# ╔═╡ cf229fd1-5bdc-4a44-8272-5ecc872a2fbd +md""" +### Reading guide for ["Definitions"](#Definitions) + +Every section here consists of a couple of definitions, followed by a cell that references all of these. The test is pressing every reference and making sure it selects the right part in the definition cell. +""" + +# ╔═╡ 8d559967-84da-45c9-9e05-ce1adc36804c +md""" +### Reading guide for ["Usages"](#Usages) + +There are some "predefined" variables: `x`, `y` and `z`; `@z`, `@z_str`; `X`, `Y` and `Z`. These are then used to make sure they get underlined. I decided that the `z`-s and `y`-s are intended to reference outside of the cell. If there is a way to override the variable locally in the cell or an identifier that isn't a reference, use `x` for that. There should be **no underlined `x`'s**. +""" + +# ╔═╡ 52620cb5-7d42-4d40-a3ae-6d9d29448014 +md"## Definitions" + +# ╔═╡ 7527a5b8-7eeb-4ec7-abbe-34ed68415ce1 +md"---" + +# ╔═╡ 0cdf94d0-dd1a-4a4a-b6c2-d2d290cd3224 +import Example + +# ╔═╡ 2d145800-c22f-4bbe-a6f3-bca8bb79d513 +import Example as ExampleAlias + +# ╔═╡ df05dcd2-fb6b-4907-ad80-6d231d6b6ce5 +import Example: hello, domath as domath_alias + +# ╔═╡ f22e3e28-6cda-4dbd-bc30-d2f7c2411e91 +import Example: hello as hello_alias + +# ╔═╡ 8948913b-9917-46c2-a91a-14386d269502 +import Example.domath + +# ╔═╡ e152285a-9265-4a13-bf0d-cfc0ba418595 +import Example.domath as another_domath_alias + +# ╔═╡ 90682238-2769-4f20-afcf-56ced93242ba +Example; ExampleAlias; hello; domath; + +# ╔═╡ e30de56d-5985-42e7-abde-1ec90c7484c9 +hello_alias; domath_alias; another_domath_alias; # Pluto doesn't recognize aliases? + +# ╔═╡ 3be4e4b7-02f8-4f4c-bcab-2d796f38a93f +md"---" + +# ╔═╡ 1d2f2927-49d0-404e-a324-4ab4f677d89a +abstract type _abstract_type1 end + +# ╔═╡ 654566d0-9b46-49dd-a8ac-4d3f5708cba5 +abstract type _abstract_type2{T} end + +# ╔═╡ 8e823381-7b06-44b1-99e0-565083bc2434 +_abstract_type1; _abstract_type2; + +# ╔═╡ 709300fe-3b3d-471f-8fc1-608b904d18ed +md"---" + +# ╔═╡ 4f996030-0ff2-4ea2-aa48-ac92765072c8 +struct _struct1 end; + +# ╔═╡ 670eb47b-225f-4626-9276-4cae08d90843 +struct _struct2 x end; + +# ╔═╡ 5afc38cb-ae2b-495e-93f9-a7ca85773ca9 +struct _struct4{T} <: _abstract_type2{T} end + +# ╔═╡ 327e846b-3edc-406a-936f-799475a7b3de +md"---" + +# ╔═╡ 955ae894-24a1-4f8a-999d-3e8d809e0eba +(_tuple1,) = (:x,); + +# ╔═╡ 09a24659-6646-40bb-8e7c-0d340d2b45da +(_tuple2, _tuple3, _tuple4...) = (:x1, :x2, :x3, :x4); + +# ╔═╡ a85d6a78-b212-46b0-bacc-ad880911f2cb +_tuple1; _tuple2; _tuple3; _tuple4; + +# ╔═╡ cb226d6d-f294-42b0-a40e-cb07e58fa776 +md"---" + +# ╔═╡ 554ad95c-2edd-4ef9-b532-0ec7cf08243c +_baretuple1, = (:x,); + +# ╔═╡ d6e27295-77eb-4a84-98be-ea338a85f455 +_baretuple2, _baretuple3... = (:x1, :x2, :x3); + +# ╔═╡ 06948715-85e7-4609-94b1-bb91123d928c +_baretuple1; _baretuple2; _baretuple3; + +# ╔═╡ 22032cef-5889-48d8-8709-bb7eeac89638 +md""" +For both `_tuple4` and `_baretuple3`: JS side has these covered (shown by example below), but Pluto doesn't recognize it (thus it not working outside cells) +""" + +# ╔═╡ 31713a89-8656-4cf9-aee0-ac24c3430c0a +let + (_tuple2, _tuple3, _tuple4...) = (:x1, :x2, :x3, :x4); + _baretuple2, _baretuple3... = (:x1, :x2, :x3); + + _baretuple3; _tuple4; # cmd+click me! +end; + +# ╔═╡ 0a8e5b66-daaa-4f32-8dd8-1e8b9ec35465 +md"---" + +# ╔═╡ 4e3b5537-59b7-4d87-ae54-f1153c092ffa +const _const = :const; + +# ╔═╡ 5d2d43f0-5a17-407a-a9ee-a041010e5579 +global _global = :global; + +# ╔═╡ e14b69ca-f325-440c-acb1-c33de71e75a2 +_const; _global; + +# ╔═╡ f9737a60-9909-445c-8382-4dd00aa267ba +md"## Usages" + +# ╔═╡ a0f62011-92f2-44ad-b420-27217bcbd89c +md"### Predefined" + +# ╔═╡ 90a81bc8-cce9-49bd-a3c4-126c74a515d3 +x = "Hi, I'm x"; + +# ╔═╡ ad3ab162-2139-45b4-8877-18285f1c2fa8 +y = "Hi, x"; + +# ╔═╡ 18e25073-6ea7-4287-975d-84c05743930e +z = "I was expecting a joke"; + +# ╔═╡ b7bd9512-a119-46e5-a6df-58b04e04bda0 +_function3() = (x, z); + +# ╔═╡ 1c530e0e-770c-44b5-a13e-e5b905e3d84c +_function6(x) = x, z; + +# ╔═╡ a6eec43c-dc37-4113-a7e5-fafde8bdbd39 +@Base.kwdef struct _struct3 + x::Int = z +end; + +# ╔═╡ 0135431d-4b3f-4513-9982-937cc0b60837 +_struct1; _struct2; _struct3; _struct4; + +# ╔═╡ 669cf7b9-b1cc-4f01-8dc3-b9a156f9de63 +macro z end; + +# ╔═╡ 20804f0f-ca92-463d-afb7-604aeb6057f7 +macro z_str end; + +# ╔═╡ 7781bce5-2dd8-4d06-8bfd-7589bea619dc +abstract type X end + +# ╔═╡ f9236dd2-4fd7-4d86-8dcb-cbc011da8b03 +abstract type Y end + +# ╔═╡ 4a9d7bb3-9ca7-4af9-b7e1-e730fbc1c570 +abstract type Z end + +# ╔═╡ 5d9701eb-46a3-483a-9b51-0e376031ae34 +function _function1()::Z end; + +# ╔═╡ 24716c18-5a36-4b12-9ed5-43069c81f15b +function _function2(x...)::Z + x, z +end; + +# ╔═╡ 5365c683-75b7-4f29-8cbe-810167409686 +_function4(x::Z) = begin x end; + +# ╔═╡ a85475ce-44ee-4b87-99b6-10b8b31d99fa +_function4(::Z) = (10, z, "hi"); + +# ╔═╡ b2c9c60f-c107-4cbb-bc7e-3018117e9ecb +_function5(x)::Z = (x, z); + +# ╔═╡ 3f3440dc-4449-4a9f-b019-f2b5a3fc97b9 +_function1; _function2; _function3; _function4; _function5; _function6; + +# ╔═╡ e5b3cb7a-bf0d-479e-a533-d5699abe6f2a +md"### Cases" + +# ╔═╡ 94c6fccc-ae3a-40bb-bf3f-a11f6d9244e2 +@> sum(x for x in [1,2,3]) + +# ╔═╡ 18ea6b86-9ed5-4a75-852e-13cbb7f4d8da +@> function f(x=z)::z + x, z +end + +# ╔═╡ d8de87c9-e516-4f5f-978a-4c53071c5656 +@> function f(x=z; y)::z + x, y, z +end + +# ╔═╡ 6bc106ce-ebba-4487-859e-9701ebeda022 +md"---" + +# ╔═╡ c283d772-e007-447a-aa88-a01d75d48e2e +@> z.@x + +# ╔═╡ fa2aaff3-9b8a-4cdc-919d-2de38f54018b +@> @z.x + +# ╔═╡ da330714-5130-470b-bd2a-6343c932f808 +@> @z + +# ╔═╡ 196a17eb-1ded-40be-a00b-b5e4d7fa1070 +md"---" + +# ╔═╡ 3e773c63-a8b7-4ad8-9dbb-74d519054f0f +@> struct x + x1 + x2::z + x3::z = z + x4 = z +end + +# ╔═╡ eac662c8-369e-4bf3-9aec-5f9c46fc4f77 +@> x::z = z + +# ╔═╡ 1d7c5c41-f5c8-40b3-b0b1-7da19572bef2 +@> :(1 + $(z...) + 1) + +# ╔═╡ 7521b3c9-a1bd-4786-aa19-44fd1db90149 +@> (x, y...) = z + +# ╔═╡ 4eb71552-16da-42bb-a9dc-f18e1b3e7190 +@> z.@macro x = z + +# ╔═╡ 3f009423-6a36-41c2-ad74-de596a8519c1 +@> begin + struct x end + struct x{y} end + struct x <: z end + struct x <: z{x,z} end + struct x{y} <: z{x,y,z} end + + x, y, z +end + +# ╔═╡ fba1aebf-c00a-4750-89d3-a1b6e27c07a4 +@> var"x" = 10; + +# ╔═╡ 0b34c665-9c93-40ab-9965-d0ae36a2190d +@> var"x"; + +# ╔═╡ 29f7c36e-9b4d-4a91-83b3-162f1cd9e00c +@> (x=z) -> (x, z) + +# ╔═╡ a478a0e0-51ba-4261-ac9d-5b3333b5a8bf +@> f(z) + +# ╔═╡ 8ea3cd9e-c831-4140-977c-cc6cee5367b9 +@> f(x=z) + +# ╔═╡ 499392fa-4c50-4d0b-b584-098355e9af48 +md"---" + +# ╔═╡ 5749eb9d-f18f-4a91-8bb1-17d1c680d397 +@> quote $(z) end + +# ╔═╡ 259004c3-770f-4fe2-9c84-4c6f5d5c879c +@> quote quote $(x) end end + +# ╔═╡ 91f8bfee-102a-437d-8c40-d7c694f0a384 +@> quote quote $$(z) end end + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +Example = "7876af07-990d-54b4-ab0e-23690620f79a" + +[compat] +Example = "~0.5.3" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[Example]] +git-tree-sha1 = "46e44e869b4d90b96bd8ed1fdcf32244fddfb6cc" +uuid = "7876af07-990d-54b4-ab0e-23690620f79a" +version = "0.5.3" +""" + +# ╔═╡ Cell order: +# ╟─a3865853-58ad-4e27-bfbf-7223760ca026 +# ╟─c93bd0ce-dffe-4416-a007-79116ab1f1cb +# ╟─91bd5444-154e-48f1-bd51-fbdcfc5cfc14 +# ╟─cf229fd1-5bdc-4a44-8272-5ecc872a2fbd +# ╟─8d559967-84da-45c9-9e05-ce1adc36804c +# ╟─52620cb5-7d42-4d40-a3ae-6d9d29448014 +# ╠═5d9701eb-46a3-483a-9b51-0e376031ae34 +# ╠═24716c18-5a36-4b12-9ed5-43069c81f15b +# ╠═b7bd9512-a119-46e5-a6df-58b04e04bda0 +# ╠═5365c683-75b7-4f29-8cbe-810167409686 +# ╠═a85475ce-44ee-4b87-99b6-10b8b31d99fa +# ╠═b2c9c60f-c107-4cbb-bc7e-3018117e9ecb +# ╠═1c530e0e-770c-44b5-a13e-e5b905e3d84c +# ╠═3f3440dc-4449-4a9f-b019-f2b5a3fc97b9 +# ╟─7527a5b8-7eeb-4ec7-abbe-34ed68415ce1 +# ╠═0cdf94d0-dd1a-4a4a-b6c2-d2d290cd3224 +# ╠═2d145800-c22f-4bbe-a6f3-bca8bb79d513 +# ╠═df05dcd2-fb6b-4907-ad80-6d231d6b6ce5 +# ╠═f22e3e28-6cda-4dbd-bc30-d2f7c2411e91 +# ╠═8948913b-9917-46c2-a91a-14386d269502 +# ╠═e152285a-9265-4a13-bf0d-cfc0ba418595 +# ╠═90682238-2769-4f20-afcf-56ced93242ba +# ╠═e30de56d-5985-42e7-abde-1ec90c7484c9 +# ╟─3be4e4b7-02f8-4f4c-bcab-2d796f38a93f +# ╠═1d2f2927-49d0-404e-a324-4ab4f677d89a +# ╠═654566d0-9b46-49dd-a8ac-4d3f5708cba5 +# ╠═8e823381-7b06-44b1-99e0-565083bc2434 +# ╟─709300fe-3b3d-471f-8fc1-608b904d18ed +# ╠═4f996030-0ff2-4ea2-aa48-ac92765072c8 +# ╠═670eb47b-225f-4626-9276-4cae08d90843 +# ╠═a6eec43c-dc37-4113-a7e5-fafde8bdbd39 +# ╠═5afc38cb-ae2b-495e-93f9-a7ca85773ca9 +# ╠═0135431d-4b3f-4513-9982-937cc0b60837 +# ╟─327e846b-3edc-406a-936f-799475a7b3de +# ╠═955ae894-24a1-4f8a-999d-3e8d809e0eba +# ╠═09a24659-6646-40bb-8e7c-0d340d2b45da +# ╠═a85d6a78-b212-46b0-bacc-ad880911f2cb +# ╟─cb226d6d-f294-42b0-a40e-cb07e58fa776 +# ╠═554ad95c-2edd-4ef9-b532-0ec7cf08243c +# ╠═d6e27295-77eb-4a84-98be-ea338a85f455 +# ╠═06948715-85e7-4609-94b1-bb91123d928c +# ╟─22032cef-5889-48d8-8709-bb7eeac89638 +# ╠═31713a89-8656-4cf9-aee0-ac24c3430c0a +# ╟─0a8e5b66-daaa-4f32-8dd8-1e8b9ec35465 +# ╠═4e3b5537-59b7-4d87-ae54-f1153c092ffa +# ╠═5d2d43f0-5a17-407a-a9ee-a041010e5579 +# ╠═e14b69ca-f325-440c-acb1-c33de71e75a2 +# ╟─f9737a60-9909-445c-8382-4dd00aa267ba +# ╟─a0f62011-92f2-44ad-b420-27217bcbd89c +# ╠═90a81bc8-cce9-49bd-a3c4-126c74a515d3 +# ╠═ad3ab162-2139-45b4-8877-18285f1c2fa8 +# ╠═18e25073-6ea7-4287-975d-84c05743930e +# ╠═669cf7b9-b1cc-4f01-8dc3-b9a156f9de63 +# ╠═20804f0f-ca92-463d-afb7-604aeb6057f7 +# ╠═7781bce5-2dd8-4d06-8bfd-7589bea619dc +# ╠═f9236dd2-4fd7-4d86-8dcb-cbc011da8b03 +# ╠═4a9d7bb3-9ca7-4af9-b7e1-e730fbc1c570 +# ╟─e5b3cb7a-bf0d-479e-a533-d5699abe6f2a +# ╠═94c6fccc-ae3a-40bb-bf3f-a11f6d9244e2 +# ╠═18ea6b86-9ed5-4a75-852e-13cbb7f4d8da +# ╠═d8de87c9-e516-4f5f-978a-4c53071c5656 +# ╟─6bc106ce-ebba-4487-859e-9701ebeda022 +# ╠═c283d772-e007-447a-aa88-a01d75d48e2e +# ╠═fa2aaff3-9b8a-4cdc-919d-2de38f54018b +# ╠═da330714-5130-470b-bd2a-6343c932f808 +# ╟─196a17eb-1ded-40be-a00b-b5e4d7fa1070 +# ╠═3e773c63-a8b7-4ad8-9dbb-74d519054f0f +# ╠═eac662c8-369e-4bf3-9aec-5f9c46fc4f77 +# ╠═1d7c5c41-f5c8-40b3-b0b1-7da19572bef2 +# ╠═7521b3c9-a1bd-4786-aa19-44fd1db90149 +# ╠═4eb71552-16da-42bb-a9dc-f18e1b3e7190 +# ╠═3f009423-6a36-41c2-ad74-de596a8519c1 +# ╠═fba1aebf-c00a-4750-89d3-a1b6e27c07a4 +# ╠═0b34c665-9c93-40ab-9965-d0ae36a2190d +# ╠═29f7c36e-9b4d-4a91-83b3-162f1cd9e00c +# ╠═a478a0e0-51ba-4261-ac9d-5b3333b5a8bf +# ╠═8ea3cd9e-c831-4140-977c-cc6cee5367b9 +# ╟─499392fa-4c50-4d0b-b584-098355e9af48 +# ╠═5749eb9d-f18f-4a91-8bb1-17d1c680d397 +# ╠═259004c3-770f-4fe2-9c84-4c6f5d5c879c +# ╠═91f8bfee-102a-437d-8c40-d7c694f0a384 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 \ No newline at end of file diff --git a/sample/test_logging.jl b/sample/test_logging.jl new file mode 100644 index 0000000000..39b23fa226 --- /dev/null +++ b/sample/test_logging.jl @@ -0,0 +1,1464 @@ +### A Pluto.jl notebook ### +# v0.19.5 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═╡ ecc81850-8d79-4b6f-83c8-f2c9bcda23b3 +using ProgressLogging + +# ╔═╡ eebe1108-588a-4e81-a69c-f2c21e9cbbaa +using PlutoUI + +# ╔═╡ 10c02645-cb3b-42be-8df1-679e8fb05382 +using HypertextLiteral + +# ╔═╡ 890b8d1d-1bf0-4497-ac64-9852f68e1577 +using Plots + +# ╔═╡ 24c5d164-b618-4e05-abe9-62d129c0b55f +md""" +# Progress +""" + +# ╔═╡ 2e7dac1a-ef0d-4b76-a33a-9510b064c25c +@progress for z in 1:1000 + sleep(.001) +end + +# ╔═╡ 3599eb82-0003-11eb-3814-dfd0f5737846 +for i in 1:10 + + @debug i + @info i*100 + if isodd(i) + @warn "Oh no!" i + @error i + end + sleep(.1) +end + +# ╔═╡ 54d5c34e-63b5-4b52-91fe-a5fd1b729182 +for z in 1:20 + @info z + sleep(.1) +end + +# ╔═╡ 0248c2de-7edf-4ff6-a450-9f6d79f8966d +@warn "wow" + +# ╔═╡ 196080df-e8c0-4120-a97c-443cf66295ff +md""" +# Positioning +""" + +# ╔═╡ a22411c8-24e0-4a80-9b91-bc1f0999cc3c +some_data = Dict([1,"asdf"] => (123, [1,[2,3,[4,5, md"# asdf"]]], md"## asdf", DomainError("asdf"))) + +# ╔═╡ 091d33fe-fffe-11ea-131f-01f4248b30ea +@info "23aaa" some_data + +# ╔═╡ 5f8496cb-d29e-4c4c-b378-1173242c7a78 +collect(rand(1000)) + +# ╔═╡ a93ac790-7a04-418d-8117-01f01e4608c8 +:asdf => 123 + +# ╔═╡ 88f87c39-89ef-4492-92ae-c6cd33699c59 +let + @info "a asdf as" + 123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123 + @info "b" + @info "c" +end + +# ╔═╡ 2d01cdaa-fffe-11ea-09f5-63527a1b0f87 +x = 233564653 + +# ╔═╡ 2fbbb413-213f-4556-b5f9-df7cf6331451 +b = @bind hello Slider(1:100) + +# ╔═╡ 449541e2-351d-41d2-9623-34d243fe6a97 +b + +# ╔═╡ 0e823733-4668-47db-8d17-f079b7ed8c75 +hello + +# ╔═╡ dfcf652e-ca15-43ad-8307-d40367de6986 +@warn "Oh no!" 12 + +# ╔═╡ 5d023cd2-4fe6-4bd0-9a54-7512f52b7916 +begin + + @info "Remeber to use the function Base.alsjdhfkjashdf to also get akjshdfkjashdfkjhasdf." + + @warn md""" + _Writing a notebook is not just about writing the final document — Pluto empowers the experiments and discoveries that are essential to getting there._ + + **Explore models and share results** in a notebook that is + + - **_reactive_** - when changing a function or variable, Pluto automatically updates all affected cells. + - **_lightweight_** - Pluto is written in pure Julia and is easy to install. + - **_simple_** - no hidden workspace state; friendly UI. + """ + + println("Some long text asdflkj asldkjf aslkdfj alskjdf kj") +end + +# ╔═╡ e5f2703b-198c-4926-867e-7f914fa10253 +md""" +# Rich output in logs +""" + +# ╔═╡ b52f7e61-c6b5-46ae-8025-d2b4649fed99 +svg_data = download("https://diffeq.sciml.ai/stable/assets/multiODEplot.png") |> read + +# ╔═╡ 52b8c0be-64f7-4950-ab4a-983c6fa50d1a +cool_plot = Show(MIME"image/png"(), svg_data) + +# ╔═╡ 504dfdc1-41da-4fcb-ba8e-aa69643d57a1 +plot(args...; kwargs...) = Plots.plot(args...; kwargs..., size=(150,120)) |> as_svg + +# ╔═╡ 6a7824d0-06e4-4569-9fa8-b9884d299f80 +begin + + simulation_data = [1,2,23,2,3] + + @info plot(simulation_data) + + + +end + +# ╔═╡ 7c7b11a2-69cf-4cd5-b9e5-f2517211579f +md""" +# @bind in logs +""" + +# ╔═╡ 9f99c4aa-c4c9-40f7-aad2-fc74dce84bc2 +begin + + b1 = @bind wowz1 Slider(50:60) + b2 = @bind wowz1 TextField() + + @htl("$(b1)$(b2)") +end + +# ╔═╡ dde4c73d-2577-411f-9e14-57988ddd3498 +wowz1, wowz1 + +# ╔═╡ d48fb1c0-b88a-4a23-8a87-7fdcd74bf3cc +begin + + @info @bind wowz Slider(1:100) + +end + +# ╔═╡ 6355afae-d4ad-40f4-9917-3f228a63ddaa +t2 = collect(1:wowz) + +# ╔═╡ 70fc79bb-6118-4a0d-ac6e-fbdf1ba9722a +let + result = sin.(t2) + @info plot(t2, result) + + + result +end + +# ╔═╡ d1a1bca1-d01a-4722-8bd9-b759b8ef72d4 +md""" +# External logs +""" + +# ╔═╡ 4ca5f24f-3139-4dee-a28a-007c936c7363 +md""" +### Function defined in another cell: +""" + +# ╔═╡ 25bca319-2b63-4013-88be-7607eff3630f +function f(x) + + @warn "x might be too large!" x +end + +# ╔═╡ 37108eb9-77db-49fa-b168-f9c1c25955fa +md""" +### Function defined in another file: +""" + +# ╔═╡ 0bf3e7bd-1da7-441a-9807-6c9473944048 +external_src = let + f = tempname() + code = """ + function g(x) + + @warn "x might be too large!" x + end + """ + write(f, code) + f +end + +# ╔═╡ cd6c50f6-16d6-4a07-8f20-7450392cd643 +function ingredients(path::String) + # this is from the Julia source code (evalfile in base/loading.jl) + # but with the modification that it returns the module instead of the last object + name = Symbol(basename(path)) + m = Module(name) + Core.eval(m, + Expr(:toplevel, + :(eval(x) = $(Expr(:core, :eval))($name, x)), + :(include(x) = $(Expr(:top, :include))($name, x)), + :(include(mapexpr::Function, x) = $(Expr(:top, :include))(mapexpr, $name, x)), + :(include($path)))) + m +end + +# ╔═╡ 9cc753a0-f8be-4045-a432-295a05388a4a +m = ingredients(external_src) + +# ╔═╡ 1a088b03-ac41-440b-8c82-bd5760590665 +m.g(123) + +# ╔═╡ 0c9de395-19a9-4ec3-a918-ea3f9835ef18 + + +# ╔═╡ f017b4d5-38ac-4498-8e58-770337a0d17d +md""" + +# Hello + + +I am a footnote $(@info("Inside text!")), how cool is that! + +But im not working :( +""" + + +# ╔═╡ 9e27dc8c-0a18-4adb-b3b1-9bdd315caaa9 +with_terminal() do + println(123) +end + +# ╔═╡ 51f4dc20-7cf6-4f08-b500-0c71f6ac01b7 + + +# ╔═╡ e68681b0-df0c-4b4d-8304-d600d511cc74 +function f(x,y) + sin(3*sqrt(x^2 + y^2)) < 0.0 +end + +# ╔═╡ 2ade9e4d-11cc-47ae-aaa6-76864757bd21 +f(123) + + + + + + + + +# ╔═╡ f6147e0c-796f-4f5d-b000-93d790683a54 +@info md"# hello" + +# ╔═╡ 755e37af-0f21-4612-8c4c-cc294048b527 +for p in readdir(first(DEPOT_PATH)) + print(p) + print("/") + print("\t\t") + print("(", Base.format_bytes(rand(1:10_000_000)), ")") + println() + print(" ") + print() + println() +end + +# ╔═╡ 05461fd2-a7ce-4ed7-a622-102242547874 +import Logging + +# ╔═╡ 13c5ce42-4eee-480b-b490-c40ef4bc8cb5 +Logging.@logmsg Logging.LogLevel(-100) "asdf" + +# ╔═╡ 3cbaa462-5714-4d7c-83e3-a957763b8d91 +begin + print(123) + @info 123 + @info 123 +end + +# ╔═╡ c50f7178-8c7d-4319-82d9-b9154e8892d9 +for x in 1:20 + @info "This is too long." +end + +# ╔═╡ 988f6343-c1b2-41e2-a3f0-b5eb6653087a +md""" +![](https://cdn.vox-cdn.com/thumbor/sgjCRJzWvyufDoVKCPKPrsyhZoA=/1400x0/filters:no_upscale()/cdn.vox-cdn.com/uploads/chorus_asset/file/10161377/iprimus_180205_2248_0003.jpg) +""" + +# ╔═╡ eb26cb00-1196-41a7-8e81-92641aa8dbd7 +run(`ls -lha $(first(DEPOT_PATH))`) + +# ╔═╡ 1e49c42a-364e-47eb-85d9-42e73fdc2371 +Logging.@logmsg Logging.LogLevel(-10) "asdf" + +# ╔═╡ c07a9c5f-3807-431f-a020-8eb127a226dc +begin + println("Here is some ascii art!") + println() + + @time for y in LinRange(5,-5,21) + for x in LinRange(-5,5,40) + print(f(x,y) ? "X" : " ") + end + println() + end +end + +# ╔═╡ 786b7146-8eab-4390-a746-3ccf25d1c4c8 +for i in 1:10 + @info i + @debug i + sleep(.05) +end + +# ╔═╡ e35e35f4-71c8-4f3b-8c72-4b3ffe4766a3 +@info collect(1:100) + +# ╔═╡ b38ae226-0a6c-49e3-b55d-ebdbf0652842 +Logging.@logmsg Logging.LogLevel(-555) "asdf" + + +# ╔═╡ e5a8e7bd-5734-4254-914d-6f87670bf7d4 +@bind wow html"" + +# ╔═╡ 2883b3d8-fffe-11ea-0a0f-bbd85ec665ea +begin + + wow && @info "a" + wow && @info "b" + wow && @info "c" + wow && @info "d" + + try + sqrt(-1) + catch e + @error "99" exception=(e, catch_backtrace()) + end + nothing +end + +# ╔═╡ 94380ba8-247b-4e9c-9c6b-a40b04e2bcfb +import FileTrees + +# ╔═╡ 7dcf9a68-4a73-4301-a1ed-39963309d028 +t = FileTrees.FileTree(joinpath(first(DEPOT_PATH), "environments")) + +# ╔═╡ 1ea9e96a-ce26-4807-9d80-114638a3952b +FileTrees.children(t) + +# ╔═╡ 7a9c4221-27c7-4195-9946-3a7190dfb07f +FileTrees.load(t) do z + rand() +end + +# ╔═╡ edde2e33-9b83-4502-85d6-13c947589f55 +md"# Logging" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +FileTrees = "72696420-646e-6120-6e77-6f6420746567" +HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c" + +[compat] +FileTrees = "~0.3.4" +HypertextLiteral = "~0.9.4" +Plots = "~1.29.0" +PlutoUI = "~0.7.39" +ProgressLogging = "~0.1.4" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.1.4" + +[[AbstractTrees]] +git-tree-sha1 = "03e0550477d86222521d254b741d470ba17ea0b5" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.3.4" + +[[Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.3.3" + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + +[[ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "9489214b993cd42d17f44c36e359bf6a7c919abf" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.15.0" + +[[ChangesOfVariables]] +deps = ["ChainRulesCore", "LinearAlgebra", "Test"] +git-tree-sha1 = "1e315e3f4b0b7ce40feded39c73049692126cf53" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.3" + +[[ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "7297381ccb5df764549818d9a7d57e45f1057d30" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.18.0" + +[[ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "0f4e115f6f34bbe43c19751c90a38b2f380637b9" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.3" + +[[ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] +git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.9.9" + +[[Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + +[[Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "87e84b2293559571802f97dd9c94cfd6be52c5e5" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "3.44.0" + +[[CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" + +[[ContextVariablesX]] +deps = ["Compat", "Logging", "UUIDs"] +git-tree-sha1 = "8ccaa8c655bc1b83d2da4d569c9b28254ababd6e" +uuid = "6add18c4-b38d-439d-96f6-d6bc489c04c5" +version = "0.1.2" + +[[Contour]] +deps = ["StaticArrays"] +git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.5.7" + +[[Dagger]] +deps = ["Colors", "ContextVariablesX", "DataAPI", "Distributed", "LinearAlgebra", "MemPool", "Profile", "Random", "Requires", "SentinelArrays", "Serialization", "SharedArrays", "SparseArrays", "Statistics", "StatsBase", "TableOperations", "Tables", "UUIDs"] +git-tree-sha1 = "df440c9b3565b897ed59697e43a1125c19ce4eb3" +uuid = "d58978e5-989f-55fb-8d15-ea34adc7bf54" +version = "0.14.4" + +[[DataAPI]] +git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.10.0" + +[[DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.13" + +[[DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.8.6" + +[[Downloads]] +deps = ["ArgTools", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" + +[[EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.2.3+0" + +[[Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.8+0" + +[[FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.0+0" + +[[FilePathsBase]] +deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] +git-tree-sha1 = "129b104185df66e408edd6625d480b7f9e9823a0" +uuid = "48062228-2e41-5def-b9a4-89aafe57970f" +version = "0.9.18" + +[[FileTrees]] +deps = ["AbstractTrees", "Dagger", "FilePathsBase", "Glob"] +git-tree-sha1 = "a2171ed4f59223c729faa42dc560ff65bcd0f902" +uuid = "72696420-646e-6120-6e77-6f6420746567" +version = "0.3.4" + +[[FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + +[[Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.6+0" + +[[GR]] +deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] +git-tree-sha1 = "b316fd18f5bc025fedcb708332aecb3e13b9b453" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.64.3" + +[[GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "1e5490a51b4e9d07e8b04836f6008f46b48aaa87" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.64.3+0" + +[[GeometryBasics]] +deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "83ea630384a13fc4f002b77690bc0afeb4255ac9" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.2" + +[[Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.68.3+2" + +[[Glob]] +git-tree-sha1 = "4df9f7e06108728ebf00a0a11edee4b29a482bb2" +uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" +version = "1.3.0" + +[[Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[HTTP]] +deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] +git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "0.9.17" + +[[HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.4" + +[[HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.4" + +[[IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.2" + +[[IniFile]] +git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625" +uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" +version = "0.5.1" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "336cc738f03e069ef2cac55a104eb823455dca75" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.4" + +[[IrrationalConstants]] +git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.1.1" + +[[IterTools]] +git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.4.0" + +[[IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.3" + +[[JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.2+0" + +[[LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[LERC_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +uuid = "88015f11-f218-50d7-93a8-a6af411a945d" +version = "3.0.0+1" + +[[LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + +[[Latexify]] +deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] +git-tree-sha1 = "46a39b9c58749eefb5f2dc1178cb8fab5332b1ab" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.15.15" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" + +[[LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.3.0+3" + +[[Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+1" + +[[Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "c9551dd26e31ab17b86cbd00c2ede019c08758eb" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.3.0+1" + +[[Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "09e4b894ce6a976c354a69041a04748180d43637" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.15" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.9" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] +git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.0.3" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" + +[[Measures]] +git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.1" + +[[MemPool]] +deps = ["DataStructures", "Distributed", "Mmap", "Random", "Serialization", "Sockets"] +git-tree-sha1 = "b0bbcf9346ef0a60d2a63069dfc8b4d51d682153" +uuid = "f9f48841-c794-520a-933b-121f7ba6ed94" +version = "0.3.9" + +[[Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.2" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" + +[[NaNMath]] +git-tree-sha1 = "737a5957f387b17e74d4ad2f440eb330b39a62c5" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.0" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + +[[Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" + +[[OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" + +[[OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ab05aa4cc89736e95915b01e7279e61b1bfe33b8" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.14+0" + +[[OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[PCRE_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" +uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" +version = "8.44.0+0" + +[[Parsers]] +deps = ["Dates"] +git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.3.1" + +[[Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[PlotThemes]] +deps = ["PlotUtils", "Statistics"] +git-tree-sha1 = "8162b2f8547bc23876edd0c5181b27702ae58dce" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "3.0.0" + +[[PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "bb16469fd5224100e422f0b027d26c5a25de1200" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.2.0" + +[[Plots]] +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] +git-tree-sha1 = "d457f881ea56bbfa18222642de51e0abf67b9027" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.29.0" + +[[PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"] +git-tree-sha1 = "8d1f54886b9037091edf146b517989fc4a09efec" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.39" + +[[Preferences]] +deps = ["TOML"] +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.3.0" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[ProgressLogging]] +deps = ["Logging", "SHA", "UUIDs"] +git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" +uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" +version = "0.1.4" + +[[Qt5Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] +git-tree-sha1 = "c6c0f690d0cc7caddb74cef7aa847b824a16b256" +uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" +version = "5.15.3+1" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[RecipesBase]] +git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.2.1" + +[[RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] +git-tree-sha1 = "dc1e451e15d90347a7decc4221842a022b011714" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.5.2" + +[[Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "0.1.3" + +[[Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Scratch]] +deps = ["Dates"] +git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.0" + +[[SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "6a2f7d70512d205ca8c7ee31bfa9f142fe74310c" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.3.12" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "bc40f042cfcc56230f781d92db71f0e21496dffd" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.1.5" + +[[StaticArrays]] +deps = ["LinearAlgebra", "Random", "Statistics"] +git-tree-sha1 = "cd56bf18ed715e8b09f06ef8c6b781e6cdc49911" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.4.4" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "c82aaa13b44ea00134f8c9c89819477bd3986ecd" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.3.0" + +[[StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "8977b17906b0a1cc74ab2e3a05faa16cf08a8291" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.16" + +[[StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] +git-tree-sha1 = "9abba8f8fb8458e9adf07c8a2377a070674a24f1" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.8" + +[[TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[[TableOperations]] +deps = ["SentinelArrays", "Tables", "Test"] +git-tree-sha1 = "e383c87cf2a1dc41fa30c093b2a19877c83e1bc1" +uuid = "ab02a1b2-a7df-11e8-156e-fb1833f50b87" +version = "1.2.0" + +[[TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] +git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.7.0" + +[[Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" + +[[TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + +[[Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[Tricks]] +git-tree-sha1 = "6bac775f2d42a611cdfcd1fb217ee719630c4175" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.6" + +[[URIs]] +git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.3.0" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[Unzip]] +git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.1.2" + +[[Wayland_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.19.0+0" + +[[Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.25.0+0" + +[[XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.12+0" + +[[XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.0+4" + +[[Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.2+4" + +[[Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.27.0+4" + +[[Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" + +[[Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.2+0" + +[[libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" + +[[libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" + +[[p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" + +[[x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" + +[[xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "0.9.1+5" +""" + +# ╔═╡ Cell order: +# ╠═24c5d164-b618-4e05-abe9-62d129c0b55f +# ╠═ecc81850-8d79-4b6f-83c8-f2c9bcda23b3 +# ╠═2e7dac1a-ef0d-4b76-a33a-9510b064c25c +# ╠═3599eb82-0003-11eb-3814-dfd0f5737846 +# ╠═eebe1108-588a-4e81-a69c-f2c21e9cbbaa +# ╠═54d5c34e-63b5-4b52-91fe-a5fd1b729182 +# ╠═0248c2de-7edf-4ff6-a450-9f6d79f8966d +# ╟─196080df-e8c0-4120-a97c-443cf66295ff +# ╠═a22411c8-24e0-4a80-9b91-bc1f0999cc3c +# ╠═091d33fe-fffe-11ea-131f-01f4248b30ea +# ╠═5f8496cb-d29e-4c4c-b378-1173242c7a78 +# ╠═a93ac790-7a04-418d-8117-01f01e4608c8 +# ╟─88f87c39-89ef-4492-92ae-c6cd33699c59 +# ╠═2d01cdaa-fffe-11ea-09f5-63527a1b0f87 +# ╠═2883b3d8-fffe-11ea-0a0f-bbd85ec665ea +# ╠═2fbbb413-213f-4556-b5f9-df7cf6331451 +# ╠═449541e2-351d-41d2-9623-34d243fe6a97 +# ╠═0e823733-4668-47db-8d17-f079b7ed8c75 +# ╠═dfcf652e-ca15-43ad-8307-d40367de6986 +# ╠═5d023cd2-4fe6-4bd0-9a54-7512f52b7916 +# ╟─e5f2703b-198c-4926-867e-7f914fa10253 +# ╠═b52f7e61-c6b5-46ae-8025-d2b4649fed99 +# ╠═52b8c0be-64f7-4950-ab4a-983c6fa50d1a +# ╠═504dfdc1-41da-4fcb-ba8e-aa69643d57a1 +# ╠═6a7824d0-06e4-4569-9fa8-b9884d299f80 +# ╟─7c7b11a2-69cf-4cd5-b9e5-f2517211579f +# ╠═10c02645-cb3b-42be-8df1-679e8fb05382 +# ╠═9f99c4aa-c4c9-40f7-aad2-fc74dce84bc2 +# ╠═dde4c73d-2577-411f-9e14-57988ddd3498 +# ╠═d48fb1c0-b88a-4a23-8a87-7fdcd74bf3cc +# ╠═890b8d1d-1bf0-4497-ac64-9852f68e1577 +# ╠═6355afae-d4ad-40f4-9917-3f228a63ddaa +# ╠═70fc79bb-6118-4a0d-ac6e-fbdf1ba9722a +# ╟─d1a1bca1-d01a-4722-8bd9-b759b8ef72d4 +# ╟─4ca5f24f-3139-4dee-a28a-007c936c7363 +# ╠═25bca319-2b63-4013-88be-7607eff3630f +# ╠═2ade9e4d-11cc-47ae-aaa6-76864757bd21 +# ╟─37108eb9-77db-49fa-b168-f9c1c25955fa +# ╠═0bf3e7bd-1da7-441a-9807-6c9473944048 +# ╟─cd6c50f6-16d6-4a07-8f20-7450392cd643 +# ╠═9cc753a0-f8be-4045-a432-295a05388a4a +# ╠═1a088b03-ac41-440b-8c82-bd5760590665 +# ╠═0c9de395-19a9-4ec3-a918-ea3f9835ef18 +# ╠═f017b4d5-38ac-4498-8e58-770337a0d17d +# ╠═9e27dc8c-0a18-4adb-b3b1-9bdd315caaa9 +# ╠═51f4dc20-7cf6-4f08-b500-0c71f6ac01b7 +# ╠═e68681b0-df0c-4b4d-8304-d600d511cc74 +# ╠═f6147e0c-796f-4f5d-b000-93d790683a54 +# ╠═755e37af-0f21-4612-8c4c-cc294048b527 +# ╠═05461fd2-a7ce-4ed7-a622-102242547874 +# ╠═1ea9e96a-ce26-4807-9d80-114638a3952b +# ╠═13c5ce42-4eee-480b-b490-c40ef4bc8cb5 +# ╠═3cbaa462-5714-4d7c-83e3-a957763b8d91 +# ╠═c50f7178-8c7d-4319-82d9-b9154e8892d9 +# ╠═988f6343-c1b2-41e2-a3f0-b5eb6653087a +# ╠═eb26cb00-1196-41a7-8e81-92641aa8dbd7 +# ╠═1e49c42a-364e-47eb-85d9-42e73fdc2371 +# ╠═c07a9c5f-3807-431f-a020-8eb127a226dc +# ╠═7a9c4221-27c7-4195-9946-3a7190dfb07f +# ╠═786b7146-8eab-4390-a746-3ccf25d1c4c8 +# ╠═e35e35f4-71c8-4f3b-8c72-4b3ffe4766a3 +# ╠═b38ae226-0a6c-49e3-b55d-ebdbf0652842 +# ╠═e5a8e7bd-5734-4254-914d-6f87670bf7d4 +# ╠═94380ba8-247b-4e9c-9c6b-a40b04e2bcfb +# ╠═7dcf9a68-4a73-4301-a1ed-39963309d028 +# ╠═edde2e33-9b83-4502-85d6-13c947589f55 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 \ No newline at end of file diff --git a/sample/test_pkg_bubble.jl b/sample/test_pkg_bubble.jl index 54406dd1d6..a180521550 100644 --- a/sample/test_pkg_bubble.jl +++ b/sample/test_pkg_bubble.jl @@ -1,57 +1,165 @@ ### A Pluto.jl notebook ### -# v0.16.4 +# v0.17.5 using Markdown using InteractiveUtils -# ╔═╡ f7dfc33e-6ff8-44d6-a88e-bea5834a9d27 -import A1 -using A2 +# ╔═╡ f16ef748-7c86-11ec-10a5-830de8dd2a2e +md""" +# Package Managment AST tests -# ╔═╡ 360ee541-cbc4-4df6-bdc5-ea23fe08abdd -import A1, B1, .C1, D1.E1 -using A2, B2, .C2, D2.E2 +- `Random` or `Downloads` indicates the name should be parsed as package name +- Single letter names are for everything that shouldn't be parsed +- Random `Base` thrown in to make sure it is not parsed +""" -# ╔═╡ 8a4eff2d-5dbc-4056-a81b-da0618503467 -import A1: b1, c1 -using A2: b2, c2 +# ╔═╡ e99b72b2-8939-430c-b8b3-25155559e7dc +macro >(expr) end -# ╔═╡ 393a7816-0fa0-4f74-8fe7-c8d8d8c7e868 -import A1.B1: b1, c1 -using A2.B2: b2, c2 +# ╔═╡ e7f324d7-e4b0-498a-a8a2-f94f52a9453d +@> using Random -# ╔═╡ c1b5da89-c9a3-439c-8bee-2a8690265796 -import .A1 -using .A2 +# ╔═╡ fb917588-1499-433b-aeba-e6833346c968 +@> using Random: a as x -# ╔═╡ daf52b3f-513c-45de-a232-bda50e45b326 -import .A1: x1 -using .A2: x2 +# ╔═╡ d4f1ec8b-7597-45bf-9cea-4770802d516b +@> using Random.A.B -# ╔═╡ 6a90ece9-e7ad-404e-a3b0-4d484821f461 -import ..A1 -using ..A2 +# ╔═╡ a68c8859-d7dd-4e8d-9996-f81216b84355 +@> using Random.B.C: X -# ╔═╡ 4206dd87-a9e9-4f2c-865f-bec68d199b55 -import A1.B1 -using A2.B2 +# ╔═╡ 589ee4e7-8fec-424a-82f7-cf0a700bf20a +@> using .A.B.C: X -# ╔═╡ eb7ba436-d23b-4e97-af92-81271fa76989 -import A1.B1.C1 -using A2.B2.C2 +# ╔═╡ 5e9f4f30-39f5-4c1d-b94d-4d937d37c47f +@> using Random.B.C, Downloads.K -# ╔═╡ 4f1d3da9-370c-42c2-9d17-a3caffca638d -import A1.B1.C1.D1 -using A2.B2.C2.D2 +# ╔═╡ 55449e27-c8db-4593-bc3b-0011179c6b20 +@> import Random + +# ╔═╡ 91b12b1c-1590-421e-8904-6b728bbf004d +@> import Base + +# ╔═╡ 9d42b339-f64d-4ce8-b765-0ebd060dec55 +@> import Random: a, b + +# ╔═╡ d555a75d-eed6-4cb8-82a0-53f84ceb982a +@> import Random: A as Z + +# ╔═╡ db8041c4-645c-4af9-8d33-aa4dfd45ea5f +@> import Random as X, Downloads as Y, .A + +# ╔═╡ 42a5bed8-c761-4e9d-907d-25d49157647b +@> import Random, Base, .A as X + +# ╔═╡ 7c4496e7-5b21-4748-9877-bff4a7ae5752 +@> import .A: X, Y + +# ╔═╡ 04faa311-541d-44c7-a189-e390c5cbdef9 +@> import .A + +# ╔═╡ 3490d653-47da-4cea-939e-076ad38558d7 +@> import .A as X, ..A as Y + +# ╔═╡ 1fc087ca-70b3-43d2-8793-70131227329f +@> import ..A + +# ╔═╡ 7150f6b7-aa4f-44bf-a751-9c34c4a1c981 +md"---" + +# ╔═╡ b371f04d-0a89-4aa9-a03a-7c903270fd20 +md"---" + +# ╔═╡ 3749489b-49d3-4187-a2f6-1dddc0e97f92 +@> import Random as + +# ╔═╡ ed56bd75-8d7d-45ec-a3f9-c440141f7633 +@> import NotExisting + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Downloads]] +deps = ["ArgTools", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +""" # ╔═╡ Cell order: -# ╠═f7dfc33e-6ff8-44d6-a88e-bea5834a9d27 -# ╠═360ee541-cbc4-4df6-bdc5-ea23fe08abdd -# ╠═8a4eff2d-5dbc-4056-a81b-da0618503467 -# ╠═393a7816-0fa0-4f74-8fe7-c8d8d8c7e868 -# ╠═c1b5da89-c9a3-439c-8bee-2a8690265796 -# ╠═daf52b3f-513c-45de-a232-bda50e45b326 -# ╠═6a90ece9-e7ad-404e-a3b0-4d484821f461 -# ╠═4206dd87-a9e9-4f2c-865f-bec68d199b55 -# ╠═eb7ba436-d23b-4e97-af92-81271fa76989 -# ╠═4f1d3da9-370c-42c2-9d17-a3caffca638d +# ╟─f16ef748-7c86-11ec-10a5-830de8dd2a2e +# ╟─e99b72b2-8939-430c-b8b3-25155559e7dc +# ╠═55449e27-c8db-4593-bc3b-0011179c6b20 +# ╠═9d42b339-f64d-4ce8-b765-0ebd060dec55 +# ╠═d555a75d-eed6-4cb8-82a0-53f84ceb982a +# ╠═db8041c4-645c-4af9-8d33-aa4dfd45ea5f +# ╠═42a5bed8-c761-4e9d-907d-25d49157647b +# ╠═7c4496e7-5b21-4748-9877-bff4a7ae5752 +# ╠═04faa311-541d-44c7-a189-e390c5cbdef9 +# ╠═3490d653-47da-4cea-939e-076ad38558d7 +# ╠═1fc087ca-70b3-43d2-8793-70131227329f +# ╟─7150f6b7-aa4f-44bf-a751-9c34c4a1c981 +# ╠═e7f324d7-e4b0-498a-a8a2-f94f52a9453d +# ╠═fb917588-1499-433b-aeba-e6833346c968 +# ╠═d4f1ec8b-7597-45bf-9cea-4770802d516b +# ╠═a68c8859-d7dd-4e8d-9996-f81216b84355 +# ╠═589ee4e7-8fec-424a-82f7-cf0a700bf20a +# ╠═5e9f4f30-39f5-4c1d-b94d-4d937d37c47f +# ╟─b371f04d-0a89-4aa9-a03a-7c903270fd20 +# ╠═3749489b-49d3-4187-a2f6-1dddc0e97f92 +# ╠═ed56bd75-8d7d-45ec-a3f9-c440141f7633 +# ╠═91b12b1c-1590-421e-8904-6b728bbf004d +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 \ No newline at end of file diff --git a/src/Configuration.jl b/src/Configuration.jl index b3db3ebabb..bc0dc8104c 100644 --- a/src/Configuration.jl +++ b/src/Configuration.jl @@ -14,56 +14,103 @@ using Configurations # https://github.com/Roger-luo/Configurations.jl import ..Pluto: tamepath -# This can't be a simple `const` because this would hard-code it into the precompile image. -const notebook_path_suggestion_ref = Ref{Union{Nothing,String}}(nothing) +safepwd() = try + pwd() +catch e + @warn "pwd() failure" exception=(e, catch_backtrace()) + homedir() +end + +# Using a ref to avoid fixing the pwd() output during the compilation phase. We don't want this value to be baked into the sysimage, because it depends on the `pwd()`. We do want to cache it, because the pwd might change while Pluto is running. +const pwd_ref = Ref{String}() function notebook_path_suggestion() - if notebook_path_suggestion_ref[] === nothing - notebook_path_suggestion_ref[] = let - preferred_dir = startswith(Sys.BINDIR, pwd()) ? homedir() : pwd() - joinpath(preferred_dir, "") # so that it ends with / or \ - end + pwd_val = if isassigned(pwd_ref) + pwd_ref[] + else + safepwd() end - notebook_path_suggestion_ref[] + preferred_dir = startswith(Sys.BINDIR, pwd_val) ? homedir() : pwd_val + # so that it ends with / or \ + string(joinpath(preferred_dir, "")) +end + +function __init__() + pwd_ref[] = safepwd() end +const ROOT_URL_DEFAULT = nothing +const BASE_URL_DEFAULT = "/" +const HOST_DEFAULT = "127.0.0.1" +const PORT_DEFAULT = nothing +const PORT_HINT_DEFAULT = 1234 +const LAUNCH_BROWSER_DEFAULT = true +const DISMISS_UPDATE_NOTIFICATION_DEFAULT = false +const SHOW_FILE_SYSTEM_DEFAULT = true +const ENABLE_PACKAGE_AUTHOR_FEATURES_DEFAULT = true +const DISABLE_WRITING_NOTEBOOK_FILES_DEFAULT = false +const AUTO_RELOAD_FROM_FILE_DEFAULT = false +const AUTO_RELOAD_FROM_FILE_COOLDOWN_DEFAULT = 0.4 +const AUTO_RELOAD_FROM_FILE_IGNORE_PKG_DEFAULT = false +const NOTEBOOK_DEFAULT = nothing +const INIT_WITH_FILE_VIEWER_DEFAULT = false +const SIMULATED_LAG_DEFAULT = 0.0 +const SIMULATED_PKG_LAG_DEFAULT = 0.0 +const INJECTED_JAVASCRIPT_DATA_URL_DEFAULT = "data:text/javascript;base64," +const ON_EVENT_DEFAULT = function(a) #= @info "$(typeof(a))" =# end + """ ServerOptions([; kwargs...]) The HTTP server options. See [`SecurityOptions`](@ref) for additional settings. -# Arguments +# Keyword arguments -- `root_url::Union{Nothing,String} = nothing` -- `host::String = "127.0.0.1"` -- `port::Union{Nothing,Integer} = nothing` -- `launch_browser::Bool = true` -- `dismiss_update_notification::Bool = false` -- `show_file_system::Bool = true` +- `host::String = "$HOST_DEFAULT"` Set to `"127.0.0.1"` (default) to run on *localhost*, which makes the server available to your computer and the local network (LAN). Set to `"0.0.0.0"` to make the server available to the entire network (internet). +- `port::Union{Nothing,Integer} = $PORT_DEFAULT` When specified, this port will be used for the server. +- `port_hint::Integer = $PORT_HINT_DEFAULT` If the other setting `port` is not specified, then this setting (`port_hint`) will be used as the starting point in finding an available port to run the server on. +- `launch_browser::Bool = $LAUNCH_BROWSER_DEFAULT` +- `dismiss_update_notification::Bool = $DISMISS_UPDATE_NOTIFICATION_DEFAULT` If `false`, the Pluto frontend will check the Pluto.jl github releases for any new recommended updates, and show a notification if there are any. If `true`, this is disabled. +- `show_file_system::Bool = $SHOW_FILE_SYSTEM_DEFAULT` - `notebook_path_suggestion::String = notebook_path_suggestion()` -- `disable_writing_notebook_files::Bool = false` -- `auto_reload_from_file::Bool = false` Watch notebook files for outside changes and update running notebook state automatically -- `auto_reload_from_file_cooldown::Real = 0.5` Experimental, will be removed -- `auto_reload_from_file_ignore_pkg::Bool = false` Experimental flag, will be removed -- `notebook::Union{Nothing,String} = nothing` Optional path of notebook to launch at start -- `simulated_lag::Real=0.0` (internal) Extra lag to add to our server responses. Will be multiplied by `0.5 + rand()`. +- `disable_writing_notebook_files::Bool = $DISABLE_WRITING_NOTEBOOK_FILES_DEFAULT` +- `auto_reload_from_file::Bool = $AUTO_RELOAD_FROM_FILE_DEFAULT` Watch notebook files for outside changes and update running notebook state automatically +- `auto_reload_from_file_cooldown::Real = $AUTO_RELOAD_FROM_FILE_COOLDOWN_DEFAULT` Experimental, will be removed +- `auto_reload_from_file_ignore_pkg::Bool = $AUTO_RELOAD_FROM_FILE_IGNORE_PKG_DEFAULT` Experimental flag, will be removed +- `notebook::Union{Nothing,String} = $NOTEBOOK_DEFAULT` Optional path of notebook to launch at start +- `init_with_file_viewer::Bool = $INIT_WITH_FILE_VIEWER_DEFAULT` +- `simulated_lag::Real=$SIMULATED_LAG_DEFAULT` (internal) Extra lag to add to our server responses. Will be multiplied by `0.5 + rand()`. +- `simulated_pkg_lag::Real=$SIMULATED_PKG_LAG_DEFAULT` (internal) Extra lag to add to operations done by Pluto's package manager. Will be multiplied by `0.5 + rand()`. +- `injected_javascript_data_url::String = "$INJECTED_JAVASCRIPT_DATA_URL_DEFAULT"` (internal) Optional javascript injectables to the front-end. Can be used to customize the editor, but this API is not meant for general use yet. +- `on_event::Function = $ON_EVENT_DEFAULT` +- `root_url::Union{Nothing,String} = $ROOT_URL_DEFAULT` This setting is used to specify the root URL of the Pluto server, but this setting is *only* used to customize the launch message (*"Go to http://localhost:1234/ in your browser"*). You can probably ignore this and use `base_url` instead. +- `base_url::String = "$BASE_URL_DEFAULT"` This (advanced) setting is used to specify a subpath at which the Pluto server will run, it should be a path starting and ending with a '/'. E.g. with `base_url = "/hello/world/"`, the server will run at `http://localhost:1234/hello/world/`, and you edit a notebook at `http://localhost:1234/hello/world/edit?id=...`. """ @option mutable struct ServerOptions - root_url::Union{Nothing,String} = nothing - host::String = "127.0.0.1" - port::Union{Nothing,Integer} = nothing - launch_browser::Bool = true - dismiss_update_notification::Bool = false - show_file_system::Bool = true + root_url::Union{Nothing,String} = ROOT_URL_DEFAULT + base_url::String = BASE_URL_DEFAULT + host::String = HOST_DEFAULT + port::Union{Nothing,Integer} = PORT_DEFAULT + port_hint::Integer = PORT_HINT_DEFAULT + launch_browser::Bool = LAUNCH_BROWSER_DEFAULT + dismiss_update_notification::Bool = DISMISS_UPDATE_NOTIFICATION_DEFAULT + show_file_system::Bool = SHOW_FILE_SYSTEM_DEFAULT notebook_path_suggestion::String = notebook_path_suggestion() - disable_writing_notebook_files::Bool = false - auto_reload_from_file::Bool = false - auto_reload_from_file_cooldown::Real = 0.4 - auto_reload_from_file_ignore_pkg::Bool = false - notebook::Union{Nothing,String,Vector{<:String}} = nothing - init_with_file_viewer::Bool = false - simulated_lag::Real = 0.0 + disable_writing_notebook_files::Bool = DISABLE_WRITING_NOTEBOOK_FILES_DEFAULT + auto_reload_from_file::Bool = AUTO_RELOAD_FROM_FILE_DEFAULT + auto_reload_from_file_cooldown::Real = AUTO_RELOAD_FROM_FILE_COOLDOWN_DEFAULT + auto_reload_from_file_ignore_pkg::Bool = AUTO_RELOAD_FROM_FILE_IGNORE_PKG_DEFAULT + notebook::Union{Nothing,String,Vector{<:String}} = NOTEBOOK_DEFAULT + init_with_file_viewer::Bool = INIT_WITH_FILE_VIEWER_DEFAULT + simulated_lag::Real = SIMULATED_LAG_DEFAULT + simulated_pkg_lag::Real = SIMULATED_PKG_LAG_DEFAULT + injected_javascript_data_url::String = INJECTED_JAVASCRIPT_DATA_URL_DEFAULT + on_event::Function = ON_EVENT_DEFAULT end +const REQUIRE_SECRET_FOR_OPEN_LINKS_DEFAULT = true +const REQUIRE_SECRET_FOR_ACCESS_DEFAULT = true +const WARN_ABOUT_UNTRUSTED_CODE_DEFAULT = true + """ SecurityOptions([; kwargs...]) @@ -71,40 +118,101 @@ Security settings for the HTTP server. # Arguments -- `require_secret_for_open_links::Bool = true` +- `require_secret_for_open_links::Bool = $REQUIRE_SECRET_FOR_OPEN_LINKS_DEFAULT` Whether the links `http://localhost:1234/open?path=/a/b/c.jl` and `http://localhost:1234/open?url=http://www.a.b/c.jl` should be protected. Use `true` for almost every setup. Only use `false` if Pluto is running in a safe container (like mybinder.org), where arbitrary code execution is not a problem. -- `require_secret_for_access::Bool = true` +- `require_secret_for_access::Bool = $REQUIRE_SECRET_FOR_ACCESS_DEFAULT` - If false, you do not need to use a `secret` in the URL to access Pluto: you will be authenticated by visiting `http://localhost:1234/` in your browser. An authentication cookie is still used for access (to prevent XSS and deceptive links or an img src to `http://localhost:1234/open?url=badpeople.org/script.jl`), and is set automatically, but this request to `/` is protected by cross-origin policy. + If `false`, you do not need to use a `secret` in the URL to access Pluto: you will be authenticated by visiting `http://localhost:1234/` in your browser. An authentication cookie is still used for access (to prevent XSS and deceptive links or an img src to `http://localhost:1234/open?url=badpeople.org/script.jl`), and is set automatically, but this request to `/` is protected by cross-origin policy. Use `true` on a computer used by multiple people simultaneously. Only use `false` if necessary. +- `warn_about_untrusted_code::Bool = $WARN_ABOUT_UNTRUSTED_CODE_DEFAULT` + + Should the Pluto GUI show warning messages about executing code from an unknown source, e.g. when opening a notebook from a URL? When `false`, notebooks will still open in Safe mode, but there is no scary message when you run it. + **Leave these options on `true` for the most secure setup.** Note that Pluto is quickly evolving software, maintained by designers, educators and enthusiasts — not security experts. If security is a serious concern for your application, then we recommend running Pluto inside a container and verifying the relevant security aspects of Pluto yourself. """ @option mutable struct SecurityOptions - require_secret_for_open_links::Bool = true - require_secret_for_access::Bool = true + require_secret_for_open_links::Bool = REQUIRE_SECRET_FOR_OPEN_LINKS_DEFAULT + require_secret_for_access::Bool = REQUIRE_SECRET_FOR_ACCESS_DEFAULT + warn_about_untrusted_code::Bool = WARN_ABOUT_UNTRUSTED_CODE_DEFAULT end +const RUN_NOTEBOOK_ON_LOAD_DEFAULT = true +const WORKSPACE_USE_DISTRIBUTED_DEFAULT = true +const WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT = nothing +const LAZY_WORKSPACE_CREATION_DEFAULT = false +const CAPTURE_STDOUT_DEFAULT = true +const WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT = nothing + """ EvaluationOptions([; kwargs...]) -Options to change Pluto's evaluation behaviour during internal testing. These options are not intended to be changed during normal use. +Options to change Pluto's evaluation behaviour during internal testing and by downstream packages. +These options are not intended to be changed during normal use. -- `run_notebook_on_load::Bool = true` -- `workspace_use_distributed::Bool = true` -- `lazy_workspace_creation::Bool = false` +- `run_notebook_on_load::Bool = $RUN_NOTEBOOK_ON_LOAD_DEFAULT` When running a notebook (not in Safe mode), should all cells evaluate immediately? Warning: this is only for internal testing, and using it will lead to unexpected behaviour and hard-to-reproduce notebooks. It's not the Pluto way! +- `workspace_use_distributed::Bool = $WORKSPACE_USE_DISTRIBUTED_DEFAULT` Whether to start notebooks in a separate process. +- `workspace_use_distributed_stdlib::Bool? = $WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT` Should we use the Distributed stdlib to run processes? Distributed will be replaced by Malt.jl, you can use this option to already get the old behaviour. `nothing` means: determine automatically (which is currently `false` on Windows, `true` otherwise). +- `lazy_workspace_creation::Bool = $LAZY_WORKSPACE_CREATION_DEFAULT` +- `capture_stdout::Bool = $CAPTURE_STDOUT_DEFAULT` +- `workspace_custom_startup_expr::Union{Nothing,String} = $WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT` An expression to be evaluated in the workspace process before running notebook code. """ @option mutable struct EvaluationOptions - run_notebook_on_load::Bool = true - workspace_use_distributed::Bool = true - lazy_workspace_creation::Bool = false + run_notebook_on_load::Bool = RUN_NOTEBOOK_ON_LOAD_DEFAULT + workspace_use_distributed::Bool = WORKSPACE_USE_DISTRIBUTED_DEFAULT + workspace_use_distributed_stdlib::Union{Bool,Nothing} = WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT + lazy_workspace_creation::Bool = LAZY_WORKSPACE_CREATION_DEFAULT + capture_stdout::Bool = CAPTURE_STDOUT_DEFAULT + workspace_custom_startup_expr::Union{Nothing,String} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT +end + +const COMPILE_DEFAULT = nothing +const PKGIMAGES_DEFAULT = nothing +const COMPILED_MODULES_DEFAULT = nothing +const SYSIMAGE_DEFAULT = nothing +const SYSIMAGE_NATIVE_CODE_DEFAULT = nothing +const BANNER_DEFAULT = nothing +const DEPWARN_DEFAULT = nothing +const OPTIMIZE_DEFAULT = nothing +const MIN_OPTLEVEL_DEFAULT = nothing +const INLINE_DEFAULT = nothing +const CHECK_BOUNDS_DEFAULT = nothing +const MATH_MODE_DEFAULT = nothing +const STARTUP_FILE_DEFAULT = "no" +const HISTORY_FILE_DEFAULT = "no" + +function roughly_the_number_of_physical_cpu_cores() + # https://gist.github.com/fonsp/738fe244719cae820245aa479e7b4a8d + threads = Sys.CPU_THREADS + num_threads_is_maybe_doubled_for_marketing = Sys.ARCH === :x86_64 + + if threads == 1 + 1 + elseif threads == 2 || threads == 3 + 2 + elseif num_threads_is_maybe_doubled_for_marketing + # This includes: + # - intel hyperthreading + # - Apple ARM efficiency cores included in the count (when running the x86 executable) + threads ÷ 2 + else + threads + end +end + +function default_number_of_threads() + env_value = get(ENV, "JULIA_NUM_THREADS", "") + + all(isspace, env_value) ? + roughly_the_number_of_physical_cpu_cores() : + env_value end """ @@ -113,50 +221,48 @@ end These options will be passed as command line argument to newly launched processes. See [the Julia documentation on command-line options](https://docs.julialang.org/en/v1/manual/command-line-options/). # Arguments -- `compile::Union{Nothing,String} = nothing` -- `sysimage::Union{Nothing,String} = nothing` -- `banner::Union{Nothing,String} = nothing` -- `optimize::Union{Nothing,Int} = nothing` -- `math_mode::Union{Nothing,String} = nothing` -- `startup_file::Union{Nothing,String} = "no"` -- `history_file::Union{Nothing,String} = "no"` +- `compile::Union{Nothing,String} = $COMPILE_DEFAULT` +- `pkgimages::Union{Nothing,String} = $PKGIMAGES_DEFAULT` +- `compiled_modules::Union{Nothing,String} = $COMPILED_MODULES_DEFAULT` +- `sysimage::Union{Nothing,String} = $SYSIMAGE_DEFAULT` +- `sysimage_native_code::Union{Nothing,String} = $SYSIMAGE_NATIVE_CODE_DEFAULT` +- `banner::Union{Nothing,String} = $BANNER_DEFAULT` +- `depwarn::Union{Nothing,String} = $DEPWARN_DEFAULT` +- `optimize::Union{Nothing,Int} = $OPTIMIZE_DEFAULT` +- `min_optlevel::Union{Nothing,Int} = $MIN_OPTLEVEL_DEFAULT` +- `inline::Union{Nothing,String} = $INLINE_DEFAULT` +- `check_bounds::Union{Nothing,String} = $CHECK_BOUNDS_DEFAULT` +- `math_mode::Union{Nothing,String} = $MATH_MODE_DEFAULT` +- `startup_file::Union{Nothing,String} = "$STARTUP_FILE_DEFAULT"` By default, the startup file isn't loaded in notebooks. +- `history_file::Union{Nothing,String} = "$HISTORY_FILE_DEFAULT"` By default, the history isn't loaded in notebooks. - `threads::Union{Nothing,String,Int} = default_number_of_threads()` """ @option mutable struct CompilerOptions - compile::Union{Nothing,String} = nothing - sysimage::Union{Nothing,String} = nothing - banner::Union{Nothing,String} = nothing - optimize::Union{Nothing,Int} = nothing - math_mode::Union{Nothing,String} = nothing + compile::Union{Nothing,String} = COMPILE_DEFAULT + pkgimages::Union{Nothing,String} = PKGIMAGES_DEFAULT + compiled_modules::Union{Nothing,String} = COMPILED_MODULES_DEFAULT + + sysimage::Union{Nothing,String} = SYSIMAGE_DEFAULT + sysimage_native_code::Union{Nothing,String} = SYSIMAGE_NATIVE_CODE_DEFAULT + + banner::Union{Nothing,String} = BANNER_DEFAULT + depwarn::Union{Nothing,String} = DEPWARN_DEFAULT + + optimize::Union{Nothing,Int} = OPTIMIZE_DEFAULT + min_optlevel::Union{Nothing,Int} = MIN_OPTLEVEL_DEFAULT + inline::Union{Nothing,String} = INLINE_DEFAULT + check_bounds::Union{Nothing,String} = CHECK_BOUNDS_DEFAULT + math_mode::Union{Nothing,String} = MATH_MODE_DEFAULT # notebook specified options # the followings are different from # the default julia compiler options - - # we don't load startup file in notebook - startup_file::Union{Nothing,String} = "no" - # we don't load history file in notebook - history_file::Union{Nothing,String} = "no" + startup_file::Union{Nothing,String} = STARTUP_FILE_DEFAULT + history_file::Union{Nothing,String} = HISTORY_FILE_DEFAULT threads::Union{Nothing,String,Int} = default_number_of_threads() end -function default_number_of_threads() - env_value = get(ENV, "JULIA_NUM_THREADS", "") - all(isspace, env_value) ? roughly_the_number_of_physical_cpu_cores() : parse(Int, env_value) -end - -function roughly_the_number_of_physical_cpu_cores() - # https://gist.github.com/fonsp/738fe244719cae820245aa479e7b4a8d - if Sys.CPU_THREADS == 1 - 1 - elseif Sys.CPU_THREADS == 2 || Sys.CPU_THREADS == 3 - 2 - else - Sys.CPU_THREADS ÷ 2 - end -end - """ Collection of all settings that configure a Pluto session. @@ -169,7 +275,107 @@ Collection of all settings that configure a Pluto session. compiler::CompilerOptions = CompilerOptions() end -from_flat_kwargs(; kwargs...) = Configurations.from_field_kwargs(Options; kwargs...) +function from_flat_kwargs(; + root_url::Union{Nothing,String} = ROOT_URL_DEFAULT, + base_url::String = BASE_URL_DEFAULT, + host::String = HOST_DEFAULT, + port::Union{Nothing,Integer} = PORT_DEFAULT, + port_hint::Integer = PORT_HINT_DEFAULT, + launch_browser::Bool = LAUNCH_BROWSER_DEFAULT, + dismiss_update_notification::Bool = DISMISS_UPDATE_NOTIFICATION_DEFAULT, + show_file_system::Bool = SHOW_FILE_SYSTEM_DEFAULT, + notebook_path_suggestion::String = notebook_path_suggestion(), + disable_writing_notebook_files::Bool = DISABLE_WRITING_NOTEBOOK_FILES_DEFAULT, + auto_reload_from_file::Bool = AUTO_RELOAD_FROM_FILE_DEFAULT, + auto_reload_from_file_cooldown::Real = AUTO_RELOAD_FROM_FILE_COOLDOWN_DEFAULT, + auto_reload_from_file_ignore_pkg::Bool = AUTO_RELOAD_FROM_FILE_IGNORE_PKG_DEFAULT, + notebook::Union{Nothing,String,Vector{<:String}} = NOTEBOOK_DEFAULT, + init_with_file_viewer::Bool = INIT_WITH_FILE_VIEWER_DEFAULT, + simulated_lag::Real = SIMULATED_LAG_DEFAULT, + simulated_pkg_lag::Real = SIMULATED_PKG_LAG_DEFAULT, + injected_javascript_data_url::String = INJECTED_JAVASCRIPT_DATA_URL_DEFAULT, + on_event::Function = ON_EVENT_DEFAULT, + + require_secret_for_open_links::Bool = REQUIRE_SECRET_FOR_OPEN_LINKS_DEFAULT, + require_secret_for_access::Bool = REQUIRE_SECRET_FOR_ACCESS_DEFAULT, + warn_about_untrusted_code::Bool = WARN_ABOUT_UNTRUSTED_CODE_DEFAULT, + + run_notebook_on_load::Bool = RUN_NOTEBOOK_ON_LOAD_DEFAULT, + workspace_use_distributed::Bool = WORKSPACE_USE_DISTRIBUTED_DEFAULT, + workspace_use_distributed_stdlib::Union{Bool,Nothing} = WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT, + lazy_workspace_creation::Bool = LAZY_WORKSPACE_CREATION_DEFAULT, + capture_stdout::Bool = CAPTURE_STDOUT_DEFAULT, + workspace_custom_startup_expr::Union{Nothing,String} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT, + + compile::Union{Nothing,String} = COMPILE_DEFAULT, + pkgimages::Union{Nothing,String} = PKGIMAGES_DEFAULT, + compiled_modules::Union{Nothing,String} = COMPILED_MODULES_DEFAULT, + sysimage::Union{Nothing,String} = SYSIMAGE_DEFAULT, + sysimage_native_code::Union{Nothing,String} = SYSIMAGE_NATIVE_CODE_DEFAULT, + banner::Union{Nothing,String} = BANNER_DEFAULT, + depwarn::Union{Nothing,String} = DEPWARN_DEFAULT, + optimize::Union{Nothing,Int} = OPTIMIZE_DEFAULT, + min_optlevel::Union{Nothing,Int} = MIN_OPTLEVEL_DEFAULT, + inline::Union{Nothing,String} = INLINE_DEFAULT, + check_bounds::Union{Nothing,String} = CHECK_BOUNDS_DEFAULT, + math_mode::Union{Nothing,String} = MATH_MODE_DEFAULT, + startup_file::Union{Nothing,String} = STARTUP_FILE_DEFAULT, + history_file::Union{Nothing,String} = HISTORY_FILE_DEFAULT, + threads::Union{Nothing,String,Int} = default_number_of_threads(), + ) + server = ServerOptions(; + root_url, + base_url, + host, + port, + port_hint, + launch_browser, + dismiss_update_notification, + show_file_system, + notebook_path_suggestion, + disable_writing_notebook_files, + auto_reload_from_file, + auto_reload_from_file_cooldown, + auto_reload_from_file_ignore_pkg, + notebook, + init_with_file_viewer, + simulated_lag, + simulated_pkg_lag, + injected_javascript_data_url, + on_event, + ) + security = SecurityOptions(; + require_secret_for_open_links, + require_secret_for_access, + warn_about_untrusted_code, + ) + evaluation = EvaluationOptions(; + run_notebook_on_load, + workspace_use_distributed, + workspace_use_distributed_stdlib, + lazy_workspace_creation, + capture_stdout, + workspace_custom_startup_expr, + ) + compiler = CompilerOptions(; + compile, + pkgimages, + compiled_modules, + sysimage, + sysimage_native_code, + banner, + depwarn, + optimize, + min_optlevel, + inline, + check_bounds, + math_mode, + startup_file, + history_file, + threads, + ) + return Options(; server, security, evaluation, compiler) +end function _merge_notebook_compiler_options(notebook, options::CompilerOptions)::CompilerOptions if notebook.compiler_options === nothing @@ -196,9 +402,7 @@ function _convert_to_flags(options::CompilerOptions)::Vector{String} flagname = string("--", replace(String(name), "_" => "-")) value = getfield(options, name) if value !== nothing - if !(VERSION <= v"1.5.0-" && name === :threads) - push!(option_list, string(flagname, "=", value)) - end + push!(option_list, string(flagname, "=", value)) end end diff --git a/src/Pluto.jl b/src/Pluto.jl index a62dd86d6a..575b432783 100644 --- a/src/Pluto.jl +++ b/src/Pluto.jl @@ -9,31 +9,56 @@ Have a look at the FAQ: https://github.com/fonsp/Pluto.jl/wiki """ module Pluto -project_relative_path(xs...) = normpath(joinpath(dirname(dirname(pathof(Pluto))), xs...)) + +if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@max_methods")) + @eval Base.Experimental.@max_methods 1 +end + +import FuzzyCompletions +import RelocatableFolders: @path +const ROOT_DIR = normpath(joinpath(@__DIR__, "..")) +const FRONTEND_DIR = @path(joinpath(ROOT_DIR, "frontend")) +const FRONTEND_DIST_DIR = let dir = joinpath(ROOT_DIR, "frontend-dist") + isdir(dir) ? @path(dir) : FRONTEND_DIR +end +const frontend_dist_exists = FRONTEND_DIR !== FRONTEND_DIST_DIR +const SAMPLE_DIR = @path(joinpath(ROOT_DIR, "sample")) +const RUNNER_DIR = @path(joinpath(ROOT_DIR, "src", "runner")) +function project_relative_path(root, xs...) + root == joinpath("src", "runner") ? joinpath(RUNNER_DIR, xs...) : + root == "frontend-dist" && frontend_dist_exists ? joinpath(FRONTEND_DIST_DIR, xs...) : + root == "frontend" ? joinpath(FRONTEND_DIR, xs...) : + root == "sample" ? joinpath(SAMPLE_DIR, xs...) : + normpath(joinpath(pkgdir(Pluto), root, xs...)) +end import Pkg +import Scratch include_dependency("../Project.toml") -const PLUTO_VERSION = VersionNumber(Pkg.TOML.parsefile(project_relative_path("Project.toml"))["version"]) -const PLUTO_VERSION_STR = 'v' * string(PLUTO_VERSION) -const JULIA_VERSION_STR = 'v' * string(VERSION) +const PLUTO_VERSION = VersionNumber(Pkg.TOML.parsefile(joinpath(ROOT_DIR, "Project.toml"))["version"]) +const PLUTO_VERSION_STR = "v$(string(PLUTO_VERSION))" +const JULIA_VERSION_STR = "v$(string(VERSION))" -include("./notebook/PathHelpers.jl") +include("./notebook/path helpers.jl") include("./notebook/Export.jl") include("./Configuration.jl") include("./evaluation/Tokens.jl") -include("./runner/PlutoRunner.jl") +include("./evaluation/Throttled.jl") +include("./runner/PlutoRunner/src/PlutoRunner.jl") include("./analysis/ExpressionExplorer.jl") -include("./analysis/FunctionDependencies.jl") -include("./analysis/ReactiveNode.jl") include("./packages/PkgCompat.jl") +include("./webserver/Status.jl") include("./notebook/Cell.jl") +include("./analysis/data structures.jl") include("./analysis/Topology.jl") include("./analysis/Errors.jl") include("./analysis/TopologicalOrder.jl") include("./notebook/Notebook.jl") +include("./notebook/saving and loading.jl") +include("./notebook/frontmatter.jl") include("./notebook/Events.jl") include("./webserver/Session.jl") include("./webserver/PutUpdates.jl") @@ -46,6 +71,9 @@ include("./analysis/DependencyCache.jl") include("./analysis/MoreAnalysis.jl") include("./evaluation/WorkspaceManager.jl") +include("./evaluation/MacroAnalysis.jl") +include("./packages/IOListener.jl") +include("./packages/precompile_isolated.jl") include("./packages/Packages.jl") include("./packages/PkgUtils.jl") include("./evaluation/Run.jl") @@ -55,6 +83,8 @@ module DownloadCool include("./webserver/data_url.jl") end include("./webserver/MsgPack.jl") include("./webserver/SessionActions.jl") include("./webserver/Static.jl") +include("./webserver/Authentication.jl") +include("./webserver/Router.jl") include("./webserver/Dynamic.jl") include("./webserver/REPLTools.jl") include("./webserver/WebServer.jl") @@ -66,16 +96,38 @@ export reset_notebook_environment export update_notebook_environment export activate_notebook_environment -if get(ENV, "JULIA_PLUTO_SHOW_BANNER", "1") !== "0" -@info """\n - Welcome to Pluto $(PLUTO_VERSION_STR) 🎈 - Start a notebook server using: +include("./precompile.jl") + +const pluto_boot_environment_path = Ref{String}() + +function __init__() + pluto_boot_environment_name = "pluto-boot-environment-$(VERSION)-$(PLUTO_VERSION)" + pluto_boot_environment_path[] = Scratch.@get_scratch!(pluto_boot_environment_name) + + # Print a welcome banner + if (get(ENV, "JULIA_PLUTO_SHOW_BANNER", "1") != "0" && + get(ENV, "CI", "🍄") != "true" && isinteractive()) + # Print the banner only once per version, if there isn't + # yet a file for this version in banner_shown scratch space. + # (Using the Pluto version as the filename enables later + # version-specific "what's new" messages.) + fn = joinpath(Scratch.@get_scratch!("banner_shown"), PLUTO_VERSION_STR) + if !isfile(fn) + @info """ + + Welcome to Pluto $(PLUTO_VERSION_STR) 🎈 + Start a notebook server using: + + julia> Pluto.run() - julia> Pluto.run() + Have a look at the FAQ: + https://github.com/fonsp/Pluto.jl/wiki - Have a look at the FAQ: - https://github.com/fonsp/Pluto.jl/wiki -\n""" + """ + # create empty file to indicate that we've shown the banner + write(fn, ""); + end + end end end diff --git a/src/analysis/DependencyCache.jl b/src/analysis/DependencyCache.jl index 00ee819a09..55ce3725d5 100644 --- a/src/analysis/DependencyCache.jl +++ b/src/analysis/DependencyCache.jl @@ -4,15 +4,16 @@ Gets a dictionary of all symbols and the respective cells which are dependent on Changes in the given cell cause re-evaluation of these cells. Note that only direct dependents are given here, not indirect dependents. """ -function downstream_cells_map(cell::Cell, notebook::Notebook)::Dict{Symbol,Vector{Cell}} - defined_symbols = let node = notebook.topology.nodes[cell] +function downstream_cells_map(cell::Cell, topology::NotebookTopology)::Dict{Symbol,Vector{Cell}} + defined_symbols = let node = topology.nodes[cell] node.definitions ∪ node.funcdefs_without_signatures end return Dict{Symbol,Vector{Cell}}( - sym => where_referenced(notebook, notebook.topology, Set([sym])) + sym => where_referenced(topology, Set([sym])) for sym in defined_symbols ) end +@deprecate downstream_cells_map(cell::Cell, notebook::Notebook) downstream_cells_map(cell, notebook.topology) """ Gets a dictionary of all symbols and the respective cells on which the given cell depends. @@ -20,27 +21,32 @@ Gets a dictionary of all symbols and the respective cells on which the given cel Changes in these cells cause re-evaluation of the given cell. Note that only direct dependencies are given here, not indirect dependencies. """ -function upstream_cells_map(cell::Cell, notebook::Notebook)::Dict{Symbol,Vector{Cell}} - referenced_symbols = notebook.topology.nodes[cell].references +function upstream_cells_map(cell::Cell, topology::NotebookTopology)::Dict{Symbol,Vector{Cell}} + referenced_symbols = topology.nodes[cell].references return Dict{Symbol,Vector{Cell}}( - sym => where_assigned(notebook, notebook.topology, Set([sym]) ) + sym => where_assigned(topology, Set([sym]) ) for sym in referenced_symbols ) end +@deprecate upstream_cells_map(cell::Cell, notebook::Notebook) upstream_cells_map(cell, notebook.topology) "Fills cell dependency information for display in the GUI" -function update_dependency_cache!(cell::Cell, notebook::Notebook) +function update_dependency_cache!(cell::Cell, topology::NotebookTopology) cell.cell_dependencies = CellDependencies( - downstream_cells_map(cell, notebook), - upstream_cells_map(cell, notebook), - cell_precedence_heuristic(notebook.topology, cell), + downstream_cells_map(cell, topology), + upstream_cells_map(cell, topology), + cell_precedence_heuristic(topology, cell), ) end "Fills dependency information on notebook and cell level." -function update_dependency_cache!(notebook::Notebook) +function update_dependency_cache!(notebook::Notebook, topology::NotebookTopology=notebook.topology) notebook._cached_topological_order = topological_order(notebook) - for cell in values(notebook.cells_dict) - update_dependency_cache!(cell, notebook) + + if notebook._cached_cell_dependencies_source !== topology + notebook._cached_cell_dependencies_source = topology + for cell in all_cells(topology) + update_dependency_cache!(cell, topology) + end end end diff --git a/src/analysis/Errors.jl b/src/analysis/Errors.jl index 446ed475a1..d849160f8b 100644 --- a/src/analysis/Errors.jl +++ b/src/analysis/Errors.jl @@ -1,5 +1,5 @@ import Base: showerror -import .ExpressionExplorer: FunctionName, join_funcname_parts +import .ExpressionExplorer: FunctionName abstract type ReactivityError <: Exception end @@ -23,16 +23,19 @@ function MultipleDefinitionsError(topology::NotebookTopology, cell::Cell, all_de ) end -hint1 = "Combine all definitions into a single reactive cell using a `begin ... end` block." -hint2 = "Wrap all code in a `begin ... end` block." +const hint1 = "Combine all definitions into a single reactive cell using a `begin ... end` block." # TODO: handle case when cells are in cycle, but variables aren't function showerror(io::IO, cre::CyclicReferenceError) - print(io, "Cyclic references among $(join(cre.syms, ", ", " and ")).\n$hint1") + print(io, "Cyclic references among ") + println(io, join(cre.syms, ", ", " and ")) + print(io, hint1) end function showerror(io::IO, mde::MultipleDefinitionsError) - print(io, "Multiple definitions for $(join(mde.syms, ", ", " and ")).\n$hint1") # TODO: hint about mutable globals + print(io, "Multiple definitions for ") + println(io, join(mde.syms, ", ", " and ")) + print(io, hint1) # TODO: hint about mutable globals end "Send `error` to the frontend without backtrace. Runtime errors are handled by `WorkspaceManager.eval_format_fetch_in_workspace` - this function is for Reactivity errors." diff --git a/src/analysis/ExpressionExplorer.jl b/src/analysis/ExpressionExplorer.jl index eddb6186c0..183f04da55 100644 --- a/src/analysis/ExpressionExplorer.jl +++ b/src/analysis/ExpressionExplorer.jl @@ -1,299 +1,74 @@ -module ExpressionExplorer -export compute_symbolreferences, try_compute_symbolreferences, compute_usings_imports, SymbolsState, FunctionName, join_funcname_parts +using ExpressionExplorer -import ..PlutoRunner -import Markdown -import Base: union, union!, ==, push! - -### -# TWO STATE OBJECTS -### - -# TODO: use GlobalRef instead -FunctionName = Array{Symbol,1} - -struct FunctionNameSignaturePair - name::FunctionName - canonicalized_head::Any -end - -Base.:(==)(a::FunctionNameSignaturePair, b::FunctionNameSignaturePair) = a.name == b.name && a.canonicalized_head == b.canonicalized_head -Base.hash(a::FunctionNameSignaturePair, h::UInt) = hash(a.name, hash(a.canonicalized_head, h)) - -"SymbolsState trickles _down_ the ASTree: it carries referenced and defined variables from endpoints down to the root." -Base.@kwdef mutable struct SymbolsState - references::Set{Symbol} = Set{Symbol}() - assignments::Set{Symbol} = Set{Symbol}() - funccalls::Set{FunctionName} = Set{FunctionName}() - funcdefs::Dict{FunctionNameSignaturePair,SymbolsState} = Dict{FunctionNameSignaturePair,SymbolsState}() - macrocalls::Set{FunctionName} = Set{FunctionName}() -end - - -"ScopeState moves _up_ the ASTree: it carries scope information up towards the endpoints." -mutable struct ScopeState - inglobalscope::Bool - exposedglobals::Set{Symbol} - hiddenglobals::Set{Symbol} - definedfuncs::Set{Symbol} -end -ScopeState() = ScopeState(true, Set{Symbol}(), Set{Symbol}(), Set{Symbol}()) - -# The `union` and `union!` overloads define how two `SymbolsState`s or two `ScopeState`s are combined. - -function union(a::Dict{FunctionNameSignaturePair,SymbolsState}, bs::Dict{FunctionNameSignaturePair,SymbolsState}...) - union!(Dict{FunctionNameSignaturePair,SymbolsState}(), a, bs...) -end - -function union!(a::Dict{FunctionNameSignaturePair,SymbolsState}, bs::Dict{FunctionNameSignaturePair,SymbolsState}...) - for b in bs - for (k, v) in b - if haskey(a, k) - a[k] = union!(a[k], v) - else - a[k] = v - end - end - a - end - return a -end - -function union(a::SymbolsState, b::SymbolsState) - SymbolsState(a.references ∪ b.references, a.assignments ∪ b.assignments, a.funccalls ∪ b.funccalls, a.funcdefs ∪ b.funcdefs, a.macrocalls ∪ b.macrocalls) -end - -function union!(a::SymbolsState, bs::SymbolsState...) - union!(a.references, (b.references for b in bs)...) - union!(a.assignments, (b.assignments for b in bs)...) - union!(a.funccalls, (b.funccalls for b in bs)...) - union!(a.funcdefs, (b.funcdefs for b in bs)...) - union!(a.macrocalls, (b.macrocalls for b in bs)...) - return a -end - -function union!(a::Tuple{FunctionName,SymbolsState}, bs::Tuple{FunctionName,SymbolsState}...) - a[1], union!(a[2], (b[2] for b in bs)...) -end - -function union(a::ScopeState, b::ScopeState) - SymbolsState(a.inglobalscope && b.inglobalscope, a.exposedglobals ∪ b.exposedglobals, a.hiddenglobals ∪ b.hiddenglobals) -end - -function union!(a::ScopeState, bs::ScopeState...) - a.inglobalscope &= all((b.inglobalscope for b in bs)...) - union!(a.exposedglobals, (b.exposedglobals for b in bs)...) - union!(a.hiddenglobals, (b.hiddenglobals for b in bs)...) - union!(a.definedfuncs, (b.definedfuncs for b in bs)...) - return a -end - -function ==(a::SymbolsState, b::SymbolsState) - a.references == b.references && a.assignments == b.assignments && a.funccalls == b.funccalls && a.funcdefs == b.funcdefs && a.macrocalls == b.macrocalls -end - -Base.push!(x::Set) = x - -### -# HELPER FUNCTIONS -### - -function explore_inner_scoped(ex::Expr, scopestate::ScopeState)::SymbolsState - # Because we are entering a new scope, we create a copy of the current scope state, and run it through the expressions. - innerscopestate = deepcopy(scopestate) - innerscopestate.inglobalscope = false - - return mapfoldl(a -> explore!(a, innerscopestate), union!, ex.args, init = SymbolsState()) -end +@deprecate ReactiveNode_from_expr(args...; kwargs...) ExpressionExplorer.compute_reactive_node(args...; kwargs...) -# from the source code: https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm#L9 -const modifiers = [:(+=), :(-=), :(*=), :(/=), :(//=), :(^=), :(÷=), :(%=), :(<<=), :(>>=), :(>>>=), :(&=), :(⊻=), :(≔), :(⩴), :(≕)] -const modifiers_dotprefixed = [Symbol('.' * String(m)) for m in modifiers] +module ExpressionExplorerExtras +import ..Pluto +import ..PlutoRunner +using ExpressionExplorer +using ExpressionExplorer: ScopeState -function will_assign_global(assignee::Symbol, scopestate::ScopeState)::Bool - (scopestate.inglobalscope || assignee ∈ scopestate.exposedglobals) && (assignee ∉ scopestate.hiddenglobals || assignee ∈ scopestate.definedfuncs) -end -function will_assign_global(assignee::Array{Symbol,1}, scopestate::ScopeState)::Bool - if length(assignee) == 0 - false - elseif length(assignee) > 1 - scopestate.inglobalscope - else - will_assign_global(assignee[1], scopestate) - end -end +""" +ExpressionExplorer does not explore inside macro calls, i.e. the arguments of a macrocall (like `a+b` in `@time a+b`) are ignored. +Normally, you would macroexpand an expression before giving it to ExpressionExplorer, but in Pluto we sometimes need to explore expressions *before* executing code. -function get_global_assignees(assignee_exprs, scopestate::ScopeState)::Set{Symbol} - global_assignees = Set{Symbol}() - for ae in assignee_exprs - if isa(ae, Symbol) - will_assign_global(ae, scopestate) && push!(global_assignees, ae) - else - if ae.head == :(::) - will_assign_global(ae.args[1], scopestate) && push!(global_assignees, ae.args[1]) - else - @warn "Unknown assignee expression" ae +In those cases, we want most accurate result possible. Our extra needs are: +1. Macros included in Julia base, Markdown and `@bind` can be expanded statically. (See `maybe_macroexpand_pluto`.) +2. If a macrocall argument contains a "special heuristic" like `Pkg.activate()` or `using Something`, we need to surface this to be visible to ExpressionExplorer and Pluto. We do this by placing the macrocall in a block, and copying the argument after to the macrocall. +3. If a macrocall argument contains other macrocalls, we need these nested macrocalls to be visible. We do this by placing the macrocall in a block, and creating new macrocall expressions with the nested macrocall names, but without arguments. +""" +function pretransform_pluto(ex) + if Meta.isexpr(ex, :macrocall) + to_add = Expr[] + + maybe_expanded = maybe_macroexpand_pluto(ex) + if maybe_expanded === ex + # we were not able to expand statically + for arg in ex.args[begin+1:end] + arg_transformed = pretransform_pluto(arg) + macro_arg_symstate = ExpressionExplorer.compute_symbols_state(arg_transformed) + + # When this macro has something special inside like `Pkg.activate()`, we're going to make sure that ExpressionExplorer treats it as normal code, not inside a macrocall. (so these heuristics trigger later) + if arg isa Expr && macro_has_special_heuristic_inside(symstate = macro_arg_symstate, expr = arg_transformed) + # then the whole argument expression should be added + push!(to_add, arg_transformed) + else + for fn in macro_arg_symstate.macrocalls + push!(to_add, Expr(:macrocall, fn)) + # fn is a FunctionName + # normally this would not be a legal expression, but ExpressionExplorer handles it correctly so it's all cool + end + end end - end - end - return global_assignees -end - -function get_assignees(ex::Expr)::FunctionName - if ex.head == :tuple - if length(ex.args) == 1 && Meta.isexpr(only(ex.args), :parameters) - # e.g. (x, y) in the ex (; x, y) = (x = 5, y = 6, z = 7) - args = only(ex.args).args + + Expr( + :block, + # the original expression, not expanded. ExpressionExplorer will just explore the name of the macro, and nothing else. + ex, + # any expressions that we need to sneakily add + to_add... + ) else - # e.g. (x, y) in the ex (x, y) = (1, 23) - args = ex.args + Expr( + :block, + # We were able to expand the macro, so let's recurse on the result. + pretransform_pluto(maybe_expanded), + # the name of the macro that got expanded + Expr(:macrocall, ex.args[1]), + ) end - union!(Symbol[], get_assignees.(args)...) - # filter(s->s isa Symbol, ex.args) - elseif ex.head == :(::) - # TODO: type is referenced - Symbol[ex.args[1]] - elseif ex.head == :ref || ex.head == :(.) - Symbol[] - else - @warn "unknown use of `=`. Assignee is unrecognised." ex - Symbol[] - end -end - -# e.g. x = 123, but ignore _ = 456 -get_assignees(ex::Symbol) = all_underscores(ex) ? Symbol[] : Symbol[ex] - -# When you assign to a datatype like Int, String, or anything bad like that -# e.g. 1 = 2 -# This is parsable code, so we have to treat it -get_assignees(::Any) = Symbol[] - -all_underscores(s::Symbol) = all(isequal('_'), string(s)) - -# TODO: this should return a FunctionName, and use `split_funcname`. -"Turn :(A{T}) into :A." -function uncurly!(ex::Expr, scopestate::ScopeState)::Tuple{Symbol,SymbolsState} - @assert ex.head == :curly - symstate = SymbolsState() - for curly_arg in ex.args[2:end] - arg_name, arg_symstate = explore_funcdef!(curly_arg, scopestate) - push!(scopestate.hiddenglobals, join_funcname_parts(arg_name)) - union!(symstate, arg_symstate) - end - Symbol(ex.args[1]), symstate -end - -uncurly!(ex::Expr)::Tuple{Symbol,SymbolsState} = ex.args[1], SymbolsState() - -uncurly!(s::Symbol, scopestate = nothing)::Tuple{Symbol,SymbolsState} = s, SymbolsState() - -"Turn `:(Base.Submodule.f)` into `[:Base, :Submodule, :f]` and `:f` into `[:f]`." -function split_funcname(funcname_ex::Expr)::FunctionName - if funcname_ex.head == :(.) - vcat(split_funcname.(funcname_ex.args)...) - else - # a call to a function that's not a global, like calling an array element: `funcs[12]()` - # TODO: explore symstate! - Symbol[] - end -end - -function split_funcname(funcname_ex::QuoteNode)::FunctionName - split_funcname(funcname_ex.value) -end -function split_funcname(funcname_ex::GlobalRef)::FunctionName - split_funcname(funcname_ex.name) -end - -function split_funcname(funcname_ex::Symbol)::FunctionName - Symbol[funcname_ex|>without_dotprefix|>without_dotsuffix] -end - -function is_just_dots(ex::Expr) - ex.head == :(.) && all(is_just_dots, ex.args) -end -is_just_dots(::Union{QuoteNode,Symbol,GlobalRef}) = true -is_just_dots(::Any) = false - -# this includes GlobalRef - it's fine that we don't recognise it, because you can't assign to a globalref? -function split_funcname(::Any)::FunctionName - Symbol[] -end - -"""Turn `Symbol(".+")` into `:(+)`""" -function without_dotprefix(funcname::Symbol)::Symbol - fn_str = String(funcname) - if length(fn_str) > 0 && fn_str[1] == '.' - Symbol(fn_str[2:end]) - else - funcname - end -end - -"""Turn `Symbol("sqrt.")` into `:sqrt`""" -function without_dotsuffix(funcname::Symbol)::Symbol - fn_str = String(funcname) - if length(fn_str) > 0 && fn_str[end] == '.' - Symbol(fn_str[1:end-1]) + elseif Meta.isexpr(ex, :module) + ex + elseif ex isa Expr + # recurse + Expr(ex.head, (pretransform_pluto(a) for a in ex.args)...) else - funcname - end -end - -"""Generates a vector of all possible variants from a function name - -``` -julia> generate_funcnames([:Base, :Foo, :bar]) -3-element Vector{Symbol}: - Symbol("Base.Foo.bar") - Symbol("Foo.bar") - :bar -``` - -""" -function generate_funcnames(funccall::FunctionName) - calls = Vector{FunctionName}(undef, length(funccall) - 1) - for i = length(funccall):-1:2 - calls[i-1] = funccall[i:end] + ex end - calls -end - -"""Turn `Symbol[:Module, :func]` into Symbol("Module.func"). - -This is **not** the same as the expression `:(Module.func)`, but is used to identify the function name using a single `Symbol` (like normal variables). -This means that it is only the inverse of `ExpressionExplorer.split_funcname` iff `length(parts) ≤ 1`.""" -function join_funcname_parts(parts::FunctionName)::Symbol - join(parts .|> String, ".") |> Symbol -end - -# this is stupid -- désolé -function is_joined_funcname(joined::Symbol) - occursin('.', String(joined)) end -assign_to_kw(e::Expr) = e.head == :(=) ? Expr(:kw, e.args...) : e -assign_to_kw(x::Any) = x - -"Turn `A[i] * B[j,K[l+m]]` into `A[0] * B[0,K[0+0]]` to hide loop indices" -function strip_indexing(x, inside::Bool = false) - if Meta.isexpr(x, :ref) - Expr(:ref, strip_indexing(x.args[1]), strip_indexing.(x.args[2:end], true)...) - elseif Meta.isexpr(x, :call) - Expr(x.head, x.args[1], strip_indexing.(x.args[2:end], inside)...) - elseif x isa Symbol && inside - 0 - else - x - end -end -"Module so I don't pollute the whole ExpressionExplorer scope" -module MacroHasSpecialHeuristicInside -import ...Pluto -import ..ExpressionExplorer, ..SymbolsState """ Uses `cell_precedence_heuristic` to determine if we need to include the contents of this macro in the symstate. @@ -302,673 +77,27 @@ This helps with things like a Pkg.activate() that's in a macro, so Pluto still u function macro_has_special_heuristic_inside(; symstate::SymbolsState, expr::Expr)::Bool # Also, because I'm lazy and don't want to copy any code, imma use cell_precedence_heuristic here. # Sad part is, that this will also include other symbols used in this macro... but come'on - local fake_cell = Pluto.Cell() - local fake_reactive_node = Pluto.ReactiveNode(symstate) - local fake_expranalysiscache = Pluto.ExprAnalysisCache( + node = ReactiveNode(symstate) + code = Pluto.ExprAnalysisCache( parsedcode = expr, module_usings_imports = ExpressionExplorer.compute_usings_imports(expr), ) - local fake_topology = Pluto.NotebookTopology( - nodes = Pluto.DefaultDict(Pluto.ReactiveNode, Dict(fake_cell => fake_reactive_node)), - codes = Pluto.DefaultDict(Pluto.ExprAnalysisCache, Dict(fake_cell => fake_expranalysiscache)) - ) - - return Pluto.cell_precedence_heuristic(fake_topology, fake_cell) < 9 -end -# Having written this... I know I said I was lazy... I was wrong -end - -### -# MAIN RECURSIVE FUNCTION -### - -# Spaghetti code for a spaghetti problem 🍝 - -# Possible leaf: value -# Like: a = 1 -# 1 is a value (Int64) -function explore!(value, scopestate::ScopeState)::SymbolsState - # includes: LineNumberNode, Int64, String, - return SymbolsState() -end - -# Possible leaf: symbol -# Like a = x -# x is a symbol -# We handle the assignment separately, and explore!(:a, ...) will not be called. -# Therefore, this method only handles _references_, which are added to the symbolstate, depending on the scopestate. -function explore!(sym::Symbol, scopestate::ScopeState)::SymbolsState - if sym ∈ scopestate.hiddenglobals - SymbolsState() - else - SymbolsState(references = Set([sym])) - end + return Pluto.cell_precedence_heuristic(node, code) < Pluto.DEFAULT_PRECEDENCE_HEURISTIC end -""" -Returns whether or not an assignment Expr(:(=),...) is assigning to a new function - * f(x) = ... - * f(x)::V = ... - * f(::T) where {T} = ... -""" -is_function_assignment(ex::Expr) = ex.args[1] isa Expr && (ex.args[1].head == :call || ex.args[1].head == :where || (ex.args[1].head == :(::) && ex.args[1].args[1] isa Expr && ex.args[1].args[1].head == :call)) - -anonymous_name() = Symbol("anon", rand(UInt64)) - -# General recursive method. Is never a leaf. -# Modifies the `scopestate`. -function explore!(ex::Expr, scopestate::ScopeState)::SymbolsState - if ex.head == :(=) - # Does not create scope - - if is_function_assignment(ex) - # f(x, y) = x + y - # Rewrite to: - # function f(x, y) x + y end - return explore!(Expr(:function, ex.args...), scopestate) - end - - val = ex.args[2] - # Handle generic types assignments A{B} = C{B, Int} - if ex.args[1] isa Expr && ex.args[1].head == :curly - assignees, symstate = explore_funcdef!(ex.args[1], scopestate) - innersymstate = union!(symstate, explore!(val, scopestate)) - else - assignees = get_assignees(ex.args[1]) - symstate = innersymstate = explore!(val, scopestate) - end - - global_assignees = get_global_assignees(assignees, scopestate) - - # If we are _not_ assigning a global variable, then this symbol hides any global definition with that name - push!(scopestate.hiddenglobals, setdiff(assignees, global_assignees)...) - assigneesymstate = explore!(ex.args[1], scopestate) - - push!(scopestate.hiddenglobals, global_assignees...) - push!(symstate.assignments, global_assignees...) - push!(symstate.references, setdiff(assigneesymstate.references, global_assignees)...) - filter!(!all_underscores, symstate.references) # Never record _ as a reference - - return symstate - elseif ex.head in modifiers - # We change: a[1] += 123 - # to: a[1] = a[1] + 123 - # We transform the modifier back to its operator - # for when users redefine the + function - - operator = let - s = string(ex.head) - Symbol(s[1:prevind(s, lastindex(s))]) - end - expanded_expr = Expr(:(=), ex.args[1], Expr(:call, operator, ex.args[1], ex.args[2])) - return explore!(expanded_expr, scopestate) - elseif ex.head in modifiers_dotprefixed - # We change: a[1] .+= 123 - # to: a[1] .= a[1] + 123 - - operator = Symbol(string(ex.head)[2:end-1]) - expanded_expr = Expr(:(.=), ex.args[1], Expr(:call, operator, ex.args[1], ex.args[2])) - return explore!(expanded_expr, scopestate) - elseif ex.head == :let || ex.head == :for || ex.head == :while - # Creates local scope - return explore_inner_scoped(ex, scopestate) - elseif ex.head == :filter - # In a filter, the assignment is the second expression, the condition the first - return mapfoldr(a -> explore!(a, scopestate), union!, ex.args, init = SymbolsState()) - elseif ex.head == :generator - # Creates local scope - - # In a `generator`, a single expression is followed by the iterator assignments. - # In a `for`, this expression comes at the end. - - # This is not strictly the normal form of a `for` but that's okay - return explore!(Expr(:for, Iterators.reverse(ex.args[2:end])..., ex.args[1]), scopestate) - elseif ex.head == :macrocall - # Early stopping, this expression will have to be re-explored once - # the macro is expanded in the notebook process. - macro_name = split_funcname(ex.args[1]) - symstate = SymbolsState(macrocalls = Set{FunctionName}([macro_name])) - - # Because it sure wouldn't break anything, - # I'm also going to blatantly assume that any macros referenced in here... - # will end up in the code after the macroexpansion 🤷‍♀️ - # "You should make a new function for that" they said, knowing I would take the lazy route. - for arg in ex.args[begin+1:end] - macro_symstate = explore!(arg, ScopeState()) - - # Also, when this macro has something special inside like `Pkg.activate()`, - # we're going to treat it as normal code (so these heuristics trigger later) - # (Might want to also not let this to @eval macro, as an extra escape hatch if you - # really don't want pluto to see your Pkg.activate() call) - if arg isa Expr && MacroHasSpecialHeuristicInside.macro_has_special_heuristic_inside(symstate = macro_symstate, expr = arg) - union!(symstate, macro_symstate) - else - union!(symstate, SymbolsState(macrocalls = macro_symstate.macrocalls)) - end - end - - # Some macros can be expanded on the server process - if join_funcname_parts(macro_name) ∈ can_macroexpand - new_ex = maybe_macroexpand(ex) - union!(symstate, explore!(new_ex, scopestate)) - end - - return symstate - elseif ex.head == :call - # Does not create scope - - if is_just_dots(ex.args[1]) - funcname = ex.args[1] |> split_funcname - symstate = if length(funcname) == 0 - explore!(ex.args[1], scopestate) - elseif length(funcname) == 1 - if funcname[1] ∈ scopestate.hiddenglobals - SymbolsState() - else - SymbolsState(funccalls = Set{FunctionName}([funcname])) - end - elseif funcname[1] ∈ scopestate.hiddenglobals - SymbolsState() - else - SymbolsState(references = Set{Symbol}([funcname[1]]), funccalls = Set{FunctionName}([funcname])) - end - - # Make `@macroexpand` and `Base.macroexpand` reactive by referencing the first macro in the second - # argument to the call. - if ([:Base, :macroexpand] == funcname || [:macroexpand] == funcname) && - length(ex.args) >= 3 && - ex.args[3] isa QuoteNode && - Meta.isexpr(ex.args[3].value, :macrocall) - expanded_macro = split_funcname(ex.args[3].value.args[1]) - union!(symstate, SymbolsState(macrocalls = Set{FunctionName}([expanded_macro]))) - end - - # Explore code inside function arguments: - union!(symstate, explore!(Expr(:block, ex.args[2:end]...), scopestate)) - return symstate - else - return explore!(Expr(:block, ex.args...), scopestate) - end - elseif ex.head == :kw - return explore!(ex.args[2], scopestate) - elseif ex.head == :struct - # Creates local scope - - structnameexpr = ex.args[2] - structfields = ex.args[3].args - - equiv_func = Expr(:function, Expr(:call, structnameexpr, structfields...), Expr(:block, nothing)) - - # struct should always be in Global state - globalscopestate = deepcopy(scopestate) - globalscopestate.inglobalscope = true - - # we register struct definitions as both a variable and a function. This is because deleting a struct is trickier than just deleting its methods. - # Due to this, outer constructors have to be defined in the same cell where the struct is defined. - # See https://github.com/fonsp/Pluto.jl/issues/732 for more details - inner_symstate = explore!(equiv_func, globalscopestate) - - structname = first(keys(inner_symstate.funcdefs)).name |> join_funcname_parts - push!(inner_symstate.assignments, structname) - return inner_symstate - elseif ex.head == :abstract - equiv_func = Expr(:function, ex.args...) - inner_symstate = explore!(equiv_func, scopestate) - - abstracttypename = first(keys(inner_symstate.funcdefs)).name |> join_funcname_parts - push!(inner_symstate.assignments, abstracttypename) - return inner_symstate - elseif ex.head == :function || ex.head == :macro - symstate = SymbolsState() - # Creates local scope - - funcroot = ex.args[1] - - # Because we are entering a new scope, we create a copy of the current scope state, and run it through the expressions. - innerscopestate = deepcopy(scopestate) - innerscopestate.inglobalscope = false - - funcname, innersymstate = explore_funcdef!(funcroot, innerscopestate) - - # Macro are called using @funcname, but defined with funcname. We need to change that in our scopestate - # (The `!= 0` is for when the function named couldn't be parsed) - if ex.head == :macro && length(funcname) != 0 - funcname = Symbol[Symbol("@$(funcname[1])")] - push!(innerscopestate.hiddenglobals, only(funcname)) - elseif length(funcname) == 1 - push!(scopestate.definedfuncs, funcname[end]) - push!(scopestate.hiddenglobals, funcname[end]) - elseif length(funcname) > 1 - push!(symstate.references, funcname[end-1]) # reference the module of the extended function - push!(scopestate.hiddenglobals, funcname[end-1]) - end - - union!(innersymstate, explore!(Expr(:block, ex.args[2:end]...), innerscopestate)) - funcnamesig = FunctionNameSignaturePair(funcname, canonalize(funcroot)) - - if will_assign_global(funcname, scopestate) - symstate.funcdefs[funcnamesig] = innersymstate - else - # The function is not defined globally. However, the function can still modify the global scope or reference globals, e.g. - - # let - # function f(x) - # global z = x + a - # end - # f(2) - # end - - # so we insert the function's inner symbol state here, as if it was a `let` block. - symstate = innersymstate - end - - return symstate - elseif ex.head == :try - symstate = SymbolsState() - - # Handle catch first - if ex.args[3] != false - union!(symstate, explore_inner_scoped(ex.args[3], scopestate)) - # If we catch a symbol, it could shadow a global reference, remove it - if ex.args[2] != false - setdiff!(symstate.references, Symbol[ex.args[2]]) - end - end - - # Handle the try block - union!(symstate, explore_inner_scoped(ex.args[1], scopestate)) - - # Finally, handle finally - if length(ex.args) == 4 - union!(symstate, explore_inner_scoped(ex.args[4], scopestate)) - end - - return symstate - elseif ex.head == :(->) - # Creates local scope - - tempname = anonymous_name() - - # We will rewrite this to a normal function definition, with a temporary name - funcroot = ex.args[1] - args_ex = if funcroot isa Symbol || (funcroot isa Expr && funcroot.head == :(::)) - [funcroot] - elseif funcroot.head == :tuple || funcroot.head == :(...) || funcroot.head == :block - funcroot.args - else - @error "Unknown lambda type" - end - - equiv_func = Expr(:function, Expr(:call, tempname, args_ex...), ex.args[2]) - - return explore!(equiv_func, scopestate) - elseif ex.head == :global - # Does not create scope - - # global x, y, z - if length(ex.args) > 1 - return mapfoldl(arg -> explore!(Expr(:global, arg), scopestate), union!, ex.args; init = SymbolsState()) - end - - # We have one of: - # global x; - # global x = 1; - # global x += 1; - - # where x can also be a tuple: - # global a,b = 1,2 - - globalisee = ex.args[1] - - if isa(globalisee, Symbol) - push!(scopestate.exposedglobals, globalisee) - return SymbolsState() - elseif isa(globalisee, Expr) - # temporarily set inglobalscope to true - old = scopestate.inglobalscope - scopestate.inglobalscope = true - result = explore!(globalisee, scopestate) - scopestate.inglobalscope = old - return result - else - @error "unknown global use" ex - return explore!(globalisee, scopestate) - end - - return symstate - elseif ex.head == :local - # Does not create scope - - # Turn `local x, y` in `local x; local y - if length(ex.args) > 1 - return mapfoldl(arg -> explore!(Expr(:local, arg), scopestate), union!, ex.args; init = SymbolsState()) - end - - localisee = ex.args[1] - - if isa(localisee, Symbol) - push!(scopestate.hiddenglobals, localisee) - return SymbolsState() - elseif isa(localisee, Expr) && (localisee.head == :(=) || localisee.head in modifiers) - push!(scopestate.hiddenglobals, get_assignees(localisee.args[1])...) - return explore!(localisee, scopestate) - else - @warn "unknown local use" ex - return explore!(localisee, scopestate) - end - elseif ex.head == :tuple - # Does not create scope - - # There are three (legal) cases: - # 1. Creating a tuple: - # (a, b, c) - - # 2. Creating a named tuple: - # (a=1, b=2, c=3) - - # 3. Multiple assignments - # a,b,c = 1,2,3 - # This parses to: - # head = :tuple - # args = [:a, :b, :(c=1), :2, :3] - # - # 🤔 - # we turn it into two expressions: - # - # (a, b) = (2, 3) - # (c = 1) - # - # and explore those :) - - indexoffirstassignment = findfirst(a -> isa(a, Expr) && a.head == :(=), ex.args) - if indexoffirstassignment !== nothing - # we have one of two cases, see next `if` - indexofsecondassignment = findnext(a -> isa(a, Expr) && a.head == :(=), ex.args, indexoffirstassignment + 1) - - if length(ex.args) == 1 || indexofsecondassignment !== nothing - # 2. - # we have a named tuple, e.g. (a=1, b=2) - new_args = map(ex.args) do a - (a isa Expr && a.head == :(=)) ? a.args[2] : a - end - return explore!(Expr(:block, new_args...), scopestate) - else - # 3. - # we have a tuple assignment, e.g. `a, (b, c) = [1, [2, 3]]` - before = ex.args[1:indexoffirstassignment-1] - after = ex.args[indexoffirstassignment+1:end] - - symstate_middle = explore!(ex.args[indexoffirstassignment], scopestate) - symstate_outer = explore!(Expr(:(=), Expr(:tuple, before...), Expr(:block, after...)), scopestate) - - return union!(symstate_middle, symstate_outer) - end - else - # 1. - # good ol' tuple - return explore!(Expr(:block, ex.args...), scopestate) - end - elseif Meta.isexpr(ex, :(.), 2) && ex.args[2] isa Expr && ex.args[2].head == :tuple - # pointwise function call, e.g. sqrt.(nums) - # we rewrite to a regular call - - return explore!(Expr(:call, ex.args[1], ex.args[2].args...), scopestate) - elseif ex.head == :using || ex.head == :import - imports = if ex.args[1].head == :(:) - ex.args[1].args[2:end] - else - ex.args - end - - packagenames = map(e -> e.args[end], imports) - - return SymbolsState(assignments = Set{Symbol}(packagenames)) - elseif ex.head == :quote - # Look through the quote and only returns explore! deeper into :$'s - # I thought we need to handle strings in the same way, - # but strings do just fine with the catch all at the end - # and actually strings don't always have a :$ expression, sometimes just - # plain Symbols (which we should then be interpreted as variables, - # which is different to how we handle Symbols in quote'd expressions) - return explore_interpolations!(ex.args[1], scopestate) - elseif ex.head == :module - # Does create it's own scope, but can import from outer scope, that's what `explore_module_definition!` is for - symstate = explore_module_definition!(ex, scopestate) - - return union(symstate, SymbolsState(assignments = Set{Symbol}([ex.args[2]]))) - elseif Meta.isexpr(ex, Symbol("'"), 1) - # a' corresponds to adjoint(a) - return explore!(Expr(:call, :adjoint, ex.args[1]), scopestate) - elseif ex.head == :meta - return SymbolsState() - else - # fallback, includes: - # begin, block, do, toplevel, const - # (and hopefully much more!) - - # Does not create scope (probably) - - return mapfoldl(a -> explore!(a, scopestate), union!, ex.args, init = SymbolsState()) - end -end - -""" -Goes through a module definition, and picks out `import ..x`'s, which are references to the outer module. -We need `module_depth + 1` dots before the specifier, so nested modules can still access Pluto. -""" -function explore_module_definition!(ex::Expr, scopestate; module_depth::Number = 0) - if ex.head == :using || ex.head == :import - # We don't care about anything after the `:` here - import_names = if ex.args[1].head == :(:) - [ex.args[1].args[1]] - else - ex.args - end - - - symstate = SymbolsState() - for import_name_expr in import_names - if ( - Meta.isexpr(import_name_expr, :., module_depth + 2) && - all(x -> x == :., import_name_expr.args[begin:end-1]) && - import_name_expr.args[end] isa Symbol - ) - # Theoretically it could still use an assigment from the same cell, if it weren't - # for the fact that modules need to be top level, and we don't support multiple (toplevel) expressions in a cell yet :D - push!(symstate.references, import_name_expr.args[end]) - end - - end - - return symstate - elseif ex.head == :module - # Explorer the block inside with one more depth added - return explore_module_definition!(ex.args[3], scopestate, module_depth = module_depth + 1) - elseif ex.head == :quote - # TODO? Explore interpolations, modules can't be in interpolations, but `import`'s can >_> - return SymbolsState() - else - # Go deeper - return mapfoldl(a -> explore_module_definition!(a, scopestate, module_depth = module_depth), union!, ex.args, init = SymbolsState()) - end -end -explore_module_definition!(expr, scopestate; module_depth::Number = 1) = SymbolsState() - - -"Go through a quoted expression and use explore! for :\$ expressions" -function explore_interpolations!(ex::Expr, scopestate) - if ex.head == :$ - explore!(ex.args[1], scopestate) - else - # We are still in a quote, so we do go deeper, but we keep ignoring everything except :$'s - return mapfoldl(a -> explore_interpolations!(a, scopestate), union!, ex.args, init = SymbolsState()) - end -end -explore_interpolations!(anything_else, scopestate) = SymbolsState() - - -"Return the function name and the SymbolsState from argument defaults. Add arguments as hidden globals to the `scopestate`. - -Is also used for `struct` and `abstract`." -function explore_funcdef!(ex::Expr, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState} - if ex.head == :call - params_to_explore = ex.args[2:end] - # Using the keyword args syntax f(;y) the :parameters node is the first arg in the AST when it should - # be explored last. We change from (parameters, ...) to (..., parameters) - if length(params_to_explore) >= 2 && params_to_explore[1] isa Expr && params_to_explore[1].head == :parameters - params_to_explore = [params_to_explore[2:end]..., params_to_explore[1]] - end - - # Handle struct as callables, `(obj::MyType)(a, b) = ...` - # or `function (obj::MyType)(a, b) ...; end` by rewriting it as: - # function MyType(obj, a, b) ...; end - funcroot = ex.args[1] - if Meta.isexpr(funcroot, :(::)) - if last(funcroot.args) isa Symbol - return explore_funcdef!(Expr(:call, reverse(funcroot.args)..., params_to_explore...), scopestate) - else - # Function call as type: (obj::typeof(myotherobject))() - symstate = explore!(last(funcroot.args), scopestate) - name, declaration_symstate = if length(funcroot.args) == 1 - explore_funcdef!(Expr(:call, anonymous_name(), params_to_explore...), scopestate) - else - explore_funcdef!(Expr(:call, anonymous_name(), first(funcroot.args), params_to_explore...), scopestate) - end - return name, union!(symstate, declaration_symstate) - end - end - - # get the function name - name, symstate = explore_funcdef!(funcroot, scopestate) - # and explore the function arguments - return mapfoldl(a -> explore_funcdef!(a, scopestate), union!, params_to_explore, init = (name, symstate)) - elseif ex.head == :(::) || ex.head == :kw || ex.head == :(=) - # account for unnamed params, like in f(::Example) = 1 - if ex.head == :(::) && length(ex.args) == 1 - symstate = explore!(ex.args[1], scopestate) - - return Symbol[], symstate - end - - # For a() = ... in a struct definition - if Meta.isexpr(ex, :(=), 2) && Meta.isexpr(ex.args[1], :call) - name, symstate = explore_funcdef!(ex.args[1], scopestate) - union!(symstate, explore!(ex.args[2], scopestate)) - return name, symstate - end - - # recurse by starting by the right hand side because f(x=x) references the global variable x - rhs_symstate = if length(ex.args) > 1 - # use `explore!` (not `explore_funcdef!`) to explore the argument's default value - these can contain arbitrary expressions - explore!(ex.args[2], scopestate) - else - SymbolsState() - end - name, symstate = explore_funcdef!(ex.args[1], scopestate) - union!(symstate, rhs_symstate) - - return name, symstate - - elseif ex.head == :where - # function(...) where {T, S <: R, U <: A.B} - # supertypes `R` and `A.B` are referenced - supertypes_symstate = SymbolsState() - for a in ex.args[2:end] - name, inner_symstate = explore_funcdef!(a, scopestate) - if length(name) == 1 - push!(scopestate.hiddenglobals, name[1]) - end - union!(supertypes_symstate, inner_symstate) - end - # recurse - name, symstate = explore_funcdef!(ex.args[1], scopestate) - union!(symstate, supertypes_symstate) - return name, symstate - - elseif ex.head == :(<:) - # for use in `struct` and `abstract` - name, symstate = uncurly!(ex.args[1], scopestate) - if length(ex.args) != 1 - union!(symstate, explore!(ex.args[2], scopestate)) - end - return Symbol[name], symstate - - elseif ex.head == :curly - name, symstate = uncurly!(ex, scopestate) - return Symbol[name], symstate - - elseif ex.head == :parameters || ex.head == :tuple - return mapfoldl(a -> explore_funcdef!(a, scopestate), union!, ex.args, init = (Symbol[], SymbolsState())) - - elseif ex.head == :(.) - return split_funcname(ex), SymbolsState() - - elseif ex.head == :(...) - return explore_funcdef!(ex.args[1], scopestate) - else - return Symbol[], explore!(ex, scopestate) - end -end - -function explore_funcdef!(ex::QuoteNode, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState} - explore_funcdef!(ex.value, scopestate) -end - -function explore_funcdef!(ex::Symbol, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState} - push!(scopestate.hiddenglobals, ex) - Symbol[ex|>without_dotprefix|>without_dotsuffix], SymbolsState() -end - -function explore_funcdef!(::Any, ::ScopeState)::Tuple{FunctionName,SymbolsState} - Symbol[], SymbolsState() -end - - - const can_macroexpand_no_bind = Set(Symbol.(["@md_str", "Markdown.@md_str", "@gensym", "Base.@gensym", "@enum", "Base.@enum", "@assert", "Base.@assert", "@cmd"])) const can_macroexpand = can_macroexpand_no_bind ∪ Set(Symbol.(["@bind", "PlutoRunner.@bind"])) -macro_kwargs_as_kw(ex::Expr) = Expr(:macrocall, ex.args[1:3]..., assign_to_kw.(ex.args[4:end])...) - -function symbolics_mockexpand(s::Any) - # goofy implementation of the syntax described in https://symbolics.juliasymbolics.org/dev/manual/variables/ - if Meta.isexpr(s, :ref, 2) - :($(s.args[1]) = $(s.args[2])) - elseif Meta.isexpr(s, :call, 2) - second = s.args[2] === Symbol("..") ? 123 : s.args[2] - :($(symbolics_mockexpand(s.args[1])); $(second) = 123) - elseif s isa Symbol - :($(s) = 123) - else - nothing - end -end - -is_symbolics_arg(s) = symbolics_mockexpand(s) !== nothing - -maybe_untuple(es) = - if length(es) == 1 && Meta.isexpr(first(es), :tuple) - first(es).args - else - es - end - """ If the macro is **known to Pluto**, expand or 'mock expand' it, if not, return the expression. Macros from external packages are not expanded, this is done later in the pipeline. See https://github.com/fonsp/Pluto.jl/pull/1032 """ -function maybe_macroexpand(ex::Expr; recursive = false, expand_bind = true) - result = if ex.head === :macrocall - funcname = ex.args[1] |> split_funcname - funcname_joined = join_funcname_parts(funcname) - - args = ex.args[3:end] +function maybe_macroexpand_pluto(ex::Expr; recursive::Bool=false, expand_bind::Bool=true) + result::Expr = if ex.head === :macrocall + funcname = ExpressionExplorer.split_funcname(ex.args[1]) - if funcname_joined ∈ (expand_bind ? can_macroexpand : can_macroexpand_no_bind) - macroexpand(PlutoRunner, ex; recursive = false) - elseif length(args) ≥ 2 && ex.args[1] != GlobalRef(Core, Symbol("@doc")) - # for macros like @test a ≈ b atol=1e-6, read assignment in 2nd & later arg as keywords - macro_kwargs_as_kw(ex) + if funcname.joined ∈ (expand_bind ? can_macroexpand : can_macroexpand_no_bind) + macroexpand(PlutoRunner, ex; recursive=false)::Expr else ex end @@ -976,184 +105,41 @@ function maybe_macroexpand(ex::Expr; recursive = false, expand_bind = true) ex end - if recursive && (result isa Expr) - Expr(result.head, maybe_macroexpand.(result.args; recursive = recursive, expand_bind = expand_bind)...) - else - result - end -end - -maybe_macroexpand(ex::Any; kwargs...) = ex - - -### -# CANONICALIZE FUNCTION DEFINITIONS -### - -""" -Turn a function definition expression (`Expr`) into a "canonical" form, in the sense that two methods that would evaluate to the same method signature have the same canonical form. Part of a solution to https://github.com/fonsp/Pluto.jl/issues/177. Such a canonical form cannot be achieved statically with 100% correctness (impossible), but we can make it good enough to be practical. - - -# Wait, "evaluate to the same method signature"? - -In Pluto, you cannot do definitions of **the same global variable** in different cells. This is needed for reactivity to work, and it avoid ambiguous notebooks and stateful stuff. This rule used to also apply to functions: you had to place all methods of a function in one cell. (Go and read more about methods in Julia if you haven't already.) But this is quite annoying, especially because multiple dispatch is so important in Julia code. So we allow methods of the same function to be defined across multiple cells, but we still want to throw errors when you define **multiple methods with the same signature**, because one overrides the other. For example: -```julia -julia> f(x) = 1 -f (generic function with 1 method) - -julia> f(x) = 2 -f (generic function with 1 method) -`` - -After adding the second method, the function still has only 1 method. This is because the second definition overrides the first one, instead of being added to the method table. This example should be illegal in Julia, for the same reason that `f = 1` and `f = 2` is illegal. So our problem is: how do we know that two cells will define overlapping methods? - -Ideally, we would just evaluate the user's code and **count methods** afterwards, letting Julia do the work. Unfortunately, we need to know this info _before_ we run cells, otherwise we don't know in which order to run a notebook! There are ways to break this circle, but it would complicate our process quite a bit. - -Instead, we will do _static analysis_ on the function definition expressions to determine whether they overlap. This is non-trivial. For example, `f(x)` and `f(y::Any)` define the same method. Trickier examples are here: https://github.com/fonsp/Pluto.jl/issues/177#issuecomment-645039993 - -# Wait, "function definition expressions"? -For example: - -```julia -e = :(function f(x::Int, y::String) - x + y - end) - -dump(e, maxdepth=2) - -#= -gives: - -Expr - head: Symbol function - args: Array{Any}((2,)) - 1: Expr - 2: Expr -=# -``` - -This first arg is the function head: - -```julia -e.args[1] == :(f(x::Int, y::String)) -``` - -# Mathematics -Our problem is to find a way to compute the equivalence relation ~ on `H × H`, with `H` the set of function head expressions, defined as: - -`a ~ b` iff evaluating both expressions results in a function with exactly one method. - -_(More precisely, evaluating `Expr(:function, x, Expr(:block))` with `x ∈ {a, b}`.)_ - -The equivalence sets are isomorphic to the set of possible Julia methods. - -Instead of finding a closed form algorithm for `~`, we search for a _canonical form_: a function `canonical: H -> H` that chooses one canonical expression per equivalence class. It has the property - -`canonical(a) = canonical(b)` implies `a ~ b`. - -We use this **canonical form** of the function's definition expression as its "signature". We compare these canonical forms when determining whether two function expressions will result in overlapping methods. - -# Example -```julia -e1 = :(f(x, z::Any)) -e2 = :(g(x, y)) - -canonalize(e1) == canonalize(e2) -``` - -```julia -e1 = :(f(x)) -e2 = :(g(x, y)) - -canonalize(e1) != canonalize(e2) -``` - -```julia -e1 = :(f(a::X, b::wow(ie), c, d...; e=f) where T) -e2 = :(g(z::X, z::wow(ie), z::Any, z... ) where T) - -canonalize(e1) == canonalize(e2) -``` -""" -function canonalize(ex::Expr) - if ex.head == :where - Expr(:where, canonalize(ex.args[1]), ex.args[2:end]...) - elseif ex.head == :call || ex.head == :tuple - skip_index = ex.head == :call ? 2 : 1 - # ex.args[1], if ex.head == :call this is the function name, we dont want it - - interesting = filter(ex.args[skip_index:end]) do arg - !(arg isa Expr && arg.head == :parameters) + if recursive + # Not using broadcasting because that is expensive compilation-wise for `result.args::Any`. + expanded = Any[] + for arg in result.args + ex = maybe_macroexpand_pluto(arg; recursive, expand_bind) + push!(expanded, ex) end - - hide_argument_name.(interesting) - elseif ex.head == :(::) - canonalize(ex.args[1]) - elseif ex.head == :curly || ex.head == :(<:) - # for struct definitions, which we hackily treat as functions - nothing + return Expr(result.head, expanded...) else - @error "Failed to canonalize this strange looking function" ex - nothing + return result end end -# for `function g end` -canonalize(::Symbol) = nothing +maybe_macroexpand_pluto(ex::Any; kwargs...) = ex -function hide_argument_name(ex::Expr) - if ex.head == :(::) && length(ex.args) > 1 - Expr(:(::), nothing, ex.args[2:end]...) - elseif ex.head == :(...) - Expr(:(...), hide_argument_name(ex.args[1])) - elseif ex.head == :kw - Expr(:kw, hide_argument_name(ex.args[1]), nothing) - else - ex - end -end -hide_argument_name(::Symbol) = Expr(:(::), nothing, :Any) -hide_argument_name(x::Any) = x -### -# UTILITY FUNCTIONS -### -"Get the global references, assignment, function calls and function defintions inside an arbitrary expression." -function compute_symbolreferences(ex::Any)::SymbolsState - symstate = explore!(ex, ScopeState()) +############### - # We do something special to account for recursive functions: - # If a function `f` calls a function `g`, and both are defined inside this cell, the reference to `g` inside the symstate of `f` will be deleted. - # The motivitation is that normally, an assignment (or function definition) will add that symbol to a list of 'hidden globals' - any future references to that symbol will be ignored. i.e. the _local definition hides a global_. - # In the case of functions, you can reference functions and variables that do not yet exist, and so they won't be in the list of hidden symbols when the function definition is analysed. - # Of course, our method will fail if a referenced function is defined both inside the cell **and** in another cell. However, this will lead to a MultipleDefinitionError before anything bad happens. - for (func, inner_symstate) in symstate.funcdefs - inner_symstate.references = setdiff(inner_symstate.references, keys(symstate.funcdefs)) - inner_symstate.funccalls = setdiff(inner_symstate.funccalls, keys(symstate.funcdefs)) - end - symstate -end +function collect_implicit_usings(usings_imports::ExpressionExplorer.UsingsImports) + implicit_usings = Set{Expr}() + for (using_, isglobal) in zip(usings_imports.usings, usings_imports.usings_isglobal) + if !(isglobal && is_implicit_using(using_)) + continue + end -function try_compute_symbolreferences(ex::Any)::SymbolsState - try - compute_symbolreferences(ex) - catch e - if e isa InterruptException - rethrow(e) + for arg in using_.args + push!(implicit_usings, transform_dot_notation(arg)) end - @error "Expression explorer failed on: " ex - showerror(stderr, e, stacktrace(catch_backtrace())) - SymbolsState(references = Set{Symbol}([:fake_reference_to_prevent_it_from_looking_like_a_text_only_cell])) end -end - -Base.@kwdef struct UsingsImports - usings::Set{Expr} = Set{Expr}() - imports::Set{Expr} = Set{Expr}() + implicit_usings end is_implicit_using(ex::Expr) = Meta.isexpr(ex, :using) && length(ex.args) >= 1 && !Meta.isexpr(ex.args[1], :(:)) + function transform_dot_notation(ex::Expr) if Meta.isexpr(ex, :(.)) Expr(:block, ex.args[end]) @@ -1162,104 +148,26 @@ function transform_dot_notation(ex::Expr) end end -function collect_implicit_usings(ex::Expr) - if is_implicit_using(ex) - Set{Expr}(transform_dot_notation.(ex.args)) - else - return Set{Expr}() - end -end -collect_implicit_usings(usings::Set{Expr}) = mapreduce(collect_implicit_usings, union!, usings; init = Set{Expr}()) -collect_implicit_usings(usings_imports::UsingsImports) = collect_implicit_usings(usings_imports.usings) -# Performance analysis: https://gist.github.com/fonsp/280f6e883f419fb3a59231b2b1b95cab -"Preallocated version of [`compute_usings_imports`](@ref)." -function compute_usings_imports!(out::UsingsImports, ex::Any) - if isa(ex, Expr) - if ex.head == :using - push!(out.usings, ex) - elseif ex.head == :import - push!(out.imports, ex) - elseif ex.head != :quote - for a in ex.args - compute_usings_imports!(out, a) - end - end - end - out -end +############### -""" -Given `:(using Plots, Something.Else, .LocalModule)`, return `Set([:Plots, :Something])`. -""" -function external_package_names(ex::Expr)::Set{Symbol} - @assert ex.head == :import || ex.head == :using - if Meta.isexpr(ex.args[1], :(:)) - external_package_names(Expr(ex.head, ex.args[1].args[1])) - else - out = Set{Symbol}() - for a in ex.args - if Meta.isexpr(a, :as) - a = a.args[1] - end - if Meta.isexpr(a, :(.)) - if a.args[1] != :(.) - push!(out, a.args[1]) - end - end - end - out - end -end - -function external_package_names(x::UsingsImports)::Set{Symbol} - union!(Set{Symbol}(), external_package_names.(x.usings)..., external_package_names.(x.imports)...) -end - -"Get the sets of `using Module` and `import Module` subexpressions that are contained in this expression." -compute_usings_imports(ex) = compute_usings_imports!(UsingsImports(), ex) -"Return whether the expression is of the form `Expr(:toplevel, LineNumberNode(..), any)`." -function is_toplevel_expr(ex::Expr)::Bool - Meta.isexpr(ex, :toplevel, 2) && (ex.args[1] isa LineNumberNode) -end - -is_toplevel_expr(::Any)::Bool = false - -"If the expression is a (simple) assignemnt at its root, return the assignee as `Symbol`, return `nothing` otherwise." -function get_rootassignee(ex::Expr, recurse::Bool = true)::Union{Symbol,Nothing} - if is_toplevel_expr(ex) && recurse - get_rootassignee(ex.args[2], false) - elseif Meta.isexpr(ex, :macrocall, 3) - rooter_assignee = get_rootassignee(ex.args[3], true) - if rooter_assignee !== nothing - Symbol(string(ex.args[1]) * " " * string(rooter_assignee)) - else - nothing - end - elseif Meta.isexpr(ex, :const, 1) - rooter_assignee = get_rootassignee(ex.args[1], false) - if rooter_assignee !== nothing - Symbol("const " * string(rooter_assignee)) - else - nothing - end - elseif ex.head == :(=) && ex.args[1] isa Symbol - ex.args[1] - else - nothing - end -end - -get_rootassignee(ex::Any, recuse::Bool = true)::Union{Symbol,Nothing} = nothing +""" +```julia +can_be_function_wrapped(ex)::Bool +``` -"Is this code simple enough that we can wrap it inside a function to boost performance? Look for [`PlutoRunner.Computer`](@ref) to learn more." +Is this code simple enough that we can wrap it inside a function, and run the function in global scope instead of running the code directly? Look for `Pluto.PlutoRunner.Computer` to learn more. +""" function can_be_function_wrapped(x::Expr) if x.head === :global || # better safe than sorry x.head === :using || x.head === :import || + x.head === :export || + x.head === :public || # Julia 1.11 x.head === :module || + x.head === :incomplete || # Only bail on named functions, but anonymous functions (args[1].head == :tuple) are fine. # TODO Named functions INSIDE other functions should be fine too (x.head === :function && !Meta.isexpr(x.args[1], :tuple)) || @@ -1269,14 +177,14 @@ function can_be_function_wrapped(x::Expr) x.head === :macrocall || x.head === :struct || x.head === :abstract || - (x.head === :(=) && is_function_assignment(x)) || # f(x) = ... + (x.head === :(=) && ExpressionExplorer.is_function_assignment(x)) || # f(x) = ... (x.head === :call && (x.args[1] === :eval || x.args[1] === :include)) false else all(can_be_function_wrapped, x.args) end - end + can_be_function_wrapped(x::Any) = true end diff --git a/src/analysis/FunctionDependencies.jl b/src/analysis/FunctionDependencies.jl deleted file mode 100644 index 52db2df2b5..0000000000 --- a/src/analysis/FunctionDependencies.jl +++ /dev/null @@ -1,45 +0,0 @@ -module FunctionDependencies - -const dependency_table = Dict{Symbol,Symbol}( - :√ => :sqrt, - :adjoint => :conj, - :< => :isless, - :> => :<, - :isgreater => :isless, - :ismore => :>, - :≥ => :(>=), - :≤ => :(<=), - :min => :isless, - :max => :isless, - :cmp => :isless, - :isequal => :(==), - :(!=) => :(==), - :≠ => :(!=), - :(!==) => :(===), - :≢ => :(!==), - :≡ => :(===), - :⊻ => :xor, - :⊼ => :nand, - :⊽ => :nor, - :% => :rem, - :÷ => :div, - :mod1 => :mod, - :∈ => :in, -) - -maybe_add_dependent_funccall!(funccalls::Set{Symbol}, ::Nothing) = funccalls -function maybe_add_dependent_funccall!(funccalls::Set{Symbol}, call) - push!(funccalls, call) - maybe_add_dependent_funccall!(funccalls, get(dependency_table, call, nothing)) - funccalls -end - -function maybe_add_dependent_funccalls!(funccalls::Set{Symbol}) - calls_to_add = intersect(keys(dependency_table), funccalls) - for call in calls_to_add - maybe_add_dependent_funccall!(funccalls, dependency_table[call]) - end - funccalls -end - -end diff --git a/src/analysis/MoreAnalysis.jl b/src/analysis/MoreAnalysis.jl index 232b5893e3..1e6dfe989d 100644 --- a/src/analysis/MoreAnalysis.jl +++ b/src/analysis/MoreAnalysis.jl @@ -3,12 +3,12 @@ module MoreAnalysis export bound_variable_connections_graph import ..Pluto -import ..Pluto: Cell, Notebook, NotebookTopology, ExpressionExplorer +import ..Pluto: Cell, Notebook, NotebookTopology, ExpressionExplorer, ExpressionExplorerExtras "Find all subexpressions of the form `@bind symbol something`, and extract the `symbol`s." function find_bound_variables(expr) found = Set{Symbol}() - _find_bound_variables!(found, ExpressionExplorer.maybe_macroexpand(expr; recursive=true, expand_bind=false)) + _find_bound_variables!(found, ExpressionExplorerExtras.maybe_macroexpand_pluto(expr; recursive=true, expand_bind=false)) found end @@ -62,7 +62,7 @@ end function _upstream_recursive!(found::Set{Cell}, notebook::Notebook, topology::NotebookTopology, from::Vector{Cell})::Nothing for cell in from references = topology.nodes[cell].references - for upstream in Pluto.where_assigned(notebook, topology, references) + for upstream in Pluto.where_assigned(topology, references) if upstream ∉ found push!(found, upstream) _upstream_recursive!(found, notebook, topology, Cell[upstream]) diff --git a/src/analysis/Parse.jl b/src/analysis/Parse.jl index 8fa7f10804..b3ac5162d5 100644 --- a/src/analysis/Parse.jl +++ b/src/analysis/Parse.jl @@ -1,4 +1,5 @@ import .ExpressionExplorer +import Markdown "Generate a file name to be given to the parser (will show up in stack traces)." pluto_filename(notebook::Notebook, cell::Cell)::String = notebook.path * "#==#" * string(cell.cell_id) @@ -6,18 +7,20 @@ pluto_filename(notebook::Notebook, cell::Cell)::String = notebook.path * "#==#" "Is Julia new enough to support filenames in parsing?" const can_insert_filename = (Base.parse_input_line("1;2") != Base.parse_input_line("1\n2")) -"Parse the code from `cell.code` into a Julia expression (`Expr`). Equivalent to `Meta.parse_input_line` in Julia v1.3, no matter the actual Julia version. +""" +Parse the code from `cell.code` into a Julia expression (`Expr`). Equivalent to `Meta.parse_input_line` in Julia v1.3, no matter the actual Julia version. 1. Turn multiple expressions into an error expression. 2. Fix some `LineNumberNode` idiosyncrasies to be more like modern Julia. 3. Will always produce an expression of the form: `Expr(:toplevel, LineNumberNode(..), root)`. It gets transformed (i.e. wrapped) into this form if needed. A `LineNumberNode` contains a line number and a file name. We use the cell UUID as a 'file name', which makes the stack traces easier to interpret. (Otherwise it would be impossible to tell from which cell a stack frame originates.) Not all Julia versions insert these `LineNumberNode`s, so we insert it ourselves if Julia doesn't. -4. Apply `preprocess_expr` (below) to `root` (from rule 2)." +4. Apply `preprocess_expr` (below) to `root` (from rule 2). +""" function parse_custom(notebook::Notebook, cell::Cell)::Expr # 1. raw = if can_insert_filename filename = pluto_filename(notebook, cell) ex = Base.parse_input_line(cell.code, filename=filename) - if (ex isa Expr) && (ex.head == :toplevel) + if Meta.isexpr(ex, :toplevel) # if there is more than one expression: if count(a -> !(a isa LineNumberNode), ex.args) > 1 Expr(:error, "extra token after end of expression\n\nBoundaries: $(expression_boundaries(cell.code))") @@ -81,7 +84,7 @@ fix_linenumbernodes!(::Any, actual_filename) = nothing `expression_boundaries("sqrt(1)\n\n123") == [ncodeunits("sqrt(1)\n\n") + 1, ncodeunits("sqrt(1)\n\n123") + 1]` """ -function expression_boundaries(code::String, start=1)::Array{<:Integer,1} +function expression_boundaries(code::String, start=1)::Vector{<:Integer} expr, next = Meta.parse(code, start, raise=false) if next <= ncodeunits(code) [next, expression_boundaries(code, next)...] @@ -90,18 +93,22 @@ function expression_boundaries(code::String, start=1)::Array{<:Integer,1} end end -"Make some small adjustments to the `expr` to make it work nicely inside a timed, wrapped expression: +""" +Make some small adjustments to the `expr` to make it work nicely inside a timed, wrapped expression: 1. If `expr` is a `:toplevel` expression (this is the case iff the expression is a combination of expressions using semicolons, like `a = 1; b` or `123;`), then it gets turned into a `:block` expression. The reason for this transformation is that `:toplevel` does not return/relay the output of its last argument, unlike `begin`, `let`, `if`, etc. (But we want it!) 2. If `expr` is a `:module` expression, wrap it in a `:toplevel` block - module creation needs to be at toplevel. Rule 1. is not applied. -3. If `expr` is a `:(=)` expression with a curly assignment, wrap it in a `:const` to allow execution - see https://github.com/fonsp/Pluto.jl/issues/517 " +3. If `expr` is a `:(=)` expression with a curly assignment, wrap it in a `:const` to allow execution - see https://github.com/fonsp/Pluto.jl/issues/517 +""" function preprocess_expr(expr::Expr) - if expr.head == :toplevel + if expr.head === :toplevel Expr(:block, expr.args...) - elseif expr.head == :module + elseif expr.head === :module Expr(:toplevel, expr) - elseif expr.head == :(=) && (expr.args[1] isa Expr && expr.args[1].head == :curly) + elseif expr.head === :(=) && (expr.args[1] isa Expr && expr.args[1].head == :curly) Expr(:const, expr) + elseif expr.head === :incomplete + Expr(:call, :(PlutoRunner.throw_syntax_error), expr.args...) else expr end diff --git a/src/analysis/ReactiveNode.jl b/src/analysis/ReactiveNode.jl deleted file mode 100644 index 927474db7d..0000000000 --- a/src/analysis/ReactiveNode.jl +++ /dev/null @@ -1,71 +0,0 @@ -import .ExpressionExplorer: SymbolsState, FunctionName, FunctionNameSignaturePair, try_compute_symbolreferences, generate_funcnames - -"Every cell is a node in the reactive graph. The nodes/point/vertices are the _cells_, and the edges/lines/arrows are the _dependencies between cells_. In a reactive notebook, these dependencies are the **global variable references and definitions**. (For the mathies: a reactive notebook is represented by a _directed multigraph_. A notebook without reactivity errors is an _acyclic directed multigraph_.) This struct contains the back edges (`references`) and forward edges (`definitions`, `soft_definitions`, `funcdefs_with_signatures`, `funcdefs_without_signatures`) of a single node. - -Before 0.12.0, we could have written this struct with just two fields: `references` and `definitions` (both of type `Set{Symbol}`) because we used variable names to form the reactive links. However, to support defining _multiple methods of the same function in different cells_ (https://github.com/fonsp/Pluto.jl/issues/177), we needed to change this. You might want to think about this old behavior first (try it on paper) before reading on. - -The essential idea is that edges are still formed by variable names. Simple global variables (`x = 1`) are registered by their name as `Symbol`, but _function definitions_ `f(x::Int) = 5` are sometimes stored in two ways: -- by their name (`f`) as `Symbol`, in `funcdefs_without_signatures`, and -- by their name with its method signature as `FunctionNameSignaturePair`, in `funcdefs_with_signatures`. - -The name _without_ signature is most important: it is used to find the reactive dependencies between cells. The name _with_ signature is needed to detect multiple cells that define methods with the _same_ signature (`f(x) = 1` and `f(x) = 2`) - this is illegal. This is why we do not collect `definitions`, `funcdefs_with_signatures` and `funcdefs_without_signatures` onto a single pile: we need them separately for different searches. -" -Base.@kwdef struct ReactiveNode - references::Set{Symbol} = Set{Symbol}() - definitions::Set{Symbol} = Set{Symbol}() - soft_definitions::Set{Symbol} = Set{Symbol}() - funcdefs_with_signatures::Set{FunctionNameSignaturePair} = Set{FunctionNameSignaturePair}() - funcdefs_without_signatures::Set{Symbol} = Set{Symbol}() - macrocalls::Set{Symbol} = Set{Symbol}() -end - -function Base.union!(a::ReactiveNode, bs::ReactiveNode...) - union!(a.references, (b.references for b in bs)...) - union!(a.definitions, (b.definitions for b in bs)...) - union!(a.soft_definitions, (b.soft_definitions for b in bs)...) - union!(a.funcdefs_with_signatures, (b.funcdefs_with_signatures for b in bs)...) - union!(a.funcdefs_without_signatures, (b.funcdefs_without_signatures for b in bs)...) - union!(a.macrocalls, (b.macrocalls for b in bs)...) - return a -end - -"Turn a `SymbolsState` into a `ReactiveNode`. The main differences are: -- A `SymbolsState` is a nested structure of function definitions inside function definitions inside... This conversion flattens this structure by merging `SymbolsState`s from defined functions. -- `ReactiveNode` functions as a cache to improve efficienty, by turning the nested structures into multiple `Set{Symbol}`s with fast lookups." -function ReactiveNode(symstate::SymbolsState) - macrocalls = join_funcname_parts.(symstate.macrocalls) |> Set{Symbol} - result = ReactiveNode( - references=Set{Symbol}(symstate.references), - definitions=Set{Symbol}(symstate.assignments), - macrocalls=macrocalls, - ) - - # defined functions are 'exploded' into the cell's reactive node - union!(result, (ReactiveNode(body_symstate) for (_, body_symstate) in symstate.funcdefs)...) - - # now we will add the function names to our edges: - funccalls = Set{Symbol}(symstate.funccalls .|> join_funcname_parts) - FunctionDependencies.maybe_add_dependent_funccalls!(funccalls) - union!(result.references, funccalls) - - union!(result.references, macrocalls) - - for (namesig, body_symstate) in symstate.funcdefs - push!(result.funcdefs_with_signatures, namesig) - push!(result.funcdefs_without_signatures, join_funcname_parts(namesig.name)) - - generated_names = generate_funcnames(namesig.name) - generated_names_syms = Set{Symbol}(join_funcname_parts.(generated_names)) - - # add the generated names so that they are added as soft definitions - # this means that they will not be used if a cycle is created - union!(result.soft_definitions, generated_names_syms) - - filter!(!∈(generated_names_syms), result.references) # don't reference defined functions (simulated recursive calls) - end - - return result -end - -# Convenience functions -ReactiveNode(code::String) = ReactiveNode(try_compute_symbolreferences(Meta.parse(code))) diff --git a/src/analysis/TopologicalOrder.jl b/src/analysis/TopologicalOrder.jl index 4fa1e49521..bd159522bf 100644 --- a/src/analysis/TopologicalOrder.jl +++ b/src/analysis/TopologicalOrder.jl @@ -4,7 +4,7 @@ import .ExpressionExplorer: SymbolsState, FunctionName Base.@kwdef struct TopologicalOrder input_topology::NotebookTopology "Cells that form a directed acyclic graph, in topological order." - runnable::Array{Cell,1} + runnable::Vector{Cell} "Cells that are in a directed cycle, with corresponding `ReactivityError`s." errable::Dict{Cell,ReactivityError} end diff --git a/src/analysis/Topology.jl b/src/analysis/Topology.jl index 7c26c0b8d7..6a4ab6ade0 100644 --- a/src/analysis/Topology.jl +++ b/src/analysis/Topology.jl @@ -15,7 +15,7 @@ ExprAnalysisCache(notebook, cell::Cell) = let code=cell.code, parsedcode=parsedcode, module_usings_imports=ExpressionExplorer.compute_usings_imports(parsedcode), - function_wrapped=ExpressionExplorer.can_be_function_wrapped(parsedcode), + function_wrapped=ExpressionExplorerExtras.can_be_function_wrapped(parsedcode), ) end @@ -25,42 +25,51 @@ function ExprAnalysisCache(old_cache::ExprAnalysisCache; new_properties...) ExprAnalysisCache(;properties...) end -struct DefaultDict{K,V} <: AbstractDict{K,V} - default::Union{Function,DataType} - container::Dict{K,V} -end - - "The (information needed to create the) dependency graph of a notebook. Cells are linked by the names of globals that they define and reference. 🕸" Base.@kwdef struct NotebookTopology - nodes::DefaultDict{Cell,ReactiveNode} = DefaultDict{Cell,ReactiveNode}(ReactiveNode) - codes::DefaultDict{Cell,ExprAnalysisCache}=DefaultDict{Cell,ExprAnalysisCache}(ExprAnalysisCache) + nodes::ImmutableDefaultDict{Cell,ReactiveNode}=ImmutableDefaultDict{Cell,ReactiveNode}(ReactiveNode) + codes::ImmutableDefaultDict{Cell,ExprAnalysisCache}=ImmutableDefaultDict{Cell,ExprAnalysisCache}(ExprAnalysisCache) + cell_order::ImmutableVector{Cell}=ImmutableVector{Cell}() - unresolved_cells::Set{Cell} = Set{Cell}() + unresolved_cells::ImmutableSet{Cell} = ImmutableSet{Cell}() + disabled_cells::ImmutableSet{Cell} = ImmutableSet{Cell}() end +# BIG TODO HERE: CELL ORDER +all_cells(topology::NotebookTopology) = topology.cell_order.c is_resolved(topology::NotebookTopology) = isempty(topology.unresolved_cells) +is_resolved(topology::NotebookTopology, c::Cell) = c in topology.unresolved_cells + +is_disabled(topology::NotebookTopology, c::Cell) = c in topology.disabled_cells function set_unresolved(topology::NotebookTopology, unresolved_cells::Vector{Cell}) - codes = Dict{Cell,ExprAnalysisCache}(cell => ExprAnalysisCache(topology.codes[cell]; function_wrapped=false, forced_expr_id=nothing) for cell in unresolved_cells) - NotebookTopology(nodes=topology.nodes, codes=merge(topology.codes, codes), unresolved_cells=union(topology.unresolved_cells, unresolved_cells)) + codes = Dict{Cell,ExprAnalysisCache}( + cell => ExprAnalysisCache(topology.codes[cell]; function_wrapped=false, forced_expr_id=nothing) + for cell in unresolved_cells + ) + NotebookTopology( + nodes=topology.nodes, + codes=merge(topology.codes, codes), + unresolved_cells=union(topology.unresolved_cells, unresolved_cells), + cell_order=topology.cell_order, + disabled_cells=topology.disabled_cells, + ) end -DefaultDict{K,V}(default::Union{Function,DataType}) where {K,V} = DefaultDict{K,V}(default, Dict{K,V}()) -function Base.getindex(aid::DefaultDict{K,V}, key::K)::V where {K,V} - get!(aid.default, aid.container, key) -end -function Base.merge(a1::DefaultDict{K,V}, a2::DefaultDict{K,V}) where {K,V} - DefaultDict{K,V}(a1.default, merge(a1.container, a2.container)) -end -function Base.merge(a1::DefaultDict{K,V}, a2::AbstractDict) where {K,V} - DefaultDict{K,V}(a1.default, merge(a1.container, a2)) +""" + exclude_roots(topology::NotebookTopology, roots_to_exclude)::NotebookTopology + +Returns a new topology as if `topology` was created with all code for `roots_to_exclude` +being empty, preserving disabled cells and cell order. +""" +function exclude_roots(topology::NotebookTopology, cells::Vector{Cell}) + NotebookTopology( + nodes=setdiffkeys(topology.nodes, cells), + codes=setdiffkeys(topology.codes, cells), + unresolved_cells=ImmutableSet{Cell}(setdiff(topology.unresolved_cells.c, cells); skip_copy=true), + cell_order=topology.cell_order, + disabled_cells=topology.disabled_cells, + ) end -Base.setindex!(aid::DefaultDict, args...) = Base.setindex!(aid.container, args...) -Base.delete!(aid::DefaultDict, args...) = Base.delete!(aid.container, args...) -Base.keys(aid::DefaultDict) = Base.keys(aid.container) -Base.values(aid::DefaultDict) = Base.values(aid.container) -Base.length(aid::DefaultDict) = Base.length(aid.container) -Base.iterate(aid::DefaultDict, args...) = Base.iterate(aid.container, args...) diff --git a/src/analysis/TopologyUpdate.jl b/src/analysis/TopologyUpdate.jl index 2378396eb7..6723087eb5 100644 --- a/src/analysis/TopologyUpdate.jl +++ b/src/analysis/TopologyUpdate.jl @@ -1,43 +1,89 @@ import .ExpressionExplorer -import .ExpressionExplorer: join_funcname_parts, SymbolsState, FunctionNameSignaturePair +import .ExpressionExplorerExtras +import .ExpressionExplorer: SymbolsState, FunctionNameSignaturePair "Return a copy of `old_topology`, but with recomputed results from `cells` taken into account." function updated_topology(old_topology::NotebookTopology, notebook::Notebook, cells) updated_codes = Dict{Cell,ExprAnalysisCache}() updated_nodes = Dict{Cell,ReactiveNode}() - unresolved_cells = copy(old_topology.unresolved_cells) + for cell in cells old_code = old_topology.codes[cell] if old_code.code !== cell.code new_code = updated_codes[cell] = ExprAnalysisCache(notebook, cell) - new_symstate = new_code.parsedcode |> - ExpressionExplorer.try_compute_symbolreferences - new_reactive_node = ReactiveNode(new_symstate) + new_reactive_node = ExpressionExplorer.compute_reactive_node(ExpressionExplorerExtras.pretransform_pluto(new_code.parsedcode)) updated_nodes[cell] = new_reactive_node elseif old_code.forced_expr_id !== nothing # reset computer code updated_codes[cell] = ExprAnalysisCache(old_code; forced_expr_id=nothing, function_wrapped=false) end + end + + + old_cells = all_cells(old_topology) + removed_cells = setdiff(old_cells, notebook.cells) + if isempty(removed_cells) + # We can keep identity + new_codes = merge(old_topology.codes, updated_codes) + new_nodes = merge(old_topology.nodes, updated_nodes) + else + new_codes = merge(setdiffkeys(old_topology.codes, removed_cells), updated_codes) + new_nodes = merge(setdiffkeys(old_topology.nodes, removed_cells), updated_nodes) + end - new_reactive_node = get(updated_nodes, cell, old_topology.nodes[cell]) - if !isempty(new_reactive_node.macrocalls) - # The unresolved cells are the cells for wich we cannot create - # a ReactiveNode yet, because they contains macrocalls. - push!(unresolved_cells, cell) - else - pop!(unresolved_cells, cell, nothing) - end + new_unresolved_set = setdiff!( + union!( + Set{Cell}(), + # all cells that were unresolved before, and did not change code... + Iterators.filter(old_topology.unresolved_cells) do c + !haskey(updated_nodes, c) + end, + # ...plus all cells that changed, and now use a macrocall... + Iterators.filter(cells) do c + !isempty(new_nodes[c].macrocalls) + end, + ), + # ...minus cells that were removed. + removed_cells, + ) + + new_disabled_set = setdiff!( + union!( + Set{Cell}(), + # all cells that were disabled before... + old_topology.disabled_cells, + # ...plus all cells that changed... + cells, + ), + # ...minus cells that changed and are not disabled. + Iterators.filter(!is_disabled, cells), + ) + + unresolved_cells = if new_unresolved_set == old_topology.unresolved_cells + old_topology.unresolved_cells + else + ImmutableSet(new_unresolved_set; skip_copy=true) end - new_codes = merge(old_topology.codes, updated_codes) - new_nodes = merge(old_topology.nodes, updated_nodes) - for removed_cell in setdiff(keys(old_topology.nodes), notebook.cells) - delete!(new_nodes, removed_cell) - delete!(new_codes, removed_cell) - delete!(unresolved_cells, removed_cell) + disabled_cells = if new_disabled_set == old_topology.disabled_cells + old_topology.disabled_cells + else + ImmutableSet(new_disabled_set; skip_copy=true) end - NotebookTopology(nodes=new_nodes, codes=new_codes, unresolved_cells=unresolved_cells) + cell_order = if old_cells == notebook.cells + old_topology.cell_order + else + ImmutableVector(notebook.cells) # makes a copy + end + + NotebookTopology(; + nodes=new_nodes, + codes=new_codes, + unresolved_cells, + disabled_cells, + cell_order, + ) end diff --git a/src/analysis/data structures.jl b/src/analysis/data structures.jl new file mode 100644 index 0000000000..0ecb292ef0 --- /dev/null +++ b/src/analysis/data structures.jl @@ -0,0 +1,110 @@ + +begin + """ + ```julia + ImmutableSet{T}(xs::Set{T}) + ``` + + Wraps around, and behaves like a regular `Set`, but mutating operations (like `push!` or `empty!`) are not allowed. + + When called on a set, a *shallow copy* of the set is stored. This means that it's fine to mutate the input set after creating an `ImmutableSet` from it. To prevent this, call `ImmutableSet(xs; skip_copy=true)`. + """ + struct ImmutableSet{T} <: AbstractSet{T} + c::Set{T} + ImmutableSet{T}(s::Set{T}; skip_copy::Bool=false) where T = new{T}(skip_copy ? s : copy(s)) + end + ImmutableSet(s::Set{T}; skip_copy::Bool=false) where T = ImmutableSet{T}(s; skip_copy) + + ImmutableSet(arg) = let + s = Set(arg) + ImmutableSet{eltype(s)}(s; skip_copy=true) + end + ImmutableSet{T}() where T = ImmutableSet{T}(Set{T}(); skip_copy=true) + ImmutableSet() = ImmutableSet(Set(); skip_copy=true) + + Base.copy(s::ImmutableSet) = ImmutableSet(copy(s.c)) + Base.in(x, s::ImmutableSet) = Base.in(x, s.c) + Base.isempty(s::ImmutableSet) = Base.isempty(s.c) + Base.length(s::ImmutableSet) = Base.length(s.c) + Base.iterate(s::ImmutableSet, i...) = Base.iterate(s.c, i...) + Base.setdiff(s::ImmutableSet, i...) = ImmutableSet(setdiff(s.c, i...)) +end + +begin + """ + ```julia + ImmutableVector{T}(xs::Vector{T}) + ``` + + Wraps around, and behaves like a regular `Vector`, but mutating operations (like `push!` or `setindex!`) are not allowed. + + When called on a vector, a *shallow copy* of the vector is stored. This means that it's fine to mutate the input vector after creating an `ImmutableVector` from it. To prevent this, call `ImmutableVector(xs; skip_copy=true)`. + """ + struct ImmutableVector{T} <: AbstractVector{T} + c::Vector{T} + ImmutableVector{T}(x; skip_copy::Bool=false) where T = new{T}(skip_copy ? x : copy(x)) + end + ImmutableVector(x::AbstractVector{T}; kwargs...) where T = ImmutableVector{T}(x; kwargs...) + ImmutableVector{T}() where T = ImmutableVector{T}(Vector{T}()) + + Base.copy(s::ImmutableVector) = ImmutableVector(copy(s.c)) + Base.in(x, s::ImmutableVector) = Base.in(x, s.c) + Base.isempty(s::ImmutableVector) = Base.isempty(s.c) + Base.length(s::ImmutableVector) = Base.length(s.c) + Base.size(s::ImmutableVector) = Base.size(s.c) + Base.iterate(s::ImmutableVector, i...) = Base.iterate(s.c, i...) + Base.getindex(s::ImmutableVector, i::Integer) = Base.getindex(s.c, i) + Base.getindex(s::ImmutableVector, i...) = ImmutableVector(Base.getindex(s.c, i...)) + delete_unsafe!(s::ImmutableSet, args...) = Base.delete!(s.c, args...) +end + +begin + """ + ```julia + ImmutableDefaultDict{K,V}(default::Function, container::Dict{K,V}) + ``` + + Wraps around, and behaves like a regular `Dict`, but if a key is not found, it will call return `default()`. + """ + struct ImmutableDefaultDict{K,V} <: AbstractDict{K,V} + default::Union{Function,DataType} + container::Dict{K,V} + end + + ImmutableDefaultDict{K,V}(default::Union{Function,DataType}) where {K,V} = ImmutableDefaultDict{K,V}(default, Dict{K,V}()) + + function Base.getindex(aid::ImmutableDefaultDict{K,V}, key::K)::V where {K,V} + get!(aid.default, aid.container, key) + end + function Base.merge(a1::ImmutableDefaultDict{K,V}, a2::ImmutableDefaultDict{K,V}) where {K,V} + isempty(a2) ? a1 : ImmutableDefaultDict{K,V}(a1.default, merge(a1.container, a2.container)) + end + function Base.merge(a1::ImmutableDefaultDict{K,V}, a2::AbstractDict) where {K,V} + isempty(a2) ? a1 : ImmutableDefaultDict{K,V}(a1.default, merge(a1.container, a2)) + end + # disabled because it's immutable! + # Base.setindex!(aid::ImmutableDefaultDict{K,V}, args...) where {K,V} = Base.setindex!(aid.container, args...) + # Base.delete!(aid::ImmutableDefaultDict{K,V}, args...) where {K,V} = Base.delete!(aid.container, args...) + delete_unsafe!(aid::ImmutableDefaultDict{K,V}, args...) where {K,V} = Base.delete!(aid.container, args...) + Base.copy(aid::ImmutableDefaultDict{K,V}) where {K,V} = ImmutableDefaultDict{K,V}(aid.default, copy(aid.container)) + Base.keys(aid::ImmutableDefaultDict) = Base.keys(aid.container) + Base.values(aid::ImmutableDefaultDict) = Base.values(aid.container) + Base.length(aid::ImmutableDefaultDict) = Base.length(aid.container) + Base.iterate(aid::ImmutableDefaultDict, args...) = Base.iterate(aid.container, args...) +end + +""" +```julia +setdiffkeys(d::Dict{K,V}, key_itrs...)::Dict{K,V} +``` + +Apply `setdiff` on the keys of a dictionary. + +# Example +```julia +setdiffkeys(Dict(1 => "one", 2 => "two", 3 => "three"), [1, 3]) +# result: `Dict(2 => "two")` +``` +""" +setdiffkeys(d::Dict{K,V}, key_itrs...) where {K,V} = Dict{K,V}(k => d[k] for k in setdiff(keys(d), key_itrs...)) +setdiffkeys(d::ImmutableDefaultDict{K,V}, key_itrs...) where {K,V} = ImmutableDefaultDict{K,V}(d.default, setdiffkeys(d.container, key_itrs...)) diff --git a/src/analysis/is_just_text.jl b/src/analysis/is_just_text.jl index f4402a6b2a..525cf27270 100644 --- a/src/analysis/is_just_text.jl +++ b/src/analysis/is_just_text.jl @@ -1,13 +1,23 @@ -const md_and_friends = [Symbol("@md_str"), Symbol("@html_str"), :getindex] +const md_and_friends = [ + # Text + Symbol("@md_str"), + Symbol("@html_str"), + :getindex, +] """Does the cell only contain md"..." and html"..."? This is used to run these cells first.""" function is_just_text(topology::NotebookTopology, cell::Cell)::Bool # https://github.com/fonsp/Pluto.jl/issues/209 - isempty(topology.nodes[cell].definitions) && isempty(topology.nodes[cell].funcdefs_with_signatures) && - topology.nodes[cell].references ⊆ md_and_friends && - no_loops(ExpressionExplorer.maybe_macroexpand(topology.codes[cell].parsedcode; recursive=true)) + node = topology.nodes[cell] + ((isempty(node.definitions) && + isempty(node.funcdefs_with_signatures) && + node.references ⊆ md_and_friends) || + (length(node.references) == 2 && + :PlutoRunner in node.references && + Symbol("PlutoRunner.throw_syntax_error") in node.references)) && + no_loops(ExpressionExplorerExtras.maybe_macroexpand_pluto(topology.codes[cell].parsedcode; recursive=true)) end function no_loops(ex::Expr) @@ -24,4 +34,4 @@ function no_loops(ex::Expr) end end -no_loops(x) = true \ No newline at end of file +no_loops(x) = true diff --git a/src/analysis/topological_order.jl b/src/analysis/topological_order.jl index d9bafd6cee..7fa0d1b2d5 100644 --- a/src/analysis/topological_order.jl +++ b/src/analysis/topological_order.jl @@ -5,8 +5,35 @@ struct Cycle <: ChildExplorationResult cycled_cells::Vector{Cell} end -"Return a `TopologicalOrder` that lists the cells to be evaluated in a single reactive run, in topological order. Includes the given roots." -function topological_order(notebook::Notebook, topology::NotebookTopology, roots::Array{Cell,1}; allow_multiple_defs=false)::TopologicalOrder +@deprecate topological_order(::Notebook, topology::NotebookTopology, args...; kwargs...) topological_order(topology, args...; kwargs...) + +""" +Return a `TopologicalOrder` that lists the cells to be evaluated in a single reactive run, in topological order. Includes the given roots. + +# Keyword arguments + +- `allow_multiple_defs::Bool = false` + + If `false` (default), multiple definitions are not allowed. When a cell is found that defines a variable that is also defined by another cell (this other cell is called a *fellow assigner*), then both cells are marked as `errable` and not `runnable`. + + If `true`, then multiple definitions are allowed, in the sense that we ignore the existance of other cells that define the same variable. + + +- `skip_at_partial_multiple_defs::Bool = false` + + If `true` (not default), and `allow_multiple_defs = true` (not default), then the search stops going downward when finding a cell that has fellow assigners, *unless all fellow assigners can be reached by the `roots`*, in which case we continue searching downward. + + In other words, if there is a set of fellow assigners that can only be reached **partially** by the roots, then this set blocks the search, and cells that depend on the set are not found. +""" +function topological_order(topology::NotebookTopology, roots::AbstractVector{Cell}; + allow_multiple_defs::Bool=false, + skip_at_partial_multiple_defs::Bool=false, +)::TopologicalOrder + + if skip_at_partial_multiple_defs + @assert allow_multiple_defs + end + entries = Cell[] exits = Cell[] errable = Dict{Cell,ReactivityError}() @@ -17,7 +44,7 @@ function topological_order(notebook::Notebook, topology::NotebookTopology, roots return Ok() elseif haskey(errable, cell) return Ok() - elseif length(entries) > 0 && entries[end] == cell + elseif length(entries) > 0 && entries[end] === cell return Ok() # a cell referencing itself is legal elseif cell in entries currently_in = setdiff(entries, exits) @@ -39,15 +66,30 @@ function topological_order(notebook::Notebook, topology::NotebookTopology, roots push!(entries, cell) - assigners = where_assigned(notebook, topology, cell) + assigners = where_assigned(topology, cell) + referencers = where_referenced(topology, cell) |> Iterators.reverse + if !allow_multiple_defs && length(assigners) > 1 for c in assigners errable[c] = MultipleDefinitionsError(topology, c, assigners) end end - referencers = where_referenced(notebook, topology, cell) |> Iterators.reverse - for c in (allow_multiple_defs ? referencers : union(assigners, referencers)) - if c != cell + + should_continue_search_down = !skip_at_partial_multiple_defs || all(c -> c === cell || c ∈ exits, assigners) + should_search_fellow_assigners_if_any = !allow_multiple_defs + + to_search_next = if should_continue_search_down + if should_search_fellow_assigners_if_any + union(assigners, referencers) + else + referencers + end + else + Cell[] + end + + for c in to_search_next + if c !== cell child_result = bfs(c) # No cycle for this child or the cycle has no soft edges @@ -72,11 +114,11 @@ function topological_order(notebook::Notebook, topology::NotebookTopology, roots delete!(errable, cycled_cell) end # 2. Remove the current child (c) from the entries if it was just added - if entries[end] == c + if entries[end] === c pop!(entries) end - continue # the cycle was created by us so we can keep exploring other childs + continue # the cycle was created by us so we can keep exploring other children end end push!(exits, cell) @@ -87,8 +129,9 @@ function topological_order(notebook::Notebook, topology::NotebookTopology, roots # we use MergeSort because it is a stable sort: leaves cells in order if they are in the same category prelim_order_1 = sort(roots, alg=MergeSort, by=c -> cell_precedence_heuristic(topology, c)) # reversing because our search returns reversed order - prelim_order_2 = Iterators.reverse(prelim_order_1) - bfs.(prelim_order_2) + for i in length(prelim_order_1):-1:1 + bfs(prelim_order_1[i]) + end ordered = reverse(exits) TopologicalOrder(topology, setdiff(ordered, keys(errable)), errable) end @@ -96,7 +139,7 @@ end function topological_order(notebook::Notebook) cached = notebook._cached_topological_order if cached === nothing || cached.input_topology !== notebook.topology - topological_order(notebook, notebook.topology, notebook.cells) + topological_order(notebook.topology, all_cells(notebook.topology)) else cached end @@ -104,21 +147,22 @@ end Base.collect(notebook_topo_order::TopologicalOrder) = union(notebook_topo_order.runnable, keys(notebook_topo_order.errable)) -function disjoint(a::Set, b::Set) +function disjoint(a, b) !any(x in a for x in b) end "Return the cells that reference any of the symbols defined by the given cell. Non-recursive: only direct dependencies are found." -function where_referenced(notebook::Notebook, topology::NotebookTopology, myself::Cell)::Array{Cell,1} +function where_referenced(topology::NotebookTopology, myself::Cell)::Vector{Cell} to_compare = union(topology.nodes[myself].definitions, topology.nodes[myself].soft_definitions, topology.nodes[myself].funcdefs_without_signatures) - where_referenced(notebook, topology, to_compare) + where_referenced(topology, to_compare) end "Return the cells that reference any of the given symbols. Non-recursive: only direct dependencies are found." -function where_referenced(notebook::Notebook, topology::NotebookTopology, to_compare::Set{Symbol})::Array{Cell,1} - return filter(notebook.cells) do cell +function where_referenced(topology::NotebookTopology, to_compare::Set{Symbol})::Vector{Cell} + return filter(all_cells(topology)) do cell !disjoint(to_compare, topology.nodes[cell].references) end end +where_referenced(::Notebook, args...) = where_referenced(args...) "Returns whether or not the edge between two cells is composed only of \"soft\"-definitions" function is_soft_edge(topology::NotebookTopology, parent_cell::Cell, child_cell::Cell) @@ -132,9 +176,12 @@ end "Return the cells that also assign to any variable or method defined by the given cell. If more than one cell is returned (besides the given cell), then all of them should throw a `MultipleDefinitionsError`. Non-recursive: only direct dependencies are found." -function where_assigned(notebook::Notebook, topology::NotebookTopology, myself::Cell)::Array{Cell,1} - self = topology.nodes[myself] - return filter(notebook.cells) do cell +function where_assigned(topology::NotebookTopology, myself::Cell)::Vector{Cell} + where_assigned(topology, topology.nodes[myself]) +end + +function where_assigned(topology::NotebookTopology, self::ReactiveNode)::Vector{Cell} + return filter(all_cells(topology)) do cell other = topology.nodes[cell] !( disjoint(self.definitions, other.definitions) && @@ -147,8 +194,8 @@ function where_assigned(notebook::Notebook, topology::NotebookTopology, myself:: end end -function where_assigned(notebook::Notebook, topology::NotebookTopology, to_compare::Set{Symbol})::Array{Cell,1} - filter(notebook.cells) do cell +function where_assigned(topology::NotebookTopology, to_compare::Set{Symbol})::Vector{Cell} + filter(all_cells(topology)) do cell other = topology.nodes[cell] !( disjoint(to_compare, other.definitions) && @@ -156,6 +203,8 @@ function where_assigned(notebook::Notebook, topology::NotebookTopology, to_compa ) end end +where_assigned(::Notebook, args...) = where_assigned(args...) + "Return whether any cell references the given symbol. Used for the @bind mechanism." function is_referenced_anywhere(notebook::Notebook, topology::NotebookTopology, sym::Symbol)::Bool @@ -188,39 +237,43 @@ function cycle_is_among_functions(topology::NotebookTopology, cycle::AbstractVec end +function cell_precedence_heuristic(topology::NotebookTopology, cell::Cell) + cell_precedence_heuristic(topology.nodes[cell], topology.codes[cell]) +end + + """Assigns a number to a cell - cells with a lower number might run first. This is used to treat reactive dependencies between cells that cannot be found using static code anylsis.""" -function cell_precedence_heuristic(topology::NotebookTopology, cell::Cell)::Real - top = topology.nodes[cell] - if :Pkg ∈ top.definitions +function cell_precedence_heuristic(node::ReactiveNode, code::ExprAnalysisCache)::Real + if :Pkg ∈ node.definitions 1 - elseif :DrWatson ∈ top.definitions + elseif :DrWatson ∈ node.definitions 2 - elseif Symbol("Pkg.API.activate") ∈ top.references || - Symbol("Pkg.activate") ∈ top.references || - Symbol("@pkg_str") ∈ top.references || + elseif Symbol("Pkg.API.activate") ∈ node.references || + Symbol("Pkg.activate") ∈ node.references || + Symbol("@pkg_str") ∈ node.references || # https://juliadynamics.github.io/DrWatson.jl/dev/project/#DrWatson.quickactivate - Symbol("quickactivate") ∈ top.references || - Symbol("@quickactivate") ∈ top.references || - Symbol("DrWatson.@quickactivate") ∈ top.references || - Symbol("DrWatson.quickactivate") ∈ top.references + Symbol("quickactivate") ∈ node.references || + Symbol("@quickactivate") ∈ node.references || + Symbol("DrWatson.@quickactivate") ∈ node.references || + Symbol("DrWatson.quickactivate") ∈ node.references 3 - elseif Symbol("Pkg.API.add") ∈ top.references || - Symbol("Pkg.add") ∈ top.references || - Symbol("Pkg.API.develop") ∈ top.references || - Symbol("Pkg.develop") ∈ top.references + elseif Symbol("Pkg.API.add") ∈ node.references || + Symbol("Pkg.add") ∈ node.references || + Symbol("Pkg.API.develop") ∈ node.references || + Symbol("Pkg.develop") ∈ node.references 4 - elseif :LOAD_PATH ∈ top.references + elseif :LOAD_PATH ∈ node.references # https://github.com/fonsp/Pluto.jl/issues/323 5 - elseif :Revise ∈ top.definitions + elseif :Revise ∈ node.definitions # Load Revise before other packages so that it can properly `revise` them. 6 - elseif !isempty(topology.codes[cell].module_usings_imports.usings) + elseif !isempty(code.module_usings_imports.usings) # always do `using X` before other cells, because we don't (yet) know which cells depend on it (we only know it with `import X` and `import X: y, z`) 7 - elseif :include ∈ top.references + elseif :include ∈ node.references # https://github.com/fonsp/Pluto.jl/issues/193 # because we don't (yet) know which cells depend on it 8 diff --git a/src/evaluation/MacroAnalysis.jl b/src/evaluation/MacroAnalysis.jl new file mode 100644 index 0000000000..06bb8c779b --- /dev/null +++ b/src/evaluation/MacroAnalysis.jl @@ -0,0 +1,212 @@ +# Macro Analysis & Topology Resolution (see https://github.com/fonsp/Pluto.jl/pull/1032) + +import .WorkspaceManager: macroexpand_in_workspace + +const lazymap = Base.Generator + +function defined_variables(topology::NotebookTopology, cells) + lazymap(cells) do cell + topology.nodes[cell].definitions + end +end + +function defined_functions(topology::NotebookTopology, cells) + lazymap(cells) do cell + ((cell.cell_id, namesig.name) for namesig in topology.nodes[cell].funcdefs_with_signatures) + end +end + +is_macro_identifier(symbol::Symbol) = startswith(string(symbol), "@") + +function with_new_soft_definitions(topology::NotebookTopology, cell::Cell, soft_definitions) + old_node = topology.nodes[cell] + new_node = union!(ReactiveNode(), old_node, ReactiveNode(soft_definitions=soft_definitions)) + NotebookTopology( + codes=topology.codes, + nodes=merge(topology.nodes, Dict(cell => new_node)), + unresolved_cells=topology.unresolved_cells, + cell_order=topology.cell_order, + disabled_cells=topology.disabled_cells, + ) +end + +collect_implicit_usings(topology::NotebookTopology, cell::Cell) = + ExpressionExplorerExtras.collect_implicit_usings(topology.codes[cell].module_usings_imports) + +function cells_with_deleted_macros(old_topology::NotebookTopology, new_topology::NotebookTopology) + old_macros = mapreduce(c -> defined_macros(old_topology, c), union!, all_cells(old_topology); init=Set{Symbol}()) + new_macros = mapreduce(c -> defined_macros(new_topology, c), union!, all_cells(new_topology); init=Set{Symbol}()) + removed_macros = setdiff(old_macros, new_macros) + + where_referenced(old_topology, removed_macros) +end + +"Returns the set of macros names defined by this cell" +defined_macros(topology::NotebookTopology, cell::Cell) = defined_macros(topology.nodes[cell]) +defined_macros(node::ReactiveNode) = union!(filter(is_macro_identifier, node.funcdefs_without_signatures), filter(is_macro_identifier, node.definitions)) # macro definitions can come from imports + +"Tells whether or not a cell can 'unlock' the resolution of other cells" +function can_help_resolve_cells(topology::NotebookTopology, cell::Cell) + cell_code = topology.codes[cell] + cell_node = topology.nodes[cell] + macros = defined_macros(cell_node) + + !isempty(cell_code.module_usings_imports.usings) || + (!isempty(macros) && any(calls -> !disjoint(calls, macros), topology.nodes[c].macrocalls for c in topology.unresolved_cells)) +end + +# Sorry couldn't help myself - DRAL +abstract type Result end +struct Success <: Result + result +end +struct Failure <: Result + error +end +struct Skipped <: Result end + +"""We still have 'unresolved' macrocalls, use the current and maybe previous workspace to do macro-expansions. + +You can optionally specify the roots for the current reactive run. If a cell macro contains only macros that will +be re-defined during this reactive run, we don't expand yet and expect the `can_help_resolve_cells` function above +to be true for the cell defining the macro, triggering a new topology resolution without needing to fallback to the +previous workspace. +""" +function resolve_topology( + session::ServerSession, + notebook::Notebook, + unresolved_topology::NotebookTopology, + old_workspace_name::Symbol; + current_roots::Vector{Cell}=Cell[], +)::NotebookTopology + + + sn = (session, notebook) + + function macroexpand_cell(cell) + try_macroexpand(module_name::Symbol=Symbol("")) = begin + success, result = macroexpand_in_workspace(sn, unresolved_topology.codes[cell].parsedcode, cell.cell_id, module_name) + if success + Success(result) + else + Failure(result) + end + end + + result = try_macroexpand() + if result isa Success + result + else + if (result.error isa LoadError && result.error.error isa UndefVarError) || result.error isa UndefVarError + try_macroexpand(old_workspace_name) + else + result + end + end + end + + function analyze_macrocell(cell::Cell) + if unresolved_topology.nodes[cell].macrocalls ⊆ ExpressionExplorerExtras.can_macroexpand + return Skipped() + end + + result = macroexpand_cell(cell) + if result isa Success + (expr, computer_id) = result.result + expanded_node = ExpressionExplorer.compute_reactive_node(ExpressionExplorerExtras.pretransform_pluto(expr)) + function_wrapped = ExpressionExplorerExtras.can_be_function_wrapped(expr) + Success((expanded_node, function_wrapped, computer_id)) + else + result + end + end + + run_defined_macros = mapreduce(c -> defined_macros(unresolved_topology, c), union!, current_roots; init=Set{Symbol}()) + + # create new node & new codes for macrocalled cells + new_nodes = Dict{Cell,ReactiveNode}() + new_codes = Dict{Cell,ExprAnalysisCache}() + still_unresolved_nodes = Set{Cell}() + + for cell in unresolved_topology.unresolved_cells + if unresolved_topology.nodes[cell].macrocalls ⊆ run_defined_macros + # Do not try to expand if a newer version of the macro is also scheduled to run in the + # current run. The recursive reactive runs will take care of it. + push!(still_unresolved_nodes, cell) + continue + end + + result = try + if will_run_code(notebook) + analyze_macrocell(cell) + else + Failure(ErrorException("shutdown")) + end + catch error + @error "Macro call expansion failed with a non-macroexpand error" error + Failure(error) + end + if result isa Success + (new_node, function_wrapped, forced_expr_id) = result.result + union!(new_node.macrocalls, unresolved_topology.nodes[cell].macrocalls) + union!(new_node.references, new_node.macrocalls) + new_nodes[cell] = new_node + + # set function_wrapped to the function wrapped analysis of the expanded expression. + new_codes[cell] = ExprAnalysisCache(unresolved_topology.codes[cell]; forced_expr_id, function_wrapped) + elseif result isa Skipped + # Skipped because it has already been resolved during ExpressionExplorer. + else + @debug "Could not resolve" result cell.code + push!(still_unresolved_nodes, cell) + end + end + + all_nodes = merge(unresolved_topology.nodes, new_nodes) + all_codes = merge(unresolved_topology.codes, new_codes) + + new_unresolved_cells = if length(still_unresolved_nodes) == length(unresolved_topology.unresolved_cells) + # then they must equal, and we can skip creating a new one to preserve identity: + unresolved_topology.unresolved_cells + else + ImmutableSet(still_unresolved_nodes; skip_copy=true) + end + + NotebookTopology(; + nodes=all_nodes, + codes=all_codes, + unresolved_cells=new_unresolved_cells, + cell_order=unresolved_topology.cell_order, + disabled_cells=unresolved_topology.disabled_cells, + ) +end + +"""Tries to add information about macro calls without running any code, using knowledge about common macros. +So, the resulting reactive nodes may not be absolutely accurate. If you can run code in a session, use `resolve_topology` instead. +""" +function static_macroexpand(topology::NotebookTopology, cell::Cell) + new_node = ExpressionExplorer.compute_reactive_node( + ExpressionExplorerExtras.pretransform_pluto( + ExpressionExplorerExtras.maybe_macroexpand_pluto( + topology.codes[cell].parsedcode; recursive=true + ) + ) + ) + union!(new_node.macrocalls, topology.nodes[cell].macrocalls) + + new_node +end + +"The same as `resolve_topology` but does not require custom code execution, only works with a few `Base` & `PlutoRunner` macros" +function static_resolve_topology(topology::NotebookTopology) + new_nodes = Dict{Cell,ReactiveNode}(cell => static_macroexpand(topology, cell) for cell in topology.unresolved_cells) + all_nodes = merge(topology.nodes, new_nodes) + + NotebookTopology( + nodes=all_nodes, + codes=topology.codes, + unresolved_cells=topology.unresolved_cells, + cell_order=topology.cell_order, + disabled_cells=topology.disabled_cells, + ) +end diff --git a/src/evaluation/Run.jl b/src/evaluation/Run.jl index 5850a495ce..0ae7570fdc 100644 --- a/src/evaluation/Run.jl +++ b/src/evaluation/Run.jl @@ -1,86 +1,137 @@ -import REPL:ends_with_semicolon +import REPL: ends_with_semicolon import .Configuration -import .ExpressionExplorer: FunctionNameSignaturePair, is_joined_funcname, UsingsImports, external_package_names -import .WorkspaceManager: macroexpand_in_workspace - -Base.push!(x::Set{Cell}) = x - -"Run given cells and all the cells that depend on them, based on the topology information before and after the changes." -function run_reactive!(session::ServerSession, notebook::Notebook, old_topology::NotebookTopology, new_topology::NotebookTopology, roots::Vector{Cell}; deletion_hook::Function = WorkspaceManager.move_vars, user_requested_run::Bool = true, already_in_run::Bool = false, already_run::Vector{Cell} = Cell[])::TopologicalOrder - if !already_in_run - # make sure that we're the only `run_reactive!` being executed - like a semaphor - take!(notebook.executetoken) - else - @assert !isready(notebook.executetoken) "run_reactive!(; already_in_run=true) was called when no reactive run was launched." +import .ExpressionExplorer: is_joined_funcname + +""" +Run given cells and all the cells that depend on them, based on the topology information before and after the changes. +""" +function run_reactive!( + session::ServerSession, + notebook::Notebook, + old_topology::NotebookTopology, + new_topology::NotebookTopology, + roots::Vector{Cell}; + save::Bool=true, + deletion_hook::Function = WorkspaceManager.move_vars, + user_requested_run::Bool = true, + bond_value_pairs=zip(Symbol[],Any[]), +)::TopologicalOrder + topological_order = withtoken(notebook.executetoken) do + run_reactive_core!( + session, + notebook, + old_topology, + new_topology, + roots; + save, + deletion_hook, + user_requested_run, + bond_value_pairs, + ) end + try_event_call(session, NotebookExecutionDoneEvent(notebook, user_requested_run)) + return topological_order +end - old_workspace_name, _ = WorkspaceManager.bump_workspace_module((session, notebook)) +""" +Run given cells and all the cells that depend on them, based on the topology information before and after the changes. +!!! warning + You should probably not call this directly and use `run_reactive!` instead. +""" +function run_reactive_core!( + session::ServerSession, + notebook::Notebook, + old_topology::NotebookTopology, + new_topology::NotebookTopology, + roots::Vector{Cell}; + save::Bool=true, + deletion_hook::Function = WorkspaceManager.move_vars, + user_requested_run::Bool = true, + already_run::Vector{Cell} = Cell[], + bond_value_pairs=zip(Symbol[],Any[]), +)::TopologicalOrder + @assert !isready(notebook.executetoken) "run_reactive_core!() was called with a free notebook.executetoken." + @assert will_run_code(notebook) + + old_workspace_name, _ = WorkspaceManager.bump_workspace_module((session, notebook)) + + run_status = Status.report_business_started!(notebook.status_tree, :run) + Status.report_business_started!(run_status, :resolve_topology) + cell_status = Status.report_business_planned!(run_status, :evaluate) + if !is_resolved(new_topology) unresolved_topology = new_topology new_topology = notebook.topology = resolve_topology(session, notebook, unresolved_topology, old_workspace_name; current_roots = setdiff(roots, already_run)) # update cache and save notebook because the dependencies might have changed after expanding macros update_dependency_cache!(notebook) - save_notebook(session, notebook) end + + # find (indirectly) skipped-as-script cells and update their status + update_skipped_cells_dependency!(notebook, new_topology) - removed_cells = setdiff(keys(old_topology.nodes), keys(new_topology.nodes)) - roots = Cell[roots..., removed_cells...] + removed_cells = setdiff(all_cells(old_topology), all_cells(new_topology)) + roots = vcat(roots, removed_cells) # by setting the reactive node and expression caches of deleted cells to "empty", we are essentially pretending that those cells still exist, but now have empty code. this makes our algorithm simpler. - new_topology = NotebookTopology( - nodes = merge( - new_topology.nodes, - Dict(cell => ReactiveNode() for cell in removed_cells), - ), - codes = merge( - new_topology.codes, - Dict(cell => ExprAnalysisCache() for cell in removed_cells) - ), - unresolved_cells = new_topology.unresolved_cells, - ) - - # save the old topological order - we'll delete variables assigned from it and re-evalutate its cells unless the cells have already run previously in the reactive run - old_order = topological_order(notebook, old_topology, roots) - - old_runnable = setdiff(old_order.runnable, already_run) - to_delete_vars = union!(Set{Symbol}(), defined_variables(old_topology, old_runnable)...) - to_delete_funcs = union!(Set{Tuple{UUID,FunctionName}}(), defined_functions(old_topology, old_runnable)...) - - # get the new topological order - new_order = topological_order(notebook, new_topology, union(roots, keys(old_order.errable))) - new_runnable = setdiff(new_order.runnable, already_run) - to_run_raw = setdiff(union(new_runnable, old_runnable), keys(new_order.errable))::Vector{Cell} # TODO: think if old error cell order matters + new_topology = exclude_roots(new_topology, removed_cells) # find (indirectly) deactivated cells and update their status - deactivated = filter(c -> c.running_disabled, notebook.cells) - indirectly_deactivated = collect(topological_order(notebook, new_topology, deactivated)) + indirectly_deactivated = collect(topological_order(new_topology, collect(new_topology.disabled_cells); allow_multiple_defs=true, skip_at_partial_multiple_defs=true)) + for cell in indirectly_deactivated cell.running = false cell.queued = false cell.depends_on_disabled_cells = true end - to_run = setdiff(to_run_raw, indirectly_deactivated) + new_topology = exclude_roots(new_topology, indirectly_deactivated) + + # save the old topological order - we'll delete variables assigned from its + # and re-evalutate its cells unless the cells have already run previously in the reactive run + old_order = topological_order(old_topology, roots) + + old_runnable = setdiff(old_order.runnable, already_run, indirectly_deactivated) + to_delete_vars = union!(Set{Symbol}(), defined_variables(old_topology, old_runnable)...) + to_delete_funcs = union!(Set{Tuple{UUID,FunctionName}}(), defined_functions(old_topology, old_runnable)...) + + + new_roots = setdiff(union(roots, keys(old_order.errable)), indirectly_deactivated) + # get the new topological order + new_order = topological_order(new_topology, new_roots) + new_runnable = setdiff(new_order.runnable, already_run) + to_run = setdiff!(union(new_runnable, old_runnable), keys(new_order.errable))::Vector{Cell} # TODO: think if old error cell order matters + # change the bar on the sides of cells to "queued" for cell in to_run cell.queued = true cell.depends_on_disabled_cells = false end + for (cell, error) in new_order.errable cell.running = false cell.queued = false + cell.depends_on_disabled_cells = false relay_reactivity_error!(cell, error) end + # Save the notebook. In most cases, this is the only time that we save the notebook, so any state changes that influence the file contents (like `depends_on_disabled_cells`) should be behind this point. (More saves might happen if a macro expansion or package using happens.) + save && save_notebook(session, notebook) + # Send intermediate updates to the clients at most 20 times / second during a reactive run. (The effective speed of a slider is still unbounded, because the last update is not throttled.) # flush_send_notebook_changes_throttled, send_notebook_changes_throttled, flush_notebook_changes = throttled(1.0 / 20) do - send_notebook_changes!(ClientRequest(session = session, notebook = notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) end send_notebook_changes_throttled() + + Status.report_business_finished!(run_status, :resolve_topology) + Status.report_business_started!(cell_status) + for i in eachindex(to_run) + Status.report_business_planned!(cell_status, Symbol(i)) + end # delete new variables that will be defined by a cell unless this cell has already run in the current reactive run to_delete_vars = union!(to_delete_vars, defined_variables(new_topology, new_runnable)...) @@ -91,30 +142,57 @@ function run_reactive!(session::ServerSession, notebook::Notebook, old_topology: to_delete_vars = union!(to_delete_vars, defined_variables(new_topology, new_errable)...) to_delete_funcs = union!(to_delete_funcs, defined_functions(new_topology, new_errable)...) - to_reimport = union!(Set{Expr}(), map(c -> new_topology.codes[c].module_usings_imports.usings, setdiff(notebook.cells, to_run))...) - deletion_hook((session, notebook), old_workspace_name, nothing, to_delete_vars, to_delete_funcs, to_reimport; to_run = to_run) # `deletion_hook` defaults to `WorkspaceManager.move_vars` + cells_to_macro_invalidate = Set{UUID}(c.cell_id for c in cells_with_deleted_macros(old_topology, new_topology)) + + to_reimport = reduce(all_cells(new_topology); init=Set{Expr}()) do to_reimport, c + c ∈ to_run && return to_reimport + usings_imports = new_topology.codes[c].module_usings_imports + for (using_, isglobal) in zip(usings_imports.usings, usings_imports.usings_isglobal) + isglobal || continue + push!(to_reimport, using_) + end + to_reimport + end + + if will_run_code(notebook) + to_delete_funcs_simple = Set{Tuple{UUID,Tuple{Vararg{Symbol}}}}((id, name.parts) for (id,name) in to_delete_funcs) + deletion_hook((session, notebook), old_workspace_name, nothing, to_delete_vars, to_delete_funcs_simple, to_reimport, cells_to_macro_invalidate; to_run) # `deletion_hook` defaults to `WorkspaceManager.move_vars` + end - delete!.([notebook.bonds], to_delete_vars) + foreach(v -> delete!(notebook.bonds, v), to_delete_vars) local any_interrupted = false for (i, cell) in enumerate(to_run) + Status.report_business_started!(cell_status, Symbol(i)) cell.queued = false cell.running = true + # Important to not use empty! here because AppendonlyMarker requires a new array identity. + # Eventually we could even make AppendonlyArray to enforce this but idk if it's worth it. yadiyadi. + cell.logs = Vector{Dict{String,Any}}() send_notebook_changes_throttled() - if any_interrupted || notebook.wants_to_interrupt + if any_interrupted || notebook.wants_to_interrupt || !will_run_code(notebook) relay_reactivity_error!(cell, InterruptException()) else run = run_single!( (session, notebook), cell, new_topology.nodes[cell], new_topology.codes[cell]; - user_requested_run = (user_requested_run && cell ∈ roots) + user_requested_run = (user_requested_run && cell ∈ roots), + capture_stdout = session.options.evaluation.capture_stdout, ) any_interrupted |= run.interrupted + + # Support one bond defining another when setting both simultaneously in PlutoSliderServer + # https://github.com/fonsp/Pluto.jl/issues/1695 + + # set the redefined bound variables to their original value from the request + defs = notebook.topology.nodes[cell].definitions + set_bond_value_pairs!(session, notebook, Iterators.filter(((sym,val),) -> sym ∈ defs, bond_value_pairs)) end cell.running = false + Status.report_business_finished!(cell_status, Symbol(i)) defined_macros_in_cell = defined_macros(new_topology, cell) |> Set{Symbol} @@ -134,28 +212,40 @@ function run_reactive!(session::ServerSession, notebook::Notebook, old_topology: # update cache and save notebook because the dependencies might have changed after expanding macros update_dependency_cache!(notebook) - save_notebook(session, notebook) + save && save_notebook(session, notebook) - return run_reactive!(session, notebook, new_topology, new_new_topology, to_run; deletion_hook = deletion_hook, user_requested_run = user_requested_run, already_in_run = true, already_run = to_run[1:i]) + return run_reactive_core!(session, notebook, new_topology, new_new_topology, to_run; save, deletion_hook, user_requested_run, already_run = to_run[1:i]) elseif !isempty(implicit_usings) new_soft_definitions = WorkspaceManager.collect_soft_definitions((session, notebook), implicit_usings) notebook.topology = new_new_topology = with_new_soft_definitions(new_topology, cell, new_soft_definitions) # update cache and save notebook because the dependencies might have changed after expanding macros update_dependency_cache!(notebook) - save_notebook(session, notebook) + save && save_notebook(session, notebook) - return run_reactive!(session, notebook, new_topology, new_new_topology, to_run; deletion_hook = deletion_hook, user_requested_run = user_requested_run, already_in_run = true, already_run = to_run[1:i]) + return run_reactive_core!(session, notebook, new_topology, new_new_topology, to_run; save, deletion_hook, user_requested_run, already_run = to_run[1:i]) end end notebook.wants_to_interrupt = false flush_notebook_changes() - # allow other `run_reactive!` calls to be executed - put!(notebook.executetoken) + Status.report_business_finished!(run_status) return new_order end +""" +```julia +set_bond_value_pairs!(session::ServerSession, notebook::Notebook, bond_value_pairs::Vector{Tuple{Symbol, Any}}) +``` +Given a list of tuples of the form `(bound variable name, (untransformed) value)`, assign each (transformed) value to the corresponding global bound variable in the notebook workspace. +`bond_value_pairs` can also be an iterator. +""" +function set_bond_value_pairs!(session::ServerSession, notebook::Notebook, bond_value_pairs) + for (bound_sym, new_value) in bond_value_pairs + WorkspaceManager.eval_in_workspace((session, notebook), :($(bound_sym) = Main.PlutoRunner.transform_bond_value($(QuoteNode(bound_sym)), $(new_value)))) + end +end + run_reactive_async!(session::ServerSession, notebook::Notebook, to_run::Vector{Cell}; kwargs...) = run_reactive_async!(session, notebook, notebook.topology, notebook.topology, to_run; kwargs...) function run_reactive_async!(session::ServerSession, notebook::Notebook, old::NotebookTopology, new::NotebookTopology, to_run::Vector{Cell}; run_async::Bool=true, kwargs...)::Union{Task,TopologicalOrder} @@ -173,31 +263,30 @@ function maybe_async(f::Function, async::Bool) end end -const lazymap = Base.Generator - -function defined_variables(topology::NotebookTopology, cells) - lazymap(cells) do cell - topology.nodes[cell].definitions - end -end - -function defined_functions(topology::NotebookTopology, cells) - lazymap(cells) do cell - ((cell.cell_id, namesig.name) for namesig in topology.nodes[cell].funcdefs_with_signatures) - end -end - "Run a single cell non-reactively, set its output, return run information." -function run_single!(session_notebook::Union{Tuple{ServerSession,Notebook},WorkspaceManager.Workspace}, cell::Cell, reactive_node::ReactiveNode, expr_cache::ExprAnalysisCache; user_requested_run::Bool=true) +function run_single!( + session_notebook::Union{Tuple{ServerSession,Notebook},WorkspaceManager.Workspace}, + cell::Cell, + reactive_node::ReactiveNode, + expr_cache::ExprAnalysisCache; + user_requested_run::Bool=true, + capture_stdout::Bool=true, +) run = WorkspaceManager.eval_format_fetch_in_workspace( - session_notebook, - expr_cache.parsedcode, - cell.cell_id, - ends_with_semicolon(cell.code), - expr_cache.function_wrapped ? (filter(!is_joined_funcname, reactive_node.references), reactive_node.definitions) : nothing, - expr_cache.forced_expr_id, + session_notebook, + expr_cache.parsedcode, + cell.cell_id; + + ends_with_semicolon = + ends_with_semicolon(cell.code), + function_wrapped_info = + expr_cache.function_wrapped ? (filter(!is_joined_funcname, reactive_node.references), reactive_node.definitions) : nothing, + forced_expr_id = + expr_cache.forced_expr_id, + known_published_objects = + collect(keys(cell.published_objects)), user_requested_run, - collect(keys(cell.published_objects)), + capture_stdout, ) set_output!(cell, run, expr_cache; persist_js_state=!user_requested_run) if session_notebook isa Tuple && run.process_exited @@ -240,176 +329,59 @@ function set_output!(cell::Cell, run, expr_cache::ExprAnalysisCache; persist_js_ cell.running = cell.queued = false end -will_run_code(notebook::Notebook) = notebook.process_status != ProcessStatus.no_process && notebook.process_status != ProcessStatus.waiting_to_restart - -is_macro_identifier(symbol::Symbol) = startswith(string(symbol), "@") - -function with_new_soft_definitions(topology::NotebookTopology, cell::Cell, soft_definitions) - old_node = topology.nodes[cell] - new_node = union!(ReactiveNode(), old_node, ReactiveNode(soft_definitions=soft_definitions)) - NotebookTopology(codes=topology.codes, nodes=merge(topology.nodes, Dict(cell => new_node)), unresolved_cells=topology.unresolved_cells) -end - -collect_implicit_usings(topology::NotebookTopology, cell::Cell) = ExpressionExplorer.collect_implicit_usings(topology.codes[cell].module_usings_imports) - -"Returns the set of macros names defined by this cell" -defined_macros(topology::NotebookTopology, cell::Cell) = defined_macros(topology.nodes[cell]) -defined_macros(node::ReactiveNode) = filter(is_macro_identifier, node.funcdefs_without_signatures) ∪ filter(is_macro_identifier, node.definitions) # macro definitions can come from imports - -"Tells whether or not a cell can 'unlock' the resolution of other cells" -function can_help_resolve_cells(topology::NotebookTopology, cell::Cell) - cell_code = topology.codes[cell] - cell_node = topology.nodes[cell] - macros = defined_macros(cell_node) - - !isempty(cell_code.module_usings_imports.usings) || - (!isempty(macros) && any(calls -> !disjoint(calls, macros), topology.nodes[c].macrocalls for c in topology.unresolved_cells)) -end - -# Sorry couldn't help myself - DRAL -abstract type Result end -struct Success <: Result - result -end -struct Failure <: Result - error -end -struct Skipped <: Result end - -"""We still have 'unresolved' macrocalls, use the current and maybe previous workspace to do macro-expansions. - -You can optionally specify the roots for the current reactive run. If a cell macro contains only macros that will -be re-defined during this reactive run, we don't expand yet and expect the `can_help_resolve_cells` function above -to be true for the cell defining the macro, triggering a new topology resolution without needing to fallback to the -previous workspace. -""" -function resolve_topology( - session::ServerSession, - notebook::Notebook, - unresolved_topology::NotebookTopology, - old_workspace_name::Symbol; - current_roots::Vector{Cell}=Cell[], -)::NotebookTopology - - - sn = (session, notebook) - - function macroexpand_cell(cell) - try_macroexpand(module_name::Union{Nothing,Symbol}=nothing) = begin - success, result = macroexpand_in_workspace(sn, unresolved_topology.codes[cell].parsedcode, cell.cell_id, module_name) - if success - Success(result) - else - Failure(result) - end - end - - result = try_macroexpand() - if result isa Success - result - else - if (result.error isa LoadError && result.error.error isa UndefVarError) || result.error isa UndefVarError - try_macroexpand(old_workspace_name) - else - result - end - end - end - - function analyze_macrocell(cell::Cell) - if unresolved_topology.nodes[cell].macrocalls ⊆ ExpressionExplorer.can_macroexpand - return Skipped() - end - - result = macroexpand_cell(cell) - if result isa Success - (expr, computer_id) = result.result - expanded_node = ExpressionExplorer.try_compute_symbolreferences(expr) |> ReactiveNode - function_wrapped = ExpressionExplorer.can_be_function_wrapped(expr) - Success((expanded_node, function_wrapped, computer_id)) - else - result - end - end - - run_defined_macros = mapreduce(c -> defined_macros(unresolved_topology, c), union!, current_roots; init=Set{Symbol}()) - - # create new node & new codes for macrocalled cells - new_nodes = Dict{Cell,ReactiveNode}() - new_codes = Dict{Cell,ExprAnalysisCache}() - still_unresolved_nodes = Set{Cell}() - - for cell in unresolved_topology.unresolved_cells - if unresolved_topology.nodes[cell].macrocalls ⊆ run_defined_macros - # Do not try to expand if a newer version of the macro is also scheduled to run in the - # current run. The recursive reactive runs will take care of it. - push!(still_unresolved_nodes, cell) - end - - result = try - analyze_macrocell(cell) - catch error - @error "Macro call expansion failed with a non-macroexpand error" error - Failure(error) - end - if result isa Success - (new_node, function_wrapped, forced_expr_id) = result.result - union!(new_node.macrocalls, unresolved_topology.nodes[cell].macrocalls) - union!(new_node.references, new_node.macrocalls) - new_nodes[cell] = new_node - - # set function_wrapped to the function wrapped analysis of the expanded expression. - new_codes[cell] = ExprAnalysisCache(unresolved_topology.codes[cell]; forced_expr_id, function_wrapped) - else - if result isa Failure - @debug "Expansion failed" err=result.error - end - push!(still_unresolved_nodes, cell) - end - end - - all_nodes = merge(unresolved_topology.nodes, new_nodes) - all_codes = merge(unresolved_topology.codes, new_codes) - - NotebookTopology(nodes=all_nodes, codes=all_codes, unresolved_cells=still_unresolved_nodes) -end - -"""Tries to add information about macro calls without running any code, using knowledge about common macros. -So, the resulting reactive nodes may not be absolutely accurate. If you can run code in a session, use `resolve_topology` instead. -""" -function static_macroexpand(topology::NotebookTopology, cell::Cell) - new_node = ExpressionExplorer.maybe_macroexpand(topology.codes[cell].parsedcode; recursive=true) |> - ExpressionExplorer.try_compute_symbolreferences |> ReactiveNode - union!(new_node.macrocalls, topology.nodes[cell].macrocalls) - - new_node -end - -"The same as `resolve_topology` but does not require custom code execution, only works with a few `Base` & `PlutoRunner` macros" -function static_resolve_topology(topology::NotebookTopology) - new_nodes = Dict{Cell,ReactiveNode}(cell => static_macroexpand(topology, cell) for cell in topology.unresolved_cells) - all_nodes = merge(topology.nodes, new_nodes) - - NotebookTopology(nodes=all_nodes, codes=topology.codes, unresolved_cells=topology.unresolved_cells) +function clear_output!(cell::Cell) + cell.output = CellOutput() + cell.published_objects = Dict{String,Any}() + + cell.runtime = nothing + cell.errored = false + cell.running = cell.queued = false end -### -# CONVENIENCE FUNCTIONS -### +will_run_code(notebook::Notebook) = notebook.process_status ∈ (ProcessStatus.ready, ProcessStatus.starting) +will_run_pkg(notebook::Notebook) = notebook.process_status !== ProcessStatus.waiting_for_permission "Do all the things!" -function update_save_run!(session::ServerSession, notebook::Notebook, cells::Array{Cell,1}; save::Bool=true, run_async::Bool=false, prerender_text::Bool=false, kwargs...) +function update_save_run!( + session::ServerSession, + notebook::Notebook, + cells::Vector{Cell}; + save::Bool=true, + run_async::Bool=false, + prerender_text::Bool=false, + clear_not_prerenderable_cells::Bool=false, + auto_solve_multiple_defs::Bool=false, + on_auto_solve_multiple_defs::Function=identity, + kwargs... +) old = notebook.topology new = notebook.topology = updated_topology(old, notebook, cells) # macros are not yet resolved + + # _assume `auto_solve_multiple_defs == false` if you want to skip some details_ + if auto_solve_multiple_defs + to_disable_dict = cells_to_disable_to_resolve_multiple_defs(old, new, cells) + + if !isempty(to_disable_dict) + to_disable = keys(to_disable_dict) + @debug "Using augmented topology" cell_id.(to_disable) + + foreach(c -> set_disabled(c, true), to_disable) + + cells = union(cells, to_disable) + # need to update the topology because the topology also keeps track of disabled cells + new = notebook.topology = updated_topology(new, notebook, to_disable) + end + + on_auto_solve_multiple_defs(to_disable_dict) + end update_dependency_cache!(notebook) save && save_notebook(session, notebook) # _assume `prerender_text == false` if you want to skip some details_ - to_run_online = if !prerender_text - cells - else + to_run_online = cells + if prerender_text # this code block will run cells that only contain text offline, i.e. on the server process, before doing anything else # this makes the notebook load a lot faster - the front-end does not have to wait for each output, and perform costly reflows whenever one updates # "A Workspace on the main process, used to prerender markdown before starting a notebook process for speedy UI." @@ -422,18 +394,20 @@ function update_save_run!(session::ServerSession, notebook::Notebook, cells::Arr is_offline_renderer=true, ) - new = notebook.topology = static_resolve_topology(new) - - to_run_offline = filter(c -> !c.running && is_just_text(new, c) && is_just_text(old, c), cells) + to_run_offline = filter(c -> !c.running && is_just_text(new, c), cells) for cell in to_run_offline run_single!(offline_workspace, cell, new.nodes[cell], new.codes[cell]) end - + cd(original_pwd) - setdiff(cells, to_run_offline) + to_run_online = setdiff(cells, to_run_offline) + + clear_not_prerenderable_cells && foreach(clear_output!, to_run_online) + + send_notebook_changes!(ClientRequest(; session, notebook)) end - - # this setting is not officially supported (default is `false`), so you can skip this block when reading the code + + # this setting is not officially supported (default is `true`), so you can skip this block when reading the code if !session.options.evaluation.run_notebook_on_load && prerender_text # these cells do something like settings up an environment, we should always run them setup_cells = filter(notebook.cells) do c @@ -441,48 +415,125 @@ function update_save_run!(session::ServerSession, notebook::Notebook, cells::Arr end # for the remaining cells, clear their topology info so that they won't run as dependencies - for cell in setdiff(to_run_online, setup_cells) - delete!(notebook.topology.nodes, cell) - delete!(notebook.topology.codes, cell) - delete!(notebook.topology.unresolved_cells, cell) - end + old = notebook.topology + to_remove = setdiff(to_run_online, setup_cells) + notebook.topology = NotebookTopology( + nodes=setdiffkeys(old.nodes, to_remove), + codes=setdiffkeys(old.codes, to_remove), + unresolved_cells=setdiff(old.unresolved_cells, to_remove), + cell_order=old.cell_order, + disabled_cells=setdiff(old.disabled_cells, to_remove), + ) # and don't run them to_run_online = to_run_online ∩ setup_cells end maybe_async(run_async) do - sync_nbpkg(session, notebook; save=(save && !session.options.server.disable_writing_notebook_files)) - if !(isempty(to_run_online) && session.options.evaluation.lazy_workspace_creation) && will_run_code(notebook) - # not async because that would be double async - run_reactive_async!(session, notebook, old, new, to_run_online; run_async=false, kwargs...) - # run_reactive_async!(session, notebook, old, new, to_run_online; deletion_hook=deletion_hook, run_async=false, kwargs...) + topological_order = withtoken(notebook.executetoken) do + run_code = !( + isempty(to_run_online) && + session.options.evaluation.lazy_workspace_creation + ) && will_run_code(notebook) + + if run_code + # this will trigger the notebook process to start. @async makes it run in the background, so that sync_nbpkg (below) can start running in parallel. + # Some notes: + # - @async is enough, we don't need multithreading because the notebook runs in a separate process. + # - sync_nbpkg manages the notebook package environment using Pkg on this server process. This means that sync_nbpkg does not need the notebook process at all, and it can run in parallel, before it has even started. + @async WorkspaceManager.get_workspace((session, notebook)) + end + + if will_run_pkg(notebook) + # downloading and precompiling packages from the General registry is also arbitrary code execution + sync_nbpkg(session, notebook, old, new; + save=(save && !session.options.server.disable_writing_notebook_files), + take_token=false + ) + end + + if run_code + # not async because that would be double async + run_reactive_core!(session, notebook, old, new, to_run_online; save, kwargs...) + # run_reactive_async!(session, notebook, old, new, to_run_online; deletion_hook=deletion_hook, run_async=false, kwargs...) + end + end + try_event_call( + session, + NotebookExecutionDoneEvent(notebook, get(kwargs, :user_requested_run, true)) + ) + topological_order + end +end + +update_save_run!(session::ServerSession, notebook::Notebook, cell::Cell; kwargs...) = update_save_run!(session, notebook, [cell]; kwargs...) +update_run!(args...; kwargs...) = update_save_run!(args...; save=false, kwargs...) + + +function cells_to_disable_to_resolve_multiple_defs(old::NotebookTopology, new::NotebookTopology, cells::Vector{Cell})::Dict{Cell,Any} + # keys are cells to disable + # values are the reason why + to_disable_and_why = Dict{Cell,Any}() + + for cell in cells + new_node = new.nodes[cell] + + fellow_assigners_old = filter!(c -> !is_disabled(old, c), where_assigned(old, new_node)) + fellow_assigners_new = filter!(c -> !is_disabled(new, c), where_assigned(new, new_node)) + + if length(fellow_assigners_new) > length(fellow_assigners_old) + other_definers = setdiff(fellow_assigners_new, (cell,)) + + @debug "Solving multiple defs" cell.cell_id cell_id.(other_definers) disjoint(cells, other_definers) + + # we want cell to be the only element of cells that defines this varialbe, i.e. all other definers must have been created previously + if disjoint(cells, other_definers) + # all fellow cells (including the current cell) should meet some criteria: + all_fellows_are_simple_enough = all(fellow_assigners_new) do c + node = new.nodes[c] + + # all must be true: + return ( + length(node.definitions) == 1 && # for more than one defined variable, we might confuse the user, or disable more things than we want to. + disjoint(node.references, node.definitions) && # avoid self-reference like `x = x + 1` + isempty(node.funcdefs_without_signatures) && + node.macrocalls ⊆ (Symbol("@bind"),) # allow no macros (except for `@bind`) + ) + end + + if all_fellows_are_simple_enough + for c in other_definers + # if the cell is already disabled (indirectly), then we don't need to disable it. probably. + if !c.depends_on_disabled_cells + to_disable_and_why[c] = (cell_id(cell), only(new.nodes[c].definitions)) + end + end + end + end end end + + to_disable_and_why end -update_save_run!(session::ServerSession, notebook::Notebook, cell::Cell; kwargs...) = update_save_run!(session, notebook, [cell]; kwargs...) -update_run!(args...) = update_save_run!(args...; save=false) + function notebook_differences(from::Notebook, to::Notebook) - old_codes = Dict( - id => c.code - for (id,c) in from.cells_dict - ) - new_codes = Dict( - id => c.code - for (id,c) in to.cells_dict - ) + from_cells = from.cells_dict + to_cells = to.cells_dict ( # it's like D3 joins: https://observablehq.com/@d3/learn-d3-joins#cell-528 - added = setdiff(keys(new_codes), keys(old_codes)), - removed = setdiff(keys(old_codes), keys(new_codes)), + added = setdiff(keys(to_cells), keys(from_cells)), + removed = setdiff(keys(from_cells), keys(to_cells)), changed = let - remained = keys(old_codes) ∩ keys(new_codes) - filter(id -> old_codes[id] != new_codes[id], remained) + remained = keys(from_cells) ∩ keys(to_cells) + filter(remained) do id + from_cells[id].code != to_cells[id].code || from_cells[id].metadata != to_cells[id].metadata + end end, + folded_changed = any(from_cells[id].code_folded != to_cells[id].code_folded for id in keys(from_cells) if haskey(to_cells, id)), order_changed = from.cell_order != to.cell_order, nbpkg_changed = !is_nbpkg_equal(from.nbpkg_ctx, to.nbpkg_ctx), ) @@ -505,11 +556,6 @@ function update_from_file(session::ServerSession, notebook::Notebook; kwargs...) return false end::Notebook - new_codes = Dict( - id => c.code - for (id,c) in just_loaded.cells_dict - ) - d = notebook_differences(notebook, just_loaded) added = d.added @@ -519,16 +565,17 @@ function update_from_file(session::ServerSession, notebook::Notebook; kwargs...) # @show added removed changed cells_changed = !(isempty(added) && isempty(removed) && isempty(changed)) + folded_changed = d.folded_changed order_changed = d.order_changed nbpkg_changed = d.nbpkg_changed - something_changed = cells_changed || order_changed || (include_nbpg && nbpkg_changed) - + something_changed = cells_changed || folded_changed || order_changed || (include_nbpg && nbpkg_changed) + if something_changed @info "Reloading notebook from file and applying changes!" notebook.last_hot_reload_time = time() end - + for c in added notebook.cells_dict[c] = just_loaded.cells_dict[c] end @@ -536,17 +583,24 @@ function update_from_file(session::ServerSession, notebook::Notebook; kwargs...) delete!(notebook.cells_dict, c) end for c in changed - notebook.cells_dict[c].code = new_codes[c] + notebook.cells_dict[c].code = just_loaded.cells_dict[c].code + notebook.cells_dict[c].metadata = just_loaded.cells_dict[c].metadata + end + + for c in keys(notebook.cells_dict) ∩ keys(just_loaded.cells_dict) + notebook.cells_dict[c].code_folded = just_loaded.cells_dict[c].code_folded end notebook.cell_order = just_loaded.cell_order - + notebook.metadata = just_loaded.metadata + if include_nbpg && nbpkg_changed @info "nbpkgs not equal" (notebook.nbpkg_ctx isa Nothing) (just_loaded.nbpkg_ctx isa Nothing) if (notebook.nbpkg_ctx isa Nothing) != (just_loaded.nbpkg_ctx isa Nothing) @info "nbpkg status changed, overriding..." notebook.nbpkg_ctx = just_loaded.nbpkg_ctx + notebook.nbpkg_install_time_ns = just_loaded.nbpkg_install_time_ns else @info "Old new project" PkgCompat.read_project_file(notebook) PkgCompat.read_project_file(just_loaded) @info "Old new manifest" PkgCompat.read_manifest_file(notebook) PkgCompat.read_manifest_file(just_loaded) @@ -556,61 +610,32 @@ function update_from_file(session::ServerSession, notebook::Notebook; kwargs...) end notebook.nbpkg_restart_required_msg = "Yes, because the file was changed externally and the embedded Pkg changed." end - + if something_changed - update_save_run!(session, notebook, Cell[notebook.cells_dict[c] for c in union(added, changed)]; kwargs...) # this will also update nbpkg + update_save_run!(session, notebook, Cell[notebook.cells_dict[c] for c in union(added, changed)]; kwargs...) # this will also update nbpkg if needed end - + return true end - - -""" -throttled(f::Function, timeout::Real) - -Return a function that when invoked, will only be triggered at most once -during `timeout` seconds. -The throttled function will run as much as it can, without ever -going more than once per `wait` duration. - -This throttle is 'leading' and has some other properties that are specifically designed for our use in Pluto, see the tests. - -Inspired by FluxML -See: https://github.com/FluxML/Flux.jl/blob/8afedcd6723112ff611555e350a8c84f4e1ad686/src/utils.jl#L662 -""" -function throttled(f::Function, timeout::Real) - tlock = ReentrantLock() - iscoolnow = Ref(false) - run_later = Ref(false) - - function flush() - lock(tlock) do - run_later[] = false - f() - end +function update_skipped_cells_dependency!(notebook::Notebook, topology::NotebookTopology=notebook.topology) + skipped_cells = filter(is_skipped_as_script, notebook.cells) + indirectly_skipped = collect(topological_order(topology, skipped_cells)) + for cell in notebook.cells + cell.depends_on_skipped_cells = false end - - function schedule() - @async begin - sleep(timeout) - if run_later[] - flush() - end - iscoolnow[] = true - end + for cell in indirectly_skipped + cell.depends_on_skipped_cells = true end - schedule() +end - function throttled_f() - if iscoolnow[] - iscoolnow[] = false - flush() - schedule() - else - run_later[] = true - end +function update_disabled_cells_dependency!(notebook::Notebook, topology::NotebookTopology=notebook.topology) + disabled_cells = filter(is_disabled, notebook.cells) + indirectly_disabled = collect(topological_order(topology, disabled_cells)) + for cell in notebook.cells + cell.depends_on_disabled_cells = false + end + for cell in indirectly_disabled + cell.depends_on_disabled_cells = true end - - return throttled_f, flush end diff --git a/src/evaluation/RunBonds.jl b/src/evaluation/RunBonds.jl index 30647b516d..3371f938ee 100644 --- a/src/evaluation/RunBonds.jl +++ b/src/evaluation/RunBonds.jl @@ -1,45 +1,73 @@ -function set_bond_values_reactive(; session::ServerSession, notebook::Notebook, bound_sym_names::AbstractVector{Symbol}, is_first_values::AbstractVector{Bool}=[true for x in bound_sym_names], kwargs...)::Union{Task,TopologicalOrder} +function set_bond_values_reactive(; + session::ServerSession, notebook::Notebook, + bound_sym_names::AbstractVector{Symbol}, + is_first_values::AbstractVector{Bool}=[false for x in bound_sym_names], + initiator=nothing, + kwargs... +)::Union{Task,TopologicalOrder} # filter out the bonds that don't need to be set - to_set = filter(zip(bound_sym_names, is_first_values) |> collect) do (bound_sym, is_first_value) - new_value = notebook.bonds[bound_sym].value - - variable_exists = is_assigned_anywhere(notebook, notebook.topology, bound_sym) - if !variable_exists - # a bond was set while the cell is in limbo state - # we don't need to do anything - return false - end + syms_to_set = first.( + Iterators.filter(zip(bound_sym_names, is_first_values) |> collect) do (bound_sym, is_first_value) + new_value = notebook.bonds[bound_sym].value + + variable_exists = is_assigned_anywhere(notebook, notebook.topology, bound_sym) + if !variable_exists + # a bond was set while the cell is in limbo state + # we don't need to do anything + return false + end - # TODO: Not checking for any dependents now - # any_dependents = is_referenced_anywhere(notebook, notebook.topology, bound_sym) + # TODO: Not checking for any dependents now + # any_dependents = is_referenced_anywhere(notebook, notebook.topology, bound_sym) - # fix for https://github.com/fonsp/Pluto.jl/issues/275 - # if `Base.get` was defined to give an initial value (read more about this in the Interactivity sample notebook), then we want to skip the first value sent back from the bond. (if `Base.get` was not defined, then the variable has value `missing`) - # Check if the variable does not already have that value. - # because if the initial value is already set, then we don't want to run dependent cells again. - eq_tester = :(try !ismissing($bound_sym) && ($bound_sym == Main.PlutoRunner.transform_bond_value($(QuoteNode(bound_sym)), $(new_value))) === true catch; false end) # not just a === comparison because JS might send back the same value but with a different type (Float64 becomes Int64 in JS when it's an integer. The `=== true` check handles cases like `[missing] == [123]`, which returns `missing`, not `true` or `false`.) - if is_first_value && WorkspaceManager.eval_fetch_in_workspace((session, notebook), eq_tester) - return false + # fix for https://github.com/fonsp/Pluto.jl/issues/275 + # if `Base.get` was defined to give an initial value (read more about this in the Interactivity sample notebook), then we want to skip the first value sent back from the bond. (if `Base.get` was not defined, then the variable has value `missing`) + # Check if the variable does not already have that value. + # because if the initial value is already set, then we don't want to run dependent cells again. + eq_tester = :(try !ismissing($bound_sym) && ($bound_sym == Main.PlutoRunner.transform_bond_value($(QuoteNode(bound_sym)), $(new_value))) === true catch; false end) # not just a === comparison because JS might send back the same value but with a different type (Float64 becomes Int64 in JS when it's an integer. The `=== true` check handles cases like `[missing] == [123]`, which returns `missing`, not `true` or `false`.) + if is_first_value && will_run_code(notebook) && WorkspaceManager.eval_fetch_in_workspace((session, notebook), eq_tester) + return false + end + return true end - return true - end .|> first + )::Vector{Symbol} - if isempty(to_set) + if isempty(syms_to_set) || !will_run_code(notebook) + send_notebook_changes!(ClientRequest(; session, notebook, initiator)) return TopologicalOrder(notebook.topology, Cell[], Dict{Cell, ReactivityError}()) end - new_values = [notebook.bonds[bound_sym].value for bound_sym in to_set] - - function custom_deletion_hook((session, notebook)::Tuple{ServerSession,Notebook}, old_workspace_name, new_workspace_name, to_delete_vars::Set{Symbol}, methods_to_delete::Set{Tuple{UUID,FunctionName}}, to_reimport::Set{Expr}; to_run::AbstractVector{Cell}) - to_delete_vars = Set([to_delete_vars..., to_set...]) # also delete the bound symbols - WorkspaceManager.move_vars((session, notebook), old_workspace_name, new_workspace_name, to_delete_vars, methods_to_delete, to_reimport) - for (bound_sym, new_value) in zip(to_set, new_values) - WorkspaceManager.eval_in_workspace((session, notebook), :($(bound_sym) = Main.PlutoRunner.transform_bond_value($(QuoteNode(bound_sym)), $(new_value)))) - end + new_values = Any[notebook.bonds[bound_sym].value for bound_sym in syms_to_set] + bond_value_pairs = zip(syms_to_set, new_values) + + syms_to_set_set = Set{Symbol}(syms_to_set) + function custom_deletion_hook((session, notebook)::Tuple{ServerSession,Notebook}, old_workspace_name, new_workspace_name, to_delete_vars::Set{Symbol}, methods_to_delete, to_reimport, invalidated_cell_uuids; to_run) + to_delete_vars = union(to_delete_vars, syms_to_set_set) # also delete the bound symbols + WorkspaceManager.move_vars( + (session, notebook), + old_workspace_name, + new_workspace_name, + to_delete_vars, + methods_to_delete, + to_reimport, + invalidated_cell_uuids, + syms_to_set_set, + ) + set_bond_value_pairs!(session, notebook, zip(syms_to_set, new_values)) end - to_reeval = where_referenced(notebook, notebook.topology, Set{Symbol}(to_set)) + to_reeval = where_referenced(notebook, notebook.topology, syms_to_set_set) - run_reactive_async!(session, notebook, to_reeval; deletion_hook=custom_deletion_hook, user_requested_run=false, run_async=false, kwargs...) + run_reactive_async!(session, notebook, to_reeval; deletion_hook=custom_deletion_hook, save=false, user_requested_run=false, run_async=false, bond_value_pairs, kwargs...) +end + +""" +Returns the names of all defined bonds +""" +function get_bond_names(session::ServerSession, notebook::Notebook) + cells_bond_names = map(notebook.cell_order) do cell_id + WorkspaceManager.get_bond_names((session,notebook), cell_id) + end + union!(Set{Symbol}(), cells_bond_names...) end """ diff --git a/src/evaluation/Throttled.jl b/src/evaluation/Throttled.jl new file mode 100644 index 0000000000..f0fa10352d --- /dev/null +++ b/src/evaluation/Throttled.jl @@ -0,0 +1,71 @@ + +""" +throttled(f::Function, timeout::Real) + +Return a function that when invoked, will only be triggered at most once +during `timeout` seconds. +The throttled function will run as much as it can, without ever +going more than once per `wait` duration. + +This throttle is 'leading' and has some other properties that are specifically designed for our use in Pluto, see the tests. + +Inspired by FluxML +See: https://github.com/FluxML/Flux.jl/blob/8afedcd6723112ff611555e350a8c84f4e1ad686/src/utils.jl#L662 +""" +function throttled(f::Function, timeout::Real) + tlock = ReentrantLock() + iscoolnow = Ref(false) + run_later = Ref(false) + + function flush() + lock(tlock) do + run_later[] = false + f() + end + end + + function schedule() + @async begin + sleep(timeout) + if run_later[] + flush() + end + iscoolnow[] = true + end + end + schedule() + + function throttled_f() + if iscoolnow[] + iscoolnow[] = false + flush() + schedule() + else + run_later[] = true + end + end + + return throttled_f, flush +end + + +""" + simple_leading_throttle(f, delay::Real) + +Return a function that when invoked, will only be triggered at most once +during `timeout` seconds. +The throttled function will run as much as it can, without ever +going more than once per `wait` duration. + +Compared to [`throttled`](@ref), this simple function only implements [leading](https://css-tricks.com/debouncing-throttling-explained-examples/) throttling and accepts function with arbitrary number of positional and keyword arguments. +""" +function simple_leading_throttle(f, delay::Real) + last_time = 0.0 + return function(args...;kwargs...) + now = time() + if now - last_time > delay + last_time = now + f(args...;kwargs...) + end + end +end \ No newline at end of file diff --git a/src/evaluation/Tokens.jl b/src/evaluation/Tokens.jl index 1dca8452b9..21b0ce14e2 100644 --- a/src/evaluation/Tokens.jl +++ b/src/evaluation/Tokens.jl @@ -48,49 +48,6 @@ function request!(queue::RequestQueue) end end -### - -mutable struct Promise{T} - value::Union{Nothing,Some{T}} - task::Union{Nothing,Task} -end - -" - Promise{T}(f::Function) - -Run `f` asynchronously, and return a `Promise` to its result of type `T`. Call `fetch` on the returned `Promise` to await the result. - -It's just like a `Task`, except the result is a type parameter. - -# Example - -``` -julia> p = Promise() do - sleep(5) - 1 + 2 -end; - -julia> fetch(p) -3 -``` - -" -function Promise{T}(f::Function) where T - p = Promise{T}(nothing, nothing) - p.task = @async begin - p.value = Some(f()) - end - return p -end -Promise(f::Function) = Promise{Any}(f) - -function Base.fetch(p::Promise{T})::T where T - wait(p.task) - something(p.value) -end - - - "Like @async except it prints errors to the terminal. 👶" macro asynclog(expr) diff --git a/src/evaluation/WorkspaceManager.jl b/src/evaluation/WorkspaceManager.jl index 9489c33534..f94e96d00a 100644 --- a/src/evaluation/WorkspaceManager.jl +++ b/src/evaluation/WorkspaceManager.jl @@ -1,116 +1,164 @@ module WorkspaceManager -import UUIDs: UUID +import UUIDs: UUID, uuid1 import ..Pluto -import ..Pluto: Configuration, Notebook, Cell, ProcessStatus, ServerSession, ExpressionExplorer, pluto_filename, Token, withtoken, Promise, tamepath, project_relative_path, putnotebookupdates!, UpdateMessage +import ..Pluto: Configuration, Notebook, Cell, ProcessStatus, ServerSession, ExpressionExplorer, pluto_filename, Token, withtoken, tamepath, project_relative_path, putnotebookupdates!, UpdateMessage +import ..Pluto.Status import ..Pluto.PkgCompat import ..Configuration: CompilerOptions, _merge_notebook_compiler_options, _convert_to_flags import ..Pluto.ExpressionExplorer: FunctionName import ..PlutoRunner -import Distributed - -"Contains the Julia process (in the sense of `Distributed.addprocs`) to evaluate code in. Each notebook gets at most one `Workspace` at any time, but it can also have no `Workspace` (it cannot `eval` code in this case)." +import Malt +import Malt.Distributed + +""" +Contains the Julia process to evaluate code in. +Each notebook gets at most one `Workspace` at any time, but it can also have no `Workspace` +(it cannot `eval` code in this case). +""" Base.@kwdef mutable struct Workspace - pid::Integer + worker::Malt.AbstractWorker + notebook_id::UUID discarded::Bool=false - log_channel::Distributed.RemoteChannel + remote_log_channel::Union{Distributed.RemoteChannel,AbstractChannel} module_name::Symbol dowork_token::Token=Token() nbpkg_was_active::Bool=false + has_executed_effectful_code::Bool=false is_offline_renderer::Bool=false original_LOAD_PATH::Vector{String}=String[] original_ACTIVE_PROJECT::Union{Nothing,String}=nothing end +const SN = Tuple{ServerSession, Notebook} + "These expressions get evaluated whenever a new `Workspace` process is created." -const process_preamble = [ - :(ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0)), - :(include($(project_relative_path("src", "runner", "Loader.jl")))), - :(ENV["GKSwstype"] = "nul"), - :(ENV["JULIA_REVISE_WORKER_ONLY"] = "1"), -] +process_preamble() = quote + Base.exit_on_sigint(false) + const pluto_boot_environment_path = $(Pluto.pluto_boot_environment_path[]) + include($(project_relative_path(joinpath("src", "runner"), "Loader.jl"))) + ENV["GKSwstype"] = "nul" + ENV["JULIA_REVISE_WORKER_ONLY"] = "1" +end -const workspaces = Dict{UUID,Promise{Workspace}}() +const active_workspaces = Dict{UUID,Task}() -const SN = Tuple{ServerSession,Notebook} +"Set of notebook IDs that we will never make a process for again." +const discarded_workspaces = Set{UUID}() -"""Create a workspace for the notebook, optionally in the main process.""" +"Create a workspace for the notebook, optionally in the main process." function make_workspace((session, notebook)::SN; is_offline_renderer::Bool=false)::Workspace + workspace_business = is_offline_renderer ? Status.Business(name=:gobble) : Status.report_business_started!(notebook.status_tree, :workspace) + create_status = Status.report_business_started!(workspace_business, :create_process) + Status.report_business_planned!(workspace_business, :init_process) + is_offline_renderer || (notebook.process_status = ProcessStatus.starting) - - use_distributed = if is_offline_renderer - false + + WorkerType = if is_offline_renderer || !session.options.evaluation.workspace_use_distributed + Malt.InProcessWorker + elseif something( + session.options.evaluation.workspace_use_distributed_stdlib, + Sys.iswindows() ? false : true + ) + Malt.DistributedStdlibWorker else - session.options.evaluation.workspace_use_distributed + Malt.Worker end - - pid = if use_distributed - create_workspaceprocess(;compiler_options=_merge_notebook_compiler_options(notebook, session.options.compiler)) - else - pid = Distributed.myid() - if !(isdefined(Main, :PlutoRunner) && Main.PlutoRunner isa Module) - # we make PlutoRunner available in Main, right now it's only defined inside this Pluto module. - @eval Main begin - PlutoRunner = $(PlutoRunner) - end - end - pid + + @debug "Creating workspace process" notebook.path length(notebook.cells) + worker = create_workspaceprocess(WorkerType; compiler_options=_merge_notebook_compiler_options(notebook, session.options.compiler)) + + Status.report_business_finished!(workspace_business, :create_process) + init_status = Status.report_business_started!(workspace_business, :init_process) + Status.report_business_started!(init_status, Symbol(1)) + Status.report_business_planned!(init_status, Symbol(2)) + Status.report_business_planned!(init_status, Symbol(3)) + Status.report_business_planned!(init_status, Symbol(4)) + + let s = session.options.evaluation.workspace_custom_startup_expr + s === nothing || Malt.remote_eval_wait(worker, Meta.parseall(s)) end - Distributed.remotecall_eval(Main, [pid], :(PlutoRunner.notebook_id[] = $(notebook.notebook_id))) - log_channel = Core.eval(Main, quote - $(Distributed).RemoteChannel(() -> eval(:(Main.PlutoRunner.log_channel)), $pid) + Malt.remote_eval_wait(worker, quote + PlutoRunner.notebook_id[] = $(notebook.notebook_id) end) - run_channel = Core.eval(Main, quote - $(Distributed).RemoteChannel(() -> eval(:(Main.PlutoRunner.run_channel)), $pid) + + remote_log_channel = Malt.worker_channel(worker, quote + channel = Channel{Any}(10) + Main.PlutoRunner.setup_plutologger( + $(notebook.notebook_id), + channel + ) + channel end) - module_name = create_emptyworkspacemodule(pid) - - original_LOAD_PATH, original_ACTIVE_PROJECT = Distributed.remotecall_eval(Main, pid, :(Base.LOAD_PATH, Base.ACTIVE_PROJECT[])) - + + run_channel = Malt.worker_channel(worker, :(Main.PlutoRunner.run_channel)) + + module_name = create_emptyworkspacemodule(worker) + + original_LOAD_PATH, original_ACTIVE_PROJECT = Malt.remote_eval_fetch(worker, :(Base.LOAD_PATH, Base.ACTIVE_PROJECT[])) + workspace = Workspace(; - pid=pid, - log_channel=log_channel, - module_name=module_name, - original_LOAD_PATH=original_LOAD_PATH, - original_ACTIVE_PROJECT=original_ACTIVE_PROJECT, - is_offline_renderer=is_offline_renderer, + worker, + notebook_id=notebook.notebook_id, + remote_log_channel, + module_name, + original_LOAD_PATH, + original_ACTIVE_PROJECT, + is_offline_renderer, ) + + + Status.report_business_finished!(init_status, Symbol(1)) + Status.report_business_started!(init_status, Symbol(2)) - @async start_relaying_logs((session, notebook), log_channel) + @async start_relaying_logs((session, notebook), remote_log_channel) @async start_relaying_self_updates((session, notebook), run_channel) cd_workspace(workspace, notebook.path) + + Status.report_business_finished!(init_status, Symbol(2)) + Status.report_business_started!(init_status, Symbol(3)) + use_nbpkg_environment((session, notebook), workspace) + + Status.report_business_finished!(init_status, Symbol(3)) + Status.report_business_started!(init_status, Symbol(4)) + + # TODO: precompile 1+1 with display + # sleep(3) + eval_format_fetch_in_workspace(workspace, Expr(:toplevel, LineNumberNode(-1), :(1+1)), uuid1(); code_is_effectful=false) + + Status.report_business_finished!(init_status, Symbol(4)) + Status.report_business_finished!(workspace_business, :init_process) + Status.report_business_finished!(workspace_business) - is_offline_renderer || (notebook.process_status = ProcessStatus.ready) + is_offline_renderer || if notebook.process_status == ProcessStatus.starting + notebook.process_status = ProcessStatus.ready + end return workspace end function use_nbpkg_environment((session, notebook)::SN, workspace=nothing) enabled = notebook.nbpkg_ctx !== nothing - if workspace.nbpkg_was_active == enabled - return - end - + workspace.nbpkg_was_active == enabled && return + workspace = workspace !== nothing ? workspace : get_workspace((session, notebook)) - if workspace.discarded - return - end - + workspace.discarded && return + workspace.nbpkg_was_active = enabled - if workspace.pid != Distributed.myid() - new_LP = enabled ? ["@", "@stdlib"] : workspace.original_LOAD_PATH - new_AP = enabled ? PkgCompat.env_dir(notebook.nbpkg_ctx) : workspace.original_ACTIVE_PROJECT - - Distributed.remotecall_eval(Main, [workspace.pid], quote - copy!(LOAD_PATH, $(new_LP)) - Base.ACTIVE_PROJECT[] = $(new_AP) - end) - else - # uhmmmmmm TODO + if workspace.worker isa Malt.InProcessWorker + # Not supported + return end + new_LP = enabled ? ["@", "@stdlib"] : workspace.original_LOAD_PATH + new_AP = enabled ? PkgCompat.env_dir(notebook.nbpkg_ctx) : workspace.original_ACTIVE_PROJECT + + Malt.remote_eval_wait(workspace.worker, quote + copy!(LOAD_PATH, $(new_LP)) + Base.ACTIVE_PROJECT[] = $(new_AP) + end) end -function start_relaying_self_updates((session, notebook)::SN, run_channel::Distributed.RemoteChannel) +function start_relaying_self_updates((session, notebook)::SN, run_channel) while true try next_run_uuid = take!(run_channel) @@ -126,11 +174,57 @@ function start_relaying_self_updates((session, notebook)::SN, run_channel::Distr end end -function start_relaying_logs((session, notebook)::SN, log_channel::Distributed.RemoteChannel) +function start_relaying_logs((session, notebook)::SN, log_channel) + update_throttled, flush_throttled = Pluto.throttled(0.1) do + Pluto.send_notebook_changes!(Pluto.ClientRequest(; session, notebook)) + end + while true try - next_log = take!(log_channel) - putnotebookupdates!(session, notebook, UpdateMessage(:log, next_log, notebook)) + next_log::Dict{String,Any} = take!(log_channel) + + fn = next_log["file"] + match = findfirst("#==#", fn) + + # Show the log at the currently running cell, which is given by + running_cell_id = next_log["cell_id"]::UUID + + # Some logs originate from outside of the running code, through function calls. Some code here to deal with that: + begin + source_cell_id = if match !== nothing + # The log originated from within the notebook + UUID(fn[match[end]+1:end]) + else + # The log originated from a function call defined outside of the notebook. + # Show the log at the currently running cell, at "line -1", i.e. without line info. + next_log["line"] = -1 + running_cell_id + end + + if running_cell_id != source_cell_id + # The log originated from a function in another cell of the notebook + # Show the log at the currently running cell, at "line -1", i.e. without line info. + next_log["line"] = -1 + end + end + + source_cell = get(notebook.cells_dict, source_cell_id, nothing) + running_cell = get(notebook.cells_dict, running_cell_id, nothing) + + display_cell = if running_cell === nothing || (source_cell !== nothing && source_cell.output.has_pluto_hook_features) + source_cell + else + running_cell + end + + @assert !isnothing(display_cell) + + # this handles the use of published_to_js inside logs: objects that were newly published during the rendering of the log args. + merge!(display_cell.published_objects, next_log["new_published_objects"]) + delete!(next_log, "new_published_objects") + + push!(display_cell.logs, next_log) + Pluto.@asynclog update_throttled() catch e if !isopen(log_channel) break @@ -143,7 +237,7 @@ end "Call `cd(\$path)` inside the workspace. This is done when creating a workspace, and whenever the notebook changes path." function cd_workspace(workspace, path::AbstractString) eval_in_workspace(workspace, quote - cd($(path |> dirname)) + cd(dirname($path)) end) end @@ -151,83 +245,117 @@ end function bump_workspace_module(session_notebook::SN) workspace = get_workspace(session_notebook) old_name = workspace.module_name - new_name = workspace.module_name = create_emptyworkspacemodule(workspace.pid) + new_name = workspace.module_name = create_emptyworkspacemodule(workspace.worker) old_name, new_name end +function get_bond_names(session_notebook::SN, cell_id) + workspace = get_workspace(session_notebook) + + Malt.remote_eval_fetch(workspace.worker, quote + PlutoRunner.get_bond_names($cell_id) + end) +end + function possible_bond_values(session_notebook::SN, n::Symbol; get_length::Bool=false) workspace = get_workspace(session_notebook) - pid = workspace.pid - Distributed.remotecall_eval(Main, pid, quote + Malt.remote_eval_fetch(workspace.worker, quote PlutoRunner.possible_bond_values($(QuoteNode(n)); get_length=$(get_length)) end) end -function create_emptyworkspacemodule(pid::Integer)::Symbol - Distributed.remotecall_eval(Main, pid, :(PlutoRunner.increment_current_module())) +function create_emptyworkspacemodule(worker::Malt.AbstractWorker)::Symbol + Malt.remote_eval_fetch(worker, quote + PlutoRunner.increment_current_module() + end) end -const Distributed_expr = :( - Base.loaded_modules[Base.PkgId(Base.UUID("8ba89e20-285c-5b6f-9357-94700520ee1b"), "Distributed")] -) - # NOTE: this function only start a worker process using given # compiler options, it does not resolve paths for notebooks # compiler configurations passed to it should be resolved before this -function create_workspaceprocess(;compiler_options=CompilerOptions())::Integer - # run on proc 1 in case Pluto is being used inside a notebook process - # Workaround for "only process 1 can add/remove workers" - pid = Distributed.remotecall_eval(Main, 1, quote - $(Distributed_expr).addprocs(1; exeflags=$(_convert_to_flags(compiler_options))) |> first - end) +function create_workspaceprocess(WorkerType; compiler_options=CompilerOptions(), status::Status.Business=Status.Business())::Malt.AbstractWorker - for expr in process_preamble - Distributed.remotecall_eval(Main, [pid], expr) + if WorkerType === Malt.InProcessWorker + worker = WorkerType() + + if !(isdefined(Main, :PlutoRunner) && Main.PlutoRunner isa Module) + # we make PlutoRunner available in Main, right now it's only defined inside this Pluto module. + Malt.remote_eval_wait(Main, worker, quote + PlutoRunner = $(PlutoRunner) + end) + end + else + + Status.report_business_started!(status, Symbol(1)) + Status.report_business_planned!(status, Symbol(2)) + + worker = WorkerType(; exeflags=_convert_to_flags(compiler_options)) + + Status.report_business_finished!(status, Symbol(1)) + Status.report_business_started!(status, Symbol(2)) + + Malt.remote_eval_wait(worker, process_preamble()) + + # so that we NEVER break the workspace with an interrupt 🤕 + Malt.remote_eval(worker, quote + while true + try + wait() + catch end + end + end) end - - # so that we NEVER break the workspace with an interrupt 🤕 - @async Distributed.remotecall_eval(Main, [pid], - :(while true - try - wait() - catch end - end)) - - pid + + Status.report_business_finished!(status) + worker end -"Return the `Workspace` of `notebook`; will be created if none exists yet." -function get_workspace(session_notebook::SN)::Workspace +""" +Return the `Workspace` of `notebook`; will be created if none exists yet. + +If `allow_creation=false`, then `nothing` is returned if no workspace exists, instead of creating one. +""" +function get_workspace(session_notebook::SN; allow_creation::Bool=true)::Union{Nothing,Workspace} session, notebook = session_notebook - promise = get!(workspaces, notebook.notebook_id) do - Promise{Workspace}(() -> make_workspace(session_notebook)) + if notebook.notebook_id in discarded_workspaces + @debug "This should not happen" notebook.process_status + error("Cannot run code in this notebook: it has already shut down.") end - fetch(promise) + + task = if !allow_creation + get(active_workspaces, notebook.notebook_id, nothing) + else + get!(active_workspaces, notebook.notebook_id) do + Task(() -> make_workspace(session_notebook)) + end + end + + isnothing(task) && return nothing + istaskstarted(task) || schedule(task) + fetch(task) end -get_workspace(workspace::Workspace)::Workspace = workspace +get_workspace(workspace::Workspace; kwargs...)::Workspace = workspace -"Try our best to delete the workspace. `ProcessWorkspace` will have its worker process terminated." -function unmake_workspace(session_notebook::Union{SN,Workspace}; async=false) - workspace = get_workspace(session_notebook) +"Try our best to delete the workspace. `Workspace` will have its worker process terminated." +function unmake_workspace(session_notebook::SN; async::Bool=false, verbose::Bool=true, allow_restart::Bool=true) + session, notebook = session_notebook + workspace = get_workspace(session_notebook; allow_creation=false) + workspace === nothing && return workspace.discarded = true + allow_restart || push!(discarded_workspaces, notebook.notebook_id) - if workspace.pid != Distributed.myid() - filter!(p -> fetch(p.second).pid != workspace.pid, workspaces) - t = @async begin - interrupt_workspace(workspace; verbose=false) - # run on proc 1 in case Pluto is being used inside a notebook process - # Workaround for "only process 1 can add/remove workers" - Distributed.remotecall_eval(Main, 1, quote - $(Distributed_expr).rmprocs($(workspace.pid)) - end) - end - async || wait(t) + filter!(p -> fetch(p.second).worker != workspace.worker, active_workspaces) + t = @async begin + interrupt_workspace(workspace; verbose=false) + Malt.stop(workspace.worker) end + async || wait(t) + nothing end -function distributed_exception_result(ex::Base.IOError, workspace::Workspace) +function workspace_exception_result(ex::Union{Base.IOError, Malt.TerminatedWorkerException, Distributed.ProcessExitedException}, workspace::Workspace) ( output_formatted=PlutoRunner.format_output(CapturedException(ex, [])), errored=true, @@ -239,15 +367,11 @@ function distributed_exception_result(ex::Base.IOError, workspace::Workspace) ) end +workspace_exception_result(exs::CompositeException, workspace::Workspace) = workspace_exception_result(first(exs.exceptions), workspace) - -function distributed_exception_result(exs::CompositeException, workspace::Workspace) - ex = exs.exceptions |> first - - if ex isa Distributed.RemoteException && - ex.pid == workspace.pid && - ex.captured.ex isa InterruptException - +function workspace_exception_result(ex::Exception, workspace::Workspace) + if ex isa InterruptException || (ex isa Malt.RemoteException && occursin("InterruptException", ex.message)) + @info "Found an interrupt!" ex ( output_formatted=PlutoRunner.format_output(CapturedException(InterruptException(), [])), errored=true, @@ -257,23 +381,13 @@ function distributed_exception_result(exs::CompositeException, workspace::Worksp published_objects=Dict{String,Any}(), has_pluto_hook_features=false, ) - elseif ex isa Distributed.ProcessExitedException - ( - output_formatted=PlutoRunner.format_output(CapturedException(exs, [])), - errored=true, - interrupted=true, - process_exited=true && !workspace.discarded, # don't report a process exit if the workspace was discarded on purpose - runtime=nothing, - published_objects=Dict{String,Any}(), - has_pluto_hook_features=false, - ) else @error "Unkown error during eval_format_fetch_in_workspace" ex ( - output_formatted=PlutoRunner.format_output(CapturedException(exs, [])), + output_formatted=PlutoRunner.format_output(CapturedException(ex, [])), errored=true, interrupted=true, - process_exited=false, + process_exited=!Malt.isrunning(workspace.worker) && !workspace.discarded, # don't report a process exit if the workspace was discarded on purpose runtime=nothing, published_objects=Dict{String,Any}(), has_pluto_hook_features=false, @@ -282,109 +396,123 @@ function distributed_exception_result(exs::CompositeException, workspace::Worksp end -"Evaluate expression inside the workspace - output is fetched and formatted, errors are caught and formatted. Returns formatted output and error flags. +""" +Evaluate expression inside the workspace - output is fetched and formatted, +errors are caught and formatted. Returns formatted output and error flags. -`expr` has to satisfy `ExpressionExplorer.is_toplevel_expr`." +`expr` has to satisfy `ExpressionExplorer.is_toplevel_expr`. +""" function eval_format_fetch_in_workspace( session_notebook::Union{SN,Workspace}, expr::Expr, - cell_id::UUID, + cell_id::UUID; ends_with_semicolon::Bool=false, function_wrapped_info::Union{Nothing,Tuple}=nothing, forced_expr_id::Union{PlutoRunner.ObjectID,Nothing}=nothing, - user_requested_run::Bool=true, known_published_objects::Vector{String}=String[], -)::NamedTuple{(:output_formatted, :errored, :interrupted, :process_exited, :runtime, :published_objects, :has_pluto_hook_features),Tuple{PlutoRunner.MimedOutput,Bool,Bool,Bool,Union{UInt64,Nothing},Dict{String,Any},Bool}} + user_requested_run::Bool=true, + capture_stdout::Bool=true, + code_is_effectful::Bool=true, +)::PlutoRunner.FormattedCellResult workspace = get_workspace(session_notebook) + is_on_this_process = workspace.worker isa Malt.InProcessWorker # if multiple notebooks run on the same process, then we need to `cd` between the different notebook paths if session_notebook isa Tuple - if workspace.pid == Distributed.myid() - cd_workspace(workspace, session_notebook[2].path) - end use_nbpkg_environment(session_notebook, workspace) end - - # run the code 🏃‍♀️ - - # a try block (on this process) to catch an InterruptException + + # Run the code 🏃 + + # A try block (on this process) to catch an InterruptException take!(workspace.dowork_token) + workspace.has_executed_effectful_code |= code_is_effectful early_result = try - # we use [pid] instead of pid to prevent fetching output - Distributed.remotecall_eval(Main, [workspace.pid], :(PlutoRunner.run_expression( - getfield(Main, $(QuoteNode(workspace.module_name))), - $(QuoteNode(expr)), - $cell_id, - $function_wrapped_info, - $forced_expr_id, - user_requested_run=$user_requested_run, - ))) + Malt.remote_eval_wait(workspace.worker, quote + PlutoRunner.run_expression( + getfield(Main, $(QuoteNode(workspace.module_name))), + $(QuoteNode(expr)), + $(workspace.notebook_id), + $cell_id, + $function_wrapped_info, + $forced_expr_id; + user_requested_run=$user_requested_run, + capture_stdout=$(capture_stdout && !is_on_this_process), + ) + end) put!(workspace.dowork_token) nothing - catch exs - # We don't use a `finally` because the token needs to be back asap for the interrupting code to pick it up. + catch e + # Don't use a `finally` because the token needs to be back asap for the interrupting code to pick it up. put!(workspace.dowork_token) - distributed_exception_result(exs, workspace) + workspace_exception_result(e, workspace) end - early_result === nothing ? - format_fetch_in_workspace(workspace, cell_id, ends_with_semicolon, known_published_objects) : + if early_result === nothing + format_fetch_in_workspace(workspace, cell_id, ends_with_semicolon, known_published_objects; capture_stdout) + else early_result + end end "Evaluate expression inside the workspace - output is not fetched, errors are rethrown. For internal use." function eval_in_workspace(session_notebook::Union{SN,Workspace}, expr) workspace = get_workspace(session_notebook) - - Distributed.remotecall_eval(Main, [workspace.pid], :(Core.eval($(workspace.module_name), $(expr |> QuoteNode)))) + + Malt.remote_eval_wait(workspace.worker, quote + Core.eval($(workspace.module_name), $(QuoteNode(expr))) + end) nothing end function format_fetch_in_workspace( - session_notebook::Union{SN,Workspace}, - cell_id, - ends_with_semicolon, + session_notebook::Union{SN,Workspace}, + cell_id, + ends_with_semicolon, known_published_objects::Vector{String}=String[], - showmore_id::Union{PlutoRunner.ObjectDimPair,Nothing}=nothing, -)::NamedTuple{(:output_formatted, :errored, :interrupted, :process_exited, :runtime, :published_objects, :has_pluto_hook_features),Tuple{PlutoRunner.MimedOutput,Bool,Bool,Bool,Union{UInt64,Nothing},Dict{String,Any},Bool}} + showmore_id::Union{PlutoRunner.ObjectDimPair,Nothing}=nothing; + capture_stdout::Bool=true, +)::PlutoRunner.FormattedCellResult workspace = get_workspace(session_notebook) - - # instead of fetching the output value (which might not make sense in our context, since the user can define structs, types, functions, etc), we format the cell output on the worker, and fetch the formatted output. + + # Instead of fetching the output value (which might not make sense in our context, + # since the user can define structs, types, functions, etc), + # we format the cell output on the worker, and fetch the formatted output. withtoken(workspace.dowork_token) do try - Distributed.remotecall_eval(Main, workspace.pid, :(PlutoRunner.formatted_result_of( - $cell_id, - $ends_with_semicolon, - $known_published_objects, - $showmore_id, - getfield(Main, $(QuoteNode(workspace.module_name))), - ))) - catch ex - distributed_exception_result(CompositeException([ex]), workspace) + Malt.remote_eval_fetch(workspace.worker, quote + PlutoRunner.formatted_result_of( + $(workspace.notebook_id), + $cell_id, + $ends_with_semicolon, + $known_published_objects, + $showmore_id, + getfield(Main, $(QuoteNode(workspace.module_name))); + capture_stdout=$capture_stdout, + ) + end) + catch e + workspace_exception_result(CompositeException([e]), workspace) end end end function collect_soft_definitions(session_notebook::SN, modules::Set{Expr}) workspace = get_workspace(session_notebook) - module_name = workspace.module_name - - ex = quote - PlutoRunner.collect_soft_definitions($module_name, $modules) - end - Distributed.remotecall_eval(Main, workspace.pid, ex) + Malt.remote_eval_fetch(workspace.worker, quote + PlutoRunner.collect_soft_definitions($(workspace.module_name), $modules) + end) end - -function macroexpand_in_workspace(session_notebook::Union{SN,Workspace}, macrocall, cell_uuid, module_name = nothing)::Tuple{Bool, Any} +function macroexpand_in_workspace(session_notebook::SN, macrocall, cell_id, module_name = Symbol(""); capture_stdout::Bool=true)::Tuple{Bool, Any} workspace = get_workspace(session_notebook) - module_name = module_name === nothing ? workspace.module_name : module_name + module_name = module_name === Symbol("") ? workspace.module_name : module_name - Distributed.remotecall_eval(Main, workspace.pid, quote + Malt.remote_eval_fetch(workspace.worker, quote try - (true, PlutoRunner.try_macroexpand($(module_name), $(cell_uuid), $(macrocall |> QuoteNode))) + (true, PlutoRunner.try_macroexpand($(module_name), $(workspace.notebook_id), $(cell_id), $(macrocall |> QuoteNode); capture_stdout=$(capture_stdout))) catch error # We have to be careful here, for example a thrown `MethodError()` will contain the called method and arguments. # which normally would be very useful for debugging, but we can't serialize it! @@ -401,26 +529,55 @@ end "Evaluate expression inside the workspace - output is returned. For internal use." function eval_fetch_in_workspace(session_notebook::Union{SN,Workspace}, expr) workspace = get_workspace(session_notebook) - - Distributed.remotecall_eval(Main, workspace.pid, :(Core.eval($(workspace.module_name), $(expr |> QuoteNode)))) + + Malt.remote_eval_fetch(workspace.worker, quote + Core.eval($(workspace.module_name), $(QuoteNode(expr))) + end) end function do_reimports(session_notebook::Union{SN,Workspace}, module_imports_to_move::Set{Expr}) workspace = get_workspace(session_notebook) - workspace_name = workspace.module_name - Distributed.remotecall_eval(Main, [workspace.pid], :(PlutoRunner.do_reimports($(workspace_name), $module_imports_to_move))) + + Malt.remote_eval_wait(workspace.worker, quote + PlutoRunner.do_reimports($(workspace.module_name), $module_imports_to_move) + end) end -"Move variables to a new module. A given set of variables to be 'deleted' will not be moved to the new module, making them unavailable. " -function move_vars(session_notebook::Union{SN,Workspace}, old_workspace_name::Symbol, new_workspace_name::Union{Nothing,Symbol}, to_delete::Set{Symbol}, methods_to_delete::Set{Tuple{UUID,FunctionName}}, module_imports_to_move::Set{Expr}; kwargs...) +""" +Move variables to a new module. A given set of variables to be 'deleted' will +not be moved to the new module, making them unavailable. +""" +function move_vars( + session_notebook::Union{SN,Workspace}, + old_workspace_name::Symbol, + new_workspace_name::Union{Nothing,Symbol}, + to_delete::Set{Symbol}, + methods_to_delete::Set{Tuple{UUID,Tuple{Vararg{Symbol}}}}, + module_imports_to_move::Set{Expr}, + invalidated_cell_uuids::Set{UUID}, + keep_registered::Set{Symbol}=Set{Symbol}(); + kwargs... + ) + workspace = get_workspace(session_notebook) new_workspace_name = something(new_workspace_name, workspace.module_name) - - Distributed.remotecall_eval(Main, [workspace.pid], :(PlutoRunner.move_vars($(old_workspace_name |> QuoteNode), $(new_workspace_name |> QuoteNode), $to_delete, $methods_to_delete, $module_imports_to_move))) + + Malt.remote_eval_wait(workspace.worker, quote + PlutoRunner.move_vars( + $(QuoteNode(old_workspace_name)), + $(QuoteNode(new_workspace_name)), + $to_delete, + $methods_to_delete, + $module_imports_to_move, + $invalidated_cell_uuids, + $keep_registered, + ) + end) end -move_vars(session_notebook::Union{SN,Workspace}, to_delete::Set{Symbol}, methods_to_delete::Set{Tuple{UUID,FunctionName}}, module_imports_to_move::Set{Expr}; kwargs...) = -move_vars(session_notebook, bump_workspace_module(session_notebook)..., to_delete, methods_to_delete, module_imports_to_move; kwargs...) +function move_vars(session_notebook::Union{SN,Workspace}, to_delete::Set{Symbol}, methods_to_delete::Set{Tuple{UUID,Tuple{Vararg{Symbol}}}}, module_imports_to_move::Set{Expr}, invalidated_cell_uuids::Set{UUID}; kwargs...) + move_vars(session_notebook, bump_workspace_module(session_notebook)..., to_delete, methods_to_delete, module_imports_to_move, invalidated_cell_uuids; kwargs...) +end # TODO: delete me @deprecate( @@ -428,6 +585,40 @@ move_vars(session_notebook, bump_workspace_module(session_notebook)..., to_delet move_vars(args...; kwargs...) ) +""" +```julia +poll(query::Function, timeout::Real=Inf64, interval::Real=1/20)::Bool +``` + +Keep running your function `query()` in intervals until it returns `true`, or until `timeout` seconds have passed. + +`poll` returns `true` if `query()` returned `true`. If `timeout` seconds have passed, `poll` returns `false`. + +# Example +```julia +vals = [1,2,3] + +@async for i in 1:5 + sleep(1) + vals[3] = 99 +end + +poll(8 #= seconds =#) do + vals[3] == 99 +end # returns `true` (after 5 seconds)! + +### + +@async for i in 1:5 + sleep(1) + vals[3] = 5678 +end + +poll(2 #= seconds =#) do + vals[3] == 5678 +end # returns `false` (after 2 seconds)! +``` +""" function poll(query::Function, timeout::Real=Inf64, interval::Real=1/20) start = time() while time() < start + timeout @@ -441,23 +632,23 @@ end "Force interrupt (SIGINT) a workspace, return whether successful" function interrupt_workspace(session_notebook::Union{SN,Workspace}; verbose=true)::Bool - workspace = get_workspace(session_notebook) + workspace = get_workspace(session_notebook; allow_creation=false) + + if !(workspace isa Workspace) + # verbose && @info "Can't interrupt this notebook: it is not running." + return false + end if poll(() -> isready(workspace.dowork_token), 2.0, 5/100) verbose && println("Cell finished, other cells cancelled!") return true end - if Sys.iswindows() - verbose && @warn "Unfortunately, stopping cells is currently not supported on Windows :( - Maybe the Windows Subsystem for Linux is right for you: - https://docs.microsoft.com/en-us/windows/wsl" - return false - end - if workspace.pid == Distributed.myid() - verbose && @warn """Cells in this workspace can't be stopped, because it is not running in a separate workspace. Use `ENV["PLUTO_WORKSPACE_USE_DISTRIBUTED"]` to control whether future workspaces are generated in a separate process.""" + if (workspace.worker isa Malt.DistributedStdlibWorker) && Sys.iswindows() + verbose && @warn "Stopping cells is not yet supported on Windows, but it will be soon!\n\nYou can already try out this new functionality with:\n\nPluto.run(workspace_use_distributed_stdlib=false)\n\nLet us know what you think!" return false end + if isready(workspace.dowork_token) verbose && @info "Tried to stop idle workspace - ignoring." return true @@ -468,8 +659,8 @@ function interrupt_workspace(session_notebook::Union{SN,Workspace}; verbose=true # TODO: this will also kill "pending" evaluations, and any evaluations started within 100ms of the kill. A global "evaluation count" would fix this. # TODO: listen for the final words of the remote process on stdout/stderr: "Force throwing a SIGINT" try - verbose && @info "Sending interrupt to process $(workspace.pid)" - Distributed.interrupt(workspace.pid) + verbose && @info "Sending interrupt to process $(workspace.worker)" + Malt.interrupt(workspace.worker) if poll(() -> isready(workspace.dowork_token), 5.0, 5/100) verbose && println("Cell interrupted!") @@ -477,10 +668,10 @@ function interrupt_workspace(session_notebook::Union{SN,Workspace}; verbose=true end verbose && println("Still running... starting sequence") - while !isready(workspace.dowork_token) + while !isready(workspace.dowork_token) for _ in 1:5 verbose && print(" 🔥 ") - Distributed.interrupt(workspace.pid) + Malt.interrupt(workspace.worker) sleep(0.18) if isready(workspace.dowork_token) break @@ -491,10 +682,10 @@ function interrupt_workspace(session_notebook::Union{SN,Workspace}; verbose=true verbose && println() verbose && println("Cell interrupted!") true - catch ex - if !(ex isa KeyError) + catch e + if !(e isa KeyError) @warn "Interrupt failed for unknown reason" - showerror(ex, stacktrace(catch_backtrace())) + showerror(e, stacktrace(catch_backtrace())) end false end diff --git a/src/notebook/Cell.jl b/src/notebook/Cell.jl index b9240167b5..c04732764d 100644 --- a/src/notebook/Cell.jl +++ b/src/notebook/Cell.jl @@ -1,5 +1,15 @@ import UUIDs: UUID, uuid1 -import .ExpressionExplorer: SymbolsState, UsingsImports + +const METADATA_DISABLED_KEY = "disabled" +const METADATA_SHOW_LOGS_KEY = "show_logs" +const METADATA_SKIP_AS_SCRIPT_KEY = "skip_as_script" + +# Make sure to keep this in sync with DEFAULT_CELL_METADATA in ../frontend/components/Editor.js +const DEFAULT_CELL_METADATA = Dict{String, Any}( + METADATA_DISABLED_KEY => false, + METADATA_SHOW_LOGS_KEY => true, + METADATA_SKIP_AS_SCRIPT_KEY => false, +) Base.@kwdef struct CellOutput body::Union{Nothing,String,Vector{UInt8},Dict}=nothing @@ -36,17 +46,21 @@ Base.@kwdef mutable struct Cell published_objects::Dict{String,Any}=Dict{String,Any}() + logs::Vector{Dict{String,Any}}=Vector{Dict{String,Any}}() + errored::Bool=false runtime::Union{Nothing,UInt64}=nothing # note that this field might be moved somewhere else later. If you are interested in visualizing the cell dependencies, take a look at the cell_dependencies field in the frontend instead. cell_dependencies::CellDependencies{Cell}=CellDependencies{Cell}(Dict{Symbol,Vector{Cell}}(), Dict{Symbol,Vector{Cell}}(), 99) - running_disabled::Bool=false depends_on_disabled_cells::Bool=false + depends_on_skipped_cells::Bool=false + + metadata::Dict{String,Any}=copy(DEFAULT_CELL_METADATA) end -Cell(cell_id, code) = Cell(cell_id=cell_id, code=code) +Cell(cell_id, code) = Cell(; cell_id, code) Cell(code) = Cell(uuid1(), code) cell_id(cell::Cell) = cell.cell_id @@ -56,9 +70,17 @@ function Base.convert(::Type{Cell}, cell::Dict) cell_id=UUID(cell["cell_id"]), code=cell["code"], code_folded=cell["code_folded"], - running_disabled=cell["running_disabled"], + metadata=cell["metadata"], ) end -function Base.convert(::Type{UUID}, string::String) - UUID(string) + +"Returns whether or not the cell is **explicitely** disabled." +is_disabled(c::Cell) = get(c.metadata, METADATA_DISABLED_KEY, DEFAULT_CELL_METADATA[METADATA_DISABLED_KEY]) +set_disabled(c::Cell, value::Bool) = if value == DEFAULT_CELL_METADATA[METADATA_DISABLED_KEY] + delete!(c.metadata, METADATA_DISABLED_KEY) +else + c.metadata[METADATA_DISABLED_KEY] = value end +can_show_logs(c::Cell) = get(c.metadata, METADATA_SHOW_LOGS_KEY, DEFAULT_CELL_METADATA[METADATA_SHOW_LOGS_KEY]) +is_skipped_as_script(c::Cell) = get(c.metadata, METADATA_SKIP_AS_SCRIPT_KEY, DEFAULT_CELL_METADATA[METADATA_SKIP_AS_SCRIPT_KEY]) +must_be_commented_in_file(c::Cell) = is_disabled(c) || is_skipped_as_script(c) || c.depends_on_disabled_cells || c.depends_on_skipped_cells diff --git a/src/notebook/Events.jl b/src/notebook/Events.jl index a3590ad548..748fbcaa0e 100644 --- a/src/notebook/Events.jl +++ b/src/notebook/Events.jl @@ -9,43 +9,50 @@ the FileSaveEvent may be triggered whenever pluto wants to make sure the file is which may be more often than the file is actually changed. Deduplicate on your own if you care about this. -To use that, we assume you are running Pluto through a julia script and -opening it as - -julia > pluto_server_session = Pluto.ServerSession(; - secret = secret, - options = pluto_server_options, -) - Define your function to handle the events using multiple dispatch: First assign a handler for all the types you will not use, using the supertype: -julia > function myfn(a::PlutoEvent) - nothing - end +```julia-repl +julia> function myfn(a::PlutoEvent) + nothing + end +``` + And then create a special function for each event you want to handle specially -julia > function myfn(a::FileSaveEvent) - HTTP.post("https://my.service.com/count_saves") - end +```julia-repl +julia> function myfn(a::FileSaveEvent) + HTTP.post("https://my.service.com/count_saves") + end +``` -Finally, assign the listener to your session +Finally, pass the listener to Pluto's configurations with a keyword argument -julia > pluto_server_session.event_listener = yourfunction +```julia-repl +julia> Pluto.run(; on_event = myfn) +``` """ abstract type PlutoEvent end function try_event_call(session, event::PlutoEvent) return try - session.event_listener(event) + session.options.server.on_event(event) catch e - @warn "Couldn't run event listener" event exception=(e, catch_backtrace()) + # Do not print all the event; it's too big! + @warn "Couldn't run event listener" event_type=typeof(event) exception=(e, catch_backtrace()) nothing end end + +# Triggered when the web server gets started +struct ServerStartEvent <: PlutoEvent + address::String + port::UInt16 +end + # Triggered when a notebook is saved struct FileSaveEvent <: PlutoEvent notebook::Notebook @@ -77,16 +84,21 @@ FileEditEvent(notebook::Notebook) = begin FileEditEvent(notebook, file_contents, notebook.path) end -# Triggered when we open a new notebook +# Triggered when we create a new notebook struct NewNotebookEvent <: PlutoEvent - notebook::Notebook end -# Triggered when a user opens a notebook +# Triggered when we open any notebook struct OpenNotebookEvent <: PlutoEvent notebook::Notebook end +# Triggered when Pluto completes an evaluation loop +struct NotebookExecutionDoneEvent <: PlutoEvent + notebook::Notebook + user_requested_run::Bool +end + # This will be fired ONLY if URL params don't match anything else. # Useful if you want to create a file in a custom way, # before opening the notebook diff --git a/src/notebook/Export.jl b/src/notebook/Export.jl index 6770d5a37f..e05186b4b9 100644 --- a/src/notebook/Export.jl +++ b/src/notebook/Export.jl @@ -1,5 +1,7 @@ import Pkg using Base64 +using HypertextLiteral +import URIs const default_binder_url = "https://mybinder.org/v2/gh/fonsp/pluto-on-binder/v$(string(PLUTO_VERSION))" @@ -10,6 +12,70 @@ if cdn_version_override !== nothing @warn "Reminder to fonsi: Using a development version of Pluto for CDN assets. The binder button might not work. You should not see this on a released version of Pluto." cdn_version_override end +cdnified_editor_html(; kwargs...) = cdnified_html("editor.html"; kwargs...) + +function cdnified_html(filename::AbstractString; + version::Union{Nothing,VersionNumber,AbstractString}=nothing, + pluto_cdn_root::Union{Nothing,AbstractString}=nothing, + ) + should_use_bundled_cdn = version ∈ (nothing, PLUTO_VERSION) && pluto_cdn_root === nothing + + something( + if should_use_bundled_cdn + try + original = read(project_relative_path("frontend-dist", filename), String) + + cdn_root = "https://cdn.jsdelivr.net/gh/fonsp/Pluto.jl@$(string(PLUTO_VERSION))/frontend-dist/" + + @debug "Using CDN for Pluto assets:" cdn_root + + replace_with_cdn(original) do url + # Because parcel creates filenames with a hash in them, we can check if the file exists locally to make sure that everything is in order. + @assert isfile(project_relative_path("frontend-dist", url)) "Could not find the file $(project_relative_path("frontend-dist", url)) locally, that's a bad sign." + + URIs.resolvereference(cdn_root, url) |> string + end + catch e + @warn "Could not use bundled CDN version of $(filename). You should only see this message if you are using a fork of Pluto." exception=(e,catch_backtrace()) maxlog=1 + nothing + end + end, + let + original = read(project_relative_path("frontend", filename), String) + + cdn_root = something(pluto_cdn_root, "https://cdn.jsdelivr.net/gh/fonsp/Pluto.jl@$(something(cdn_version_override, string(something(version, PLUTO_VERSION))))/frontend/") + + @debug "Using CDN for Pluto assets:" cdn_root + + replace_with_cdn(original) do url + URIs.resolvereference(cdn_root, url) |> string + end + end + ) +end + +const _insertion_meta = """""" +const _insertion_parameters = """""" + + +inserted_html(original_contents::AbstractString; + meta::AbstractString="", + parameters::AbstractString="", +) = replace_at_least_once( + replace_at_least_once(original_contents, + _insertion_meta => + """ + $(meta) + $(_insertion_meta) + """ + ), + _insertion_parameters => + """ + $(parameters) + $(_insertion_parameters) + """ +) + """ See [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) if you are interested in exporting notebooks programatically. """ @@ -27,46 +93,32 @@ function generate_html(; preamble_html_js::AbstractString="undefined", notebook_id_js::AbstractString="undefined", isolated_cell_ids_js::AbstractString="undefined", - )::String - - # Here we don't use frontend-dist (bundled code) yet, might want to - # use a separate Parcel pipeline to make UBER-BUNDLED html exports (TODO DRAL) - original = read(project_relative_path("frontend", "editor.html"), String) - - cdn_root = if pluto_cdn_root === nothing - if version === nothing - version = PLUTO_VERSION - end - "https://cdn.jsdelivr.net/gh/fonsp/Pluto.jl@$(something(cdn_version_override, string(PLUTO_VERSION)))/frontend/" - else - pluto_cdn_root - end - - @debug "Using CDN for Pluto assets:" cdn_root - cdnified = replace( - replace(original, - "href=\"./" => "href=\"$(cdn_root)"), - "src=\"./" => "src=\"$(cdn_root)") + header_html::AbstractString="", + )::String - result = replace(cdnified, - "" => - """ - - - """ - ) + cdnified = cdnified_editor_html(; version, pluto_cdn_root) + + parameters = """ + + """ + + inserted_html(cdnified; meta=header_html, parameters) +end - return result +function replace_at_least_once(s, pair) + from, to = pair + @assert occursin(from, s) + replace(s, pair) end @@ -89,6 +141,108 @@ function generate_html(notebook; kwargs...)::String "\"data:;base64,$(statefile64)\"" end + fm = frontmatter(notebook) + header_html = isempty(fm) ? "" : frontmatter_html(fm) # avoid loading HypertextLiteral if there is no frontmatter + # We don't set `notebook_id_js` because this is generated by the server, the option is only there for funky setups. - generate_html(; statefile_js=statefile_js, notebookfile_js=notebookfile_js, kwargs...) + generate_html(; statefile_js, notebookfile_js, header_html, kwargs...) +end + + +const frontmatter_writers = ( + ("title", x -> @htl(""" + $(x) + """)), + ("description", x -> @htl(""" + + """)), + ("tags", x -> x isa Vector ? @htl("$(( + @htl(""" + + """) + for t in x + ))") : nothing), +) + + +const _og_properties = ("title", "type", "description", "image", "url", "audio", "video", "site_name", "locale", "locale:alternate", "determiner") + +const _default_frontmatter = Dict{String, Any}( + "type" => "article", + # Note: these defaults are skipped when there is no frontmatter at all. +) + +function frontmatter_html(frontmatter::Dict{String,Any}; default_frontmatter::Dict{String,Any}=_default_frontmatter)::String + d = merge(default_frontmatter, frontmatter) + repr(MIME"text/html"(), + @htl("""$(( + f(d[key]) + for (key, f) in frontmatter_writers if haskey(d, key) + ))$(( + @htl(""" + """) + for (key, val) in d if key in _og_properties + ))""")) +end + + +replace_substring(s::String, sub::SubString, newval::AbstractString) = *( + SubString(s, 1, prevind(s, sub.offset + 1, 1)), + newval, + SubString(s, nextind(s, sub.offset + sub.ncodeunits)) +) + +const dont_cdnify = ("new","open","shutdown","move","notebooklist","notebookfile","statefile","notebookexport","notebookupload") + +const source_pattern = r"\s(?:src|href)=\"(.+?)\"" + +function replace_with_cdn(cdnify::Function, s::String, idx::Integer=1) + next_match = match(source_pattern, s, idx) + if next_match === nothing + s + else + url = only(next_match.captures) + if occursin("//", url) || url ∈ dont_cdnify + # skip this one + replace_with_cdn(cdnify, s, nextind(s, next_match.offset)) + else + replace_with_cdn(cdnify, replace_substring( + s, + url, + cdnify(url) + )) + end + end +end + +""" +Generate a custom index.html that is designed to display a custom set of featured notebooks, without the file UI or Pluto logo. This is to be used by [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) to show a fancy index page. +""" +function generate_index_html(; + version::Union{Nothing,VersionNumber,AbstractString}=nothing, + pluto_cdn_root::Union{Nothing,AbstractString}=nothing, + + featured_direct_html_links::Bool=false, + featured_sources_js::AbstractString="undefined", +) + cdnified = cdnified_html("index.html"; version, pluto_cdn_root) + + meta = """ + + """ + + parameters = """ + + """ + + inserted_html(cdnified; meta, parameters) end diff --git a/src/notebook/Notebook.jl b/src/notebook/Notebook.jl index c2e5452b86..45f2be62ab 100644 --- a/src/notebook/Notebook.jl +++ b/src/notebook/Notebook.jl @@ -1,8 +1,11 @@ import UUIDs: UUID, uuid1 -import .ExpressionExplorer: SymbolsState, FunctionNameSignaturePair, FunctionName import .Configuration import .PkgCompat: PkgCompat, PkgContext import Pkg +import TOML +import .Status + +const DEFAULT_NOTEBOOK_METADATA = Dict{String, Any}() mutable struct BondValue value::Any @@ -16,18 +19,20 @@ const ProcessStatus = ( starting="starting", no_process="no_process", waiting_to_restart="waiting_to_restart", + waiting_for_permission="waiting_for_permission", ) "Like a [`Diary`](@ref) but more serious. 📓" Base.@kwdef mutable struct Notebook "Cells are ordered in a `Notebook`, and this order can be changed by the user. Cells will always have a constant UUID." cells_dict::Dict{UUID,Cell} - cell_order::Array{UUID,1} - + cell_order::Vector{UUID} + path::String notebook_id::UUID=uuid1() - topology::NotebookTopology=NotebookTopology() + topology::NotebookTopology _cached_topological_order::Union{Nothing,TopologicalOrder}=nothing + _cached_cell_dependencies_source::Union{Nothing,NotebookTopology}=nothing # buffer will contain all unfetched updates - must be big enough # We can keep 1024 updates pending. After this, any put! calls (i.e. calls that push an update to the notebook) will simply block, which is fine. @@ -45,320 +50,75 @@ Base.@kwdef mutable struct Notebook nbpkg_restart_recommended_msg::Union{Nothing,String}=nothing nbpkg_restart_required_msg::Union{Nothing,String}=nothing nbpkg_terminal_outputs::Dict{String,String}=Dict{String,String}() + nbpkg_install_time_ns::Union{Nothing,UInt64}=zero(UInt64) nbpkg_busy_packages::Vector{String}=String[] nbpkg_installed_versions_cache::Dict{String,String}=Dict{String,String}() process_status::String=ProcessStatus.starting + status_tree::Status.Business=_initial_nb_status() wants_to_interrupt::Bool=false - last_save_time::typeof(time())=time() - last_hot_reload_time::typeof(time())=zero(time()) + last_save_time::Float64=time() + last_hot_reload_time::Float64=zero(time()) bonds::Dict{Symbol,BondValue}=Dict{Symbol,BondValue}() -end -Notebook(cells::Array{Cell,1}, path::AbstractString, notebook_id::UUID) = Notebook( - cells_dict=Dict(map(cells) do cell - (cell.cell_id, cell) - end), - cell_order=map(x -> x.cell_id, cells), - path=path, - notebook_id=notebook_id, -) - -Notebook(cells::Array{Cell,1}, path::AbstractString=numbered_until_new(joinpath(new_notebooks_directory(), cutename()))) = Notebook(cells, path, uuid1()) - -function Base.getproperty(notebook::Notebook, property::Symbol) - if property == :cells - cells_dict = getfield(notebook, :cells_dict) - cell_order = getfield(notebook, :cell_order) - map(cell_order) do id - cells_dict[id] - end - elseif property == :cell_inputs - getfield(notebook, :cells_dict) - else - getfield(notebook, property) - end + metadata::Dict{String, Any}=copy(DEFAULT_NOTEBOOK_METADATA) end -const _notebook_header = "### A Pluto.jl notebook ###" -# We use a creative delimiter to avoid accidental use in code -# so don't get inspired to suddenly use these in your code! -const _cell_id_delimiter = "# ╔═╡ " -const _order_delimiter = "# ╠═" -const _order_delimiter_folded = "# ╟─" -const _cell_suffix = "\n\n" - -const _ptoml_cell_id = UUID(1) -const _mtoml_cell_id = UUID(2) - -emptynotebook(args...) = Notebook([Cell()], args...) - -""" -Save the notebook to `io`, `file` or to `notebook.path`. - -In the produced file, cells are not saved in the notebook order. If `notebook.topology` is up-to-date, I will save cells in _topological order_. This guarantees that you can run the notebook file outside of Pluto, with `julia my_notebook.jl`. - -Have a look at our [JuliaCon 2020 presentation](https://youtu.be/IAF8DjrQSSk?t=1085) to learn more! -""" -function save_notebook(io, notebook::Notebook) - println(io, _notebook_header) - println(io, "# ", PLUTO_VERSION_STR) - # Anything between the version string and the first UUID delimiter will be ignored by the notebook loader. - println(io, "") - println(io, "using Markdown") - println(io, "using InteractiveUtils") - # Super Advanced Code Analysis™ to add the @bind macro to the saved file if it's used somewhere. - if any(occursin("@bind", c.code) for c in notebook.cells) - println(io, "") - println(io, "# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).") - println(io, PlutoRunner.fake_bind) - end - println(io) - - cells_ordered = collect(topological_order(notebook)) - - for c in cells_ordered - println(io, _cell_id_delimiter, string(c.cell_id)) - # write the cell code and prevent collisions with the cell delimiter - print(io, replace(c.code, _cell_id_delimiter => "# ")) - print(io, _cell_suffix) - end - - - using_plutopkg = notebook.nbpkg_ctx !== nothing - - write_package = if using_plutopkg - ptoml_contents = PkgCompat.read_project_file(notebook) - mtoml_contents = PkgCompat.read_manifest_file(notebook) - - !isempty(strip(ptoml_contents)) - else - false - end - - if write_package - println(io, _cell_id_delimiter, string(_ptoml_cell_id)) - print(io, "PLUTO_PROJECT_TOML_CONTENTS = \"\"\"\n") - write(io, ptoml_contents) - print(io, "\"\"\"") - print(io, _cell_suffix) - - println(io, _cell_id_delimiter, string(_mtoml_cell_id)) - print(io, "PLUTO_MANIFEST_TOML_CONTENTS = \"\"\"\n") - write(io, mtoml_contents) - print(io, "\"\"\"") - print(io, _cell_suffix) - end - - - println(io, _cell_id_delimiter, "Cell order:") - for c in notebook.cells - delim = c.code_folded ? _order_delimiter_folded : _order_delimiter - println(io, delim, string(c.cell_id)) - end - if write_package - println(io, _order_delimiter_folded, string(_ptoml_cell_id)) - println(io, _order_delimiter_folded, string(_mtoml_cell_id)) - end - - notebook +function _initial_nb_status() + b = Status.Business(name=:notebook, started_at=time()) + Status.report_business_planned!(b, :workspace) + Status.report_business_planned!(b, :pkg) + Status.report_business_planned!(b, :run) + return b end -function write_buffered(fn::Function, path) - file_content = sprint(fn) - write(path, file_content) -end - -function save_notebook(notebook::Notebook, path::String) - # @warn "Saving to file!!" exception=(ErrorException(""), backtrace()) - notebook.last_save_time = time() - write_buffered(path) do io - save_notebook(io, notebook) +function _report_business_cells_planned!(notebook::Notebook) + run_status = Status.report_business_planned!(notebook.status_tree, :run) + Status.report_business_planned!(run_status, :resolve_topology) + cell_status = Status.report_business_planned!(run_status, :evaluate) + for (i,c) in enumerate(notebook.cells) + c.running = true + c.queued = true + Status.report_business_planned!(cell_status, Symbol(i)) end end -save_notebook(notebook::Notebook) = save_notebook(notebook, notebook.path) - -"Load a notebook without saving it or creating a backup; returns a `Notebook`. REMEMBER TO CHANGE THE NOTEBOOK PATH after loading it to prevent it from autosaving and overwriting the original file." -function load_notebook_nobackup(io, path)::Notebook - firstline = String(readline(io)) - - if firstline != _notebook_header - error("File is not a Pluto.jl notebook") - end - - file_VERSION_STR = readline(io)[3:end] - if file_VERSION_STR != PLUTO_VERSION_STR - # @info "Loading a notebook saved with Pluto $(file_VERSION_STR). This is Pluto $(PLUTO_VERSION_STR)." - end - - collected_cells = Dict{UUID,Cell}() - - # ignore first bits of file - readuntil(io, _cell_id_delimiter) - - while !eof(io) - cell_id_str = String(readline(io)) - if cell_id_str == "Cell order:" - break - else - cell_id = UUID(cell_id_str) - code_raw = String(readuntil(io, _cell_id_delimiter)) - # change Windows line endings to Linux - code_normalised = replace(code_raw, "\r\n" => "\n") - # remove the cell suffix - code = code_normalised[1:prevind(code_normalised, end, length(_cell_suffix))] - - read_cell = Cell(cell_id, code) - collected_cells[cell_id] = read_cell - end - end - - cell_order = UUID[] - while !eof(io) - cell_id_str = String(readline(io)) - if length(cell_id_str) >= 36 && (startswith(cell_id_str, _order_delimiter_folded) || startswith(cell_id_str, _order_delimiter)) - cell_id = let - UUID(cell_id_str[end - 35:end]) - end - next_cell = get(collected_cells, cell_id, nothing) - if next_cell !== nothing - next_cell.code_folded = startswith(cell_id_str, _order_delimiter_folded) - end - push!(cell_order, cell_id) - else - break - end - end - - read_package = - _ptoml_cell_id ∈ cell_order && - _mtoml_cell_id ∈ cell_order && - haskey(collected_cells, _ptoml_cell_id) && - haskey(collected_cells, _mtoml_cell_id) - - nbpkg_ctx = if read_package - ptoml_code = collected_cells[_ptoml_cell_id].code - mtoml_code = collected_cells[_mtoml_cell_id].code - - ptoml_contents = lstrip(split(ptoml_code, "\"\"\"")[2]) - mtoml_contents = lstrip(split(mtoml_code, "\"\"\"")[2]) - - env_dir = mktempdir() - write(joinpath(env_dir, "Project.toml"), ptoml_contents) - write(joinpath(env_dir, "Manifest.toml"), mtoml_contents) - - try - PkgCompat.load_ctx(env_dir) - catch e - @error "Failed to load notebook files: Project.toml+Manifest.toml parse error. Trying to recover Project.toml without Manifest.toml..." exception=(e,catch_backtrace()) - try - rm(joinpath(env_dir, "Manifest.toml")) - PkgCompat.load_ctx(env_dir) - catch e - @error "Failed to load notebook files: Project.toml parse error." exception=(e,catch_backtrace()) - PkgCompat.create_empty_ctx() - end - end - else - PkgCompat.create_empty_ctx() - end - - appeared_order = setdiff!( - union!( - # don't include cells that only appear in the order, but no code was given - intersect!(cell_order, keys(collected_cells)), - # add cells that appeared in code, but not in the order. - keys(collected_cells) - ), - # remove Pkg cells - (_ptoml_cell_id, _mtoml_cell_id) +_collect_cells(cells_dict::Dict{UUID,Cell}, cells_order::Vector{UUID}) = + map(i -> cells_dict[i], cells_order) +_initial_topology(cells_dict::Dict{UUID,Cell}, cells_order::Vector{UUID}) = + NotebookTopology(; + cell_order=ImmutableVector(_collect_cells(cells_dict, cells_order)), ) - appeared_cells_dict = filter(collected_cells) do (k, v) - k ∈ appeared_order - end - Notebook(cells_dict=appeared_cells_dict, cell_order=appeared_order, path=path, nbpkg_ctx=nbpkg_ctx, nbpkg_installed_versions_cache=nbpkg_cache(nbpkg_ctx)) -end - -function load_notebook_nobackup(path::String)::Notebook - local loaded - open(path, "r") do io - loaded = load_notebook_nobackup(io, path) - end - loaded +function Notebook(cells::Vector{Cell}, @nospecialize(path::AbstractString), notebook_id::UUID) + cells_dict=Dict(map(cells) do cell + (cell.cell_id, cell) + end) + cell_order=map(x -> x.cell_id, cells) + Notebook(; + cells_dict, + cell_order, + topology=_initial_topology(cells_dict, cell_order), + path, + notebook_id + ) end -"Create a backup of the given file, load the file as a .jl Pluto notebook, save the loaded notebook, compare the two files, and delete the backup of the newly saved file is equal to the backup." -function load_notebook(path::String; disable_writing_notebook_files::Bool=false)::Notebook - backup_path = backup_filename(path) - # local backup_num = 1 - # backup_path = path - # while isfile(backup_path) - # backup_path = path * ".backup" * string(backup_num) - # backup_num += 1 - # end - disable_writing_notebook_files || readwrite(path, backup_path) - - loaded = load_notebook_nobackup(path) - # Analyze cells so that the initial save is in topological order - loaded.topology = updated_topology(loaded.topology, loaded, loaded.cells) |> static_resolve_topology - update_dependency_cache!(loaded) - - disable_writing_notebook_files || save_notebook(loaded) - loaded.topology = NotebookTopology() +Notebook(cells::Vector{Cell}, path::AbstractString=numbered_until_new(joinpath(new_notebooks_directory(), cutename()))) = Notebook(cells, path, uuid1()) - disable_writing_notebook_files || if only_versions_or_lineorder_differ(path, backup_path) - rm(backup_path) +function Base.getproperty(notebook::Notebook, property::Symbol) + if property == :cells + _collect_cells(notebook.cells_dict, notebook.cell_order) + elseif property == :cell_inputs + notebook.cells_dict else - @warn "Old Pluto notebook might not have loaded correctly. Backup saved to: " backup_path + getfield(notebook, property) end - - loaded -end - -_after_first_cell(lines) = lines[something(findfirst(startswith(_cell_id_delimiter), lines), 1):end] - -""" -Check if two savefiles are identical, up to their version numbers and a possible line shuffle. - -If a notebook has not yet had all of its cells analysed, we can't deduce the topological cell order. (but can we ever??) (no) -""" -function only_versions_or_lineorder_differ(pathA::AbstractString, pathB::AbstractString)::Bool - Set(readlines(pathA) |> _after_first_cell) == Set(readlines(pathB) |> _after_first_cell) -end - -function only_versions_differ(pathA::AbstractString, pathB::AbstractString)::Bool - readlines(pathA) |> _after_first_cell == readlines(pathB) |> _after_first_cell end -"Set `notebook.path` to the new value, save the notebook, verify file integrity, and if all OK, delete the old savefile. Normalizes the given path to make it absolute. Moving is always hard. 😢" -function move_notebook!(notebook::Notebook, newpath::String; disable_writing_notebook_files::Bool=false) - # Will throw exception and return if anything goes wrong, so at least one file is guaranteed to exist. - oldpath_tame = tamepath(notebook.path) - newpath_tame = tamepath(newpath) - - if !disable_writing_notebook_files - save_notebook(notebook, oldpath_tame) - save_notebook(notebook, newpath_tame) - - # @assert that the new file looks alright - @assert only_versions_differ(oldpath_tame, newpath_tame) - notebook.path = newpath_tame - - if oldpath_tame != newpath_tame - rm(oldpath_tame) - end - else - notebook.path = newpath_tame - end - if isdir("$oldpath_tame.assets") - mv("$oldpath_tame.assets", "$newpath_tame.assets") - end - notebook -end +emptynotebook(args...) = Notebook([Cell()], args...) function sample_notebook(name::String) file = project_relative_path("sample", name * ".jl") @@ -366,3 +126,10 @@ function sample_notebook(name::String) nb.path = tempname() * ".jl" nb end + +create_cell_metadata(metadata::Dict{String,<:Any}) = merge(DEFAULT_CELL_METADATA, metadata) +create_notebook_metadata(metadata::Dict{String,<:Any}) = merge(DEFAULT_NOTEBOOK_METADATA, metadata) +get_metadata(cell::Cell)::Dict{String,Any} = cell.metadata +get_metadata(notebook::Notebook)::Dict{String,Any} = notebook.metadata +get_metadata_no_default(cell::Cell)::Dict{String,Any} = Dict{String,Any}(setdiff(pairs(cell.metadata), pairs(DEFAULT_CELL_METADATA))) +get_metadata_no_default(notebook::Notebook)::Dict{String,Any} = Dict{String,Any}(setdiff(pairs(notebook.metadata), pairs(DEFAULT_NOTEBOOK_METADATA))) diff --git a/src/notebook/frontmatter.jl b/src/notebook/frontmatter.jl new file mode 100644 index 0000000000..e93f03e257 --- /dev/null +++ b/src/notebook/frontmatter.jl @@ -0,0 +1,52 @@ + +const FrontMatter = Dict{String,Any} + +""" + frontmatter(nb::Notebook; raise::Bool=false)::Dict{String,Any} + frontmatter(nb_path::String; raise::Bool=false)::Dict{String,Any} + +Extract frontmatter from a notebook, which is extra meta-information that the author attaches to the notebook, often including *title*, *description*, *tags*, *author*, and more. Search for *frontmatter* online to learn more. + +If `raise` is true, then parsing errors will be rethrown. If `false`, this function will always return a `Dict`. +""" +function frontmatter(nb::Notebook; raise::Bool=false) + convert(FrontMatter, + get(() -> FrontMatter(), get_metadata(nb), "frontmatter") + ) +end + +function frontmatter(abs_path::String; raise::Bool=false) + try + # this will load the notebook to analyse, it won't run it + frontmatter(load_notebook_nobackup(abs_path); raise) + catch e + if raise + rethrow(e) + else + @error "Error reading notebook file." abs_path exception=(e,catch_backtrace()) + FrontMatter() + end + end +end + +""" +```julia +set_frontmatter!(nb::Notebook, new_value::Dict) +``` + +Set the new frontmatter of the [`Notebook`](@ref). Use [`frontmatter(nb)`](@ref) to get the old dictionary. + +If you want to save the file, call [`save_notebook(nb)`](@ref) afterwards. + +`set_frontmatter!(nb, nothing)` will delete the frontmatter. + +""" +function set_frontmatter!(nb::Notebook, ::Nothing) + delete!(nb.metadata, "frontmatter") +end + +function set_frontmatter!(nb::Notebook, new_value::Dict) + nb.metadata["frontmatter"] = convert(FrontMatter, new_value) +end + + diff --git a/src/notebook/PathHelpers.jl b/src/notebook/path helpers.jl similarity index 70% rename from src/notebook/PathHelpers.jl rename to src/notebook/path helpers.jl index aa52212c8e..9a3a387931 100644 --- a/src/notebook/PathHelpers.jl +++ b/src/notebook/path helpers.jl @@ -1,5 +1,44 @@ import Base64: base64decode +# from https://github.com/JuliaLang/julia/pull/36425 +function detectwsl() + Sys.islinux() && + isfile("/proc/sys/kernel/osrelease") && + occursin(r"Microsoft|WSL"i, read("/proc/sys/kernel/osrelease", String)) +end + +""" + maybe_convert_path_to_wsl(path) + +Return the WSL path if the system is using the Windows Subsystem for Linux (WSL) and return `path` otherwise. +WSL mounts the windows drive to /mnt/ and provides a utility tool to convert windows +paths into WSL paths. This function will try to use this tool to automagically +convert paths pasted from windows (with the right click -> copy as path functionality) +into paths Pluto can understand. + +Example: +$(raw"C:\Users\pankg\OneDrive\Desktop\pluto\bakery_pnl_ready2.jl") +→ +"/mnt/c/Users/pankg/OneDrive/Desktop/pluto/bakery_pnl_ready2.jl" + +but "/mnt/c/Users/pankg/OneDrive/Desktop/pluto/bakery_pnl_ready2.jl" stays the same + +""" +function maybe_convert_path_to_wsl(path) + try + isfile(path) && return path + if detectwsl() + # wslpath utility prints path to stderr if it fails to convert + # (it used to fail for WSL-valid paths) + !isnothing(match(r"^/mnt/\w+/", path)) && return path + return readchomp(pipeline(`wslpath -u $(path)`; stderr=devnull)) + end + catch e + return path + end + return path +end + const adjectives = [ "groundbreaking" "revolutionary" @@ -44,13 +83,20 @@ const nouns = [ "conjecture" ] +""" +Generate a filename like `"Cute discovery"`. Does not end with `.jl`. +""" function cutename() titlecase(rand(adjectives)) * " " * rand(nouns) end function new_notebooks_directory() try - path = joinpath(first(DEPOT_PATH), "pluto_notebooks") + path = get( + ENV, + "JULIA_PLUTO_NEW_NOTEBOOKS_DIR", + joinpath(first(DEPOT_PATH), "pluto_notebooks") + ) if !isdir(path) mkdir(path) end @@ -78,6 +124,9 @@ const pluto_file_extensions = [ endswith_pluto_file_extension(s) = any(endswith(s, e) for e in pluto_file_extensions) +""" +Extract the Julia notebook file contents from a Pluto-exported HTML file. +""" function embedded_notebookfile(html_contents::AbstractString)::String if !occursin("", html_contents) throw(ArgumentError("Pass the contents of a Pluto-exported HTML file as argument.")) diff --git a/src/notebook/saving and loading.jl b/src/notebook/saving and loading.jl new file mode 100644 index 0000000000..f0a44aaf35 --- /dev/null +++ b/src/notebook/saving and loading.jl @@ -0,0 +1,411 @@ + + +const _notebook_header = "### A Pluto.jl notebook ###" +const _notebook_metadata_prefix = "#> " +# We use a creative delimiter to avoid accidental use in code +# so don't get inspired to suddenly use these in your code! +const _cell_id_delimiter = "# ╔═╡ " +const _cell_metadata_prefix = "# ╠═╡ " +const _order_delimiter = "# ╠═" +const _order_delimiter_folded = "# ╟─" +const _cell_suffix = "\n\n" + +const _disabled_prefix = "#=╠═╡\n" +const _disabled_suffix = "\n ╠═╡ =#" + +const _ptoml_cell_id = UUID(1) +const _mtoml_cell_id = UUID(2) + + +### +# SAVING +### + + +""" +Save the notebook to `io`, `file` or to `notebook.path`. + +In the produced file, cells are not saved in the notebook order. If `notebook.topology` is up-to-date, I will save cells in _topological order_. This guarantees that you can run the notebook file outside of Pluto, with `julia my_notebook.jl`. + +Have a look at our [JuliaCon 2020 presentation](https://youtu.be/IAF8DjrQSSk?t=1085) to learn more! +""" +function save_notebook(io::IO, notebook::Notebook) + println(io, _notebook_header) + println(io, "# ", PLUTO_VERSION_STR) + + # Notebook metadata + let nb_metadata_toml = strip(sprint(TOML.print, get_metadata_no_default(notebook))) + if !isempty(nb_metadata_toml) + println(io) + for line in split(nb_metadata_toml, "\n") + println(io, _notebook_metadata_prefix, line) + end + end + end + + # Anything between the version string and the first UUID delimiter will be ignored by the notebook loader. + println(io, "") + println(io, "using Markdown") + println(io, "using InteractiveUtils") + # Super Advanced Code Analysis™ to add the @bind macro to the saved file if it's used somewhere. + if any(!must_be_commented_in_file(c) && occursin("@bind", c.code) for c in notebook.cells) + println(io, "") + println(io, "# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).") + println(io, PlutoRunner.fake_bind) + end + println(io) + + cells_ordered = collect(topological_order(notebook)) + + # NOTE: the notebook topological is cached on every update_dependency! call + # .... so it is possible that a cell was added/removed since this last update. + # .... in this case, it will not contain that cell since it is build from its + # .... store notebook topology. therefore, we compute an updated topological + # .... order in this unlikely case. + if length(cells_ordered) != length(notebook.cells_dict) + cells = notebook.cells + updated_topo = updated_topology(notebook.topology, notebook, cells) + cells_ordered = collect(topological_order(updated_topo, cells)) + end + + for c in cells_ordered + println(io, _cell_id_delimiter, string(c.cell_id)) + + let metadata_toml = strip(sprint(TOML.print, get_metadata_no_default(c))) + if metadata_toml != "" + for line in split(metadata_toml, "\n") + println(io, _cell_metadata_prefix, line) + end + end + end + + if must_be_commented_in_file(c) + print(io, _disabled_prefix) + print(io, replace(c.code, _cell_id_delimiter => "# ")) + print(io, _disabled_suffix) + print(io, _cell_suffix) + else + # write the cell code and prevent collisions with the cell delimiter + print(io, replace(c.code, _cell_id_delimiter => "# ")) + print(io, _cell_suffix) + end + end + + + using_plutopkg = notebook.nbpkg_ctx !== nothing + + write_package = if using_plutopkg + ptoml_contents = PkgCompat.read_project_file(notebook) + mtoml_contents = PkgCompat.read_manifest_file(notebook) + + !isempty(strip(ptoml_contents)) + else + false + end + + if write_package + println(io, _cell_id_delimiter, string(_ptoml_cell_id)) + print(io, "PLUTO_PROJECT_TOML_CONTENTS = \"\"\"\n") + write(io, ptoml_contents) + print(io, "\"\"\"") + print(io, _cell_suffix) + + println(io, _cell_id_delimiter, string(_mtoml_cell_id)) + print(io, "PLUTO_MANIFEST_TOML_CONTENTS = \"\"\"\n") + write(io, mtoml_contents) + print(io, "\"\"\"") + print(io, _cell_suffix) + end + + + println(io, _cell_id_delimiter, "Cell order:") + for c in notebook.cells + delim = c.code_folded ? _order_delimiter_folded : _order_delimiter + println(io, delim, string(c.cell_id)) + end + if write_package + println(io, _order_delimiter_folded, string(_ptoml_cell_id)) + println(io, _order_delimiter_folded, string(_mtoml_cell_id)) + end + + notebook +end + +# UTILS + +function write_buffered(fn::Function, path) + file_content = sprint(fn) + write(path, file_content) +end + +function save_notebook(notebook::Notebook, path::String) + # @warn "Saving to file!!" exception=(ErrorException(""), backtrace()) + notebook.last_save_time = time() + Status.report_business!(notebook.status_tree, :saving) do + write_buffered(path) do io + save_notebook(io, notebook) + end + end +end + +save_notebook(notebook::Notebook) = save_notebook(notebook, notebook.path) + + +### +# LOADING +### + +function _notebook_metadata!(@nospecialize(io::IO)) + firstline = String(readline(io))::String + + if firstline != _notebook_header + error("File is not a Pluto.jl notebook") + end + + file_VERSION_STR = readline(io)[3:end] + if file_VERSION_STR != PLUTO_VERSION_STR + # @info "Loading a notebook saved with Pluto $(file_VERSION_STR). This is Pluto $(PLUTO_VERSION_STR)." + end + + # Read all remaining file contents before the first cell delimiter. + header_content = readuntil(io, _cell_id_delimiter) + header_lines = split(header_content, "\n") + + nb_prefix_length = ncodeunits(_notebook_metadata_prefix) + nb_metadata_toml_lines = String[ + line[begin+nb_prefix_length:end] + for line in header_lines if startswith(line, _notebook_metadata_prefix) + ] + + notebook_metadata = try + create_notebook_metadata(TOML.parse(join(nb_metadata_toml_lines, "\n"))) + catch e + @error "Failed to parse embedded TOML content" exception=(e, catch_backtrace()) + DEFAULT_NOTEBOOK_METADATA + end + return notebook_metadata +end + +function _notebook_collected_cells!(@nospecialize(io::IO)) + collected_cells = Dict{UUID,Cell}() + while !eof(io) + cell_id_str = String(readline(io)) + if cell_id_str == "Cell order:" + break + else + cell_id = UUID(cell_id_str) + + metadata_toml_lines = String[] + initial_code_line = "" + while !eof(io) + line = String(readline(io)) + if startswith(line, _cell_metadata_prefix) + prefix_length = ncodeunits(_cell_metadata_prefix) + push!(metadata_toml_lines, line[begin+prefix_length:end]) + else + initial_code_line = line + break + end + end + + code_raw = initial_code_line * "\n" * String(readuntil(io, _cell_id_delimiter)) + # change Windows line endings to Linux + code_normalised = replace(code_raw, "\r\n" => "\n") + + # remove the disabled on startup comments for further processing in Julia + code_normalised = replace(replace(code_normalised, _disabled_prefix => ""), _disabled_suffix => "") + + # remove the cell suffix + code = code_normalised[1:prevind(code_normalised, end, length(_cell_suffix))] + + # parse metadata + metadata = try + create_cell_metadata(TOML.parse(join(metadata_toml_lines, "\n"))) + catch + @error "Failed to parse embedded TOML content" cell_id exception=(e, catch_backtrace()) + DEFAULT_CELL_METADATA + end + + read_cell = Cell(; cell_id, code, metadata) + collected_cells[cell_id] = read_cell + end + end + return collected_cells +end + +function _notebook_cell_order!(@nospecialize(io::IO), collected_cells) + cell_order = UUID[] + while !eof(io) + cell_id_str = String(readline(io)) + if length(cell_id_str) >= 36 && (startswith(cell_id_str, _order_delimiter_folded) || startswith(cell_id_str, _order_delimiter)) + cell_id = let + UUID(cell_id_str[end - 35:end]) + end + next_cell = get(collected_cells, cell_id, nothing) + if next_cell !== nothing + next_cell.code_folded = startswith(cell_id_str, _order_delimiter_folded) + end + push!(cell_order, cell_id) + else + break + end + end + return cell_order +end + +function _notebook_nbpkg_ctx(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell}) + read_package = + _ptoml_cell_id ∈ cell_order && + _mtoml_cell_id ∈ cell_order && + haskey(collected_cells, _ptoml_cell_id) && + haskey(collected_cells, _mtoml_cell_id) + + nbpkg_ctx = if read_package + ptoml_code = string(collected_cells[_ptoml_cell_id].code)::String + mtoml_code = string(collected_cells[_mtoml_cell_id].code)::String + + ptoml_contents = lstrip(split(ptoml_code, "\"\"\"")[2]) + mtoml_contents = lstrip(split(mtoml_code, "\"\"\"")[2]) + + env_dir = mktempdir() + write(joinpath(env_dir, "Project.toml"), ptoml_contents) + write(joinpath(env_dir, "Manifest.toml"), mtoml_contents) + + try + PkgCompat.load_ctx(env_dir) + catch e + @error "Failed to load notebook files: Project.toml+Manifest.toml parse error. Trying to recover Project.toml without Manifest.toml..." exception=(e,catch_backtrace()) + try + rm(joinpath(env_dir, "Manifest.toml")) + PkgCompat.load_ctx(env_dir) + catch e + @error "Failed to load notebook files: Project.toml parse error." exception=(e,catch_backtrace()) + PkgCompat.create_empty_ctx() + end + end + else + PkgCompat.create_empty_ctx() + end + return nbpkg_ctx +end + +function _notebook_appeared_order!(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell}) + setdiff!( + union!( + # don't include cells that only appear in the order, but no code was given + intersect!(cell_order, keys(collected_cells)), + # add cells that appeared in code, but not in the order. + keys(collected_cells) + ), + # remove Pkg cells + (_ptoml_cell_id, _mtoml_cell_id) + ) +end + +"Load a notebook without saving it or creating a backup; returns a `Notebook`. REMEMBER TO CHANGE THE NOTEBOOK PATH after loading it to prevent it from autosaving and overwriting the original file." +function load_notebook_nobackup(@nospecialize(io::IO), @nospecialize(path::AbstractString))::Notebook + notebook_metadata = _notebook_metadata!(io) + + collected_cells = _notebook_collected_cells!(io) + cell_order = _notebook_cell_order!(io, collected_cells) + nbpkg_ctx = _notebook_nbpkg_ctx(cell_order, collected_cells) + appeared_order = _notebook_appeared_order!(cell_order, collected_cells) + appeared_cells_dict = filter(collected_cells) do (k, v) + k ∈ appeared_order + end + + Notebook(; + cells_dict=appeared_cells_dict, + cell_order=appeared_order, + topology=_initial_topology(appeared_cells_dict, appeared_order), + path=path, + nbpkg_ctx=nbpkg_ctx, + nbpkg_installed_versions_cache=nbpkg_cache(nbpkg_ctx), + metadata=notebook_metadata, + ) +end + +# UTILS + +function load_notebook_nobackup(path::String)::Notebook + local loaded + open(path, "r") do io + loaded = load_notebook_nobackup(io, path) + end + loaded +end + +# BACKUPS + +"Create a backup of the given file, load the file as a .jl Pluto notebook, save the loaded notebook, compare the two files, and delete the backup of the newly saved file is equal to the backup." +function load_notebook(path::String; disable_writing_notebook_files::Bool=false)::Notebook + backup_path = backup_filename(path) + # local backup_num = 1 + # backup_path = path + # while isfile(backup_path) + # backup_path = path * ".backup" * string(backup_num) + # backup_num += 1 + # end + disable_writing_notebook_files || readwrite(path, backup_path) + + loaded = load_notebook_nobackup(path) + # Analyze cells so that the initial save is in topological order + loaded.topology = updated_topology(loaded.topology, loaded, loaded.cells) |> static_resolve_topology + # We update cell dependency on skip_as_script and disabled to avoid removing block comments on the file. See https://github.com/fonsp/Pluto.jl/issues/2182 + update_disabled_cells_dependency!(loaded) + update_skipped_cells_dependency!(loaded) + update_dependency_cache!(loaded) + + disable_writing_notebook_files || save_notebook(loaded) + loaded.topology = NotebookTopology(; cell_order=ImmutableVector(loaded.cells)) + + disable_writing_notebook_files || if only_versions_or_lineorder_differ(path, backup_path) + rm(backup_path) + else + @warn "Old Pluto notebook might not have loaded correctly. Backup saved to: " backup_path + end + + loaded +end + +_after_first_cell(lines) = lines[something(findfirst(startswith(_cell_id_delimiter), lines), 1):end] + +""" +Check if two savefiles are identical, up to their version numbers and a possible line shuffle. + +If a notebook has not yet had all of its cells analysed, we can't deduce the topological cell order. (but can we ever??) (no) +""" +function only_versions_or_lineorder_differ(pathA::AbstractString, pathB::AbstractString)::Bool + Set(readlines(pathA) |> _after_first_cell) == Set(readlines(pathB) |> _after_first_cell) +end + +function only_versions_differ(pathA::AbstractString, pathB::AbstractString)::Bool + readlines(pathA) |> _after_first_cell == readlines(pathB) |> _after_first_cell +end + +"Set `notebook.path` to the new value, save the notebook, verify file integrity, and if all OK, delete the old savefile. Normalizes the given path to make it absolute. Moving is always hard. 😢" +function move_notebook!(notebook::Notebook, newpath::String; disable_writing_notebook_files::Bool=false) + # Will throw exception and return if anything goes wrong, so at least one file is guaranteed to exist. + oldpath_tame = tamepath(notebook.path) + newpath_tame = tamepath(newpath) + + if !disable_writing_notebook_files + save_notebook(notebook, oldpath_tame) + save_notebook(notebook, newpath_tame) + + # @assert that the new file looks alright + @assert only_versions_differ(oldpath_tame, newpath_tame) + + notebook.path = newpath_tame + + if oldpath_tame != newpath_tame + rm(oldpath_tame) + end + else + notebook.path = newpath_tame + end + if isdir("$oldpath_tame.assets") + mv("$oldpath_tame.assets", "$newpath_tame.assets") + end + notebook +end diff --git a/src/packages/ANSIEmulation.jl b/src/packages/ANSIEmulation.jl new file mode 100644 index 0000000000..25ae199295 --- /dev/null +++ b/src/packages/ANSIEmulation.jl @@ -0,0 +1,577 @@ +### A Pluto.jl notebook ### +# v0.19.24 + +using Markdown +using InteractiveUtils + +# ╔═╡ 6f1cb799-21b7-459a-a7c5-6c42b1376b11 +# ╠═╡ skip_as_script = true +#=╠═╡ +using BenchmarkTools: @benchmark + ╠═╡ =# + +# ╔═╡ 98ac036d-1a37-457c-b89d-8e954ab6f039 +# ╠═╡ skip_as_script = true +#=╠═╡ +using PlutoUI: Slider + ╠═╡ =# + +# ╔═╡ e665ae4e-bf4e-11ed-330a-f3670dd00a95 +# ╠═╡ skip_as_script = true +#=╠═╡ +str = read(download("https://raw.githubusercontent.com/fonsp/disorganised-mess/main/ansidemo.txt"), String) + ╠═╡ =# + +# ╔═╡ 032a10cc-8b2b-4e85-bac4-b9623b91d016 +# ╠═╡ disabled = true +# ╠═╡ skip_as_script = true +#=╠═╡ +str = "\nInstantiating...\n\e[32m\e[1m No Changes\e[22m\e[39m to `/private/var/folders/v_/fhpj9jn151d4p9c2fdw2gv780000gn/T/jl_DivOhV/Project.toml`\n\e[32m\e[1m No Changes\e[22m\e[39m to `/private/var/folders/v_/fhpj9jn151d4p9c2fdw2gv780000gn/T/jl_DivOhV/Manifest.toml`\n\e[?25l\e[?25h\e[2K\nResolving...\n\e[32m\e[1m No Changes\e[22m\e[39m to `/private/var/folders/v_/fhpj9jn151d4p9c2fdw2gv780000gn/T/jl_DivOhV/Project.toml`\n\e[32m\e[1m No Changes\e[22m\e[39m to `/private/var/folders/v_/fhpj9jn151d4p9c2fdw2gv780000gn/T/jl_DivOhV/Manifest.toml`\n\e[?25l\e[?25h\e[2K" + ╠═╡ =# + +# ╔═╡ 209f221c-be89-4976-b712-2b9214c3291c +#=╠═╡ +Text(str) + ╠═╡ =# + +# ╔═╡ dff16b61-7fa6-4702-95a6-a0d2913c3070 +#=╠═╡ +collect(str) + ╠═╡ =# + +# ╔═╡ b6fe176d-cfbe-4aac-ad46-3345b0acbb74 +#=╠═╡ +length(str) + ╠═╡ =# + +# ╔═╡ c952da01-ba67-4a49-99df-c61939ba81be +# ESC[H moves cursor to home position (0, 0) +# ESC[{line};{column}H +# ESC[{line};{column}f moves cursor to line #, column # +# ESC[#A moves cursor up # lines +# ESC[#B moves cursor down # lines +# ESC[#C moves cursor right # columns +# ESC[#D moves cursor left # columns +# ESC[#E moves cursor to beginning of next line, # lines down +# ESC[#F moves cursor to beginning of previous line, # lines up +# ESC[#G moves cursor to column # +# ESC[6n request cursor position (reports as ESC[#;#R) +# ESC M moves cursor one line up, scrolling if needed +# ESC 7 save cursor position (DEC) +# ESC 8 restores the cursor to the last saved position (DEC) +# ESC[s save cursor position (SCO) +# ESC[u restores the cursor to the last saved position (SCO) + +# ╔═╡ f661240f-4950-4be0-a2b2-98ed77f6e4a2 +const stoppers = ('H', 'f', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'n', 's', 'u', 'J', 'K', 'm', 'l', 'h', 'S') + +# ╔═╡ af48f80f-345d-4d90-9cf1-b8be9004a53d +Base.@kwdef mutable struct ANSITerminalState + lines::Dict{Int,Vector{Char}}=Dict{Int,Vector{Char}}() + col::Int=1 + row::Int=1 +end + +# ╔═╡ f54f7282-87fd-4f05-8f8a-220d83186e9a +getline(state::ANSITerminalState) = get!(state.lines, state.row) do + Char[] +end + +# ╔═╡ 0a4587f7-55b2-4621-89e8-a9492d32bc09 +#=╠═╡ +@benchmark ncodeunits(str) + ╠═╡ =# + +# ╔═╡ 84a457d4-1e3c-4797-aa94-a7ca9ce628e4 +""" +Update the `ANSITerminalState` with new data from a TTY stream. +""" +function consume!(state::ANSITerminalState, str::AbstractString) + ind = 0 + + L = ncodeunits(str) + + while ind < L + ind = nextind(str, ind) + if ind > L + break + end + + c = str[ind] + if c === '\n' + state.col = 1 + state.row += 1 + + elseif c === '\r' + state.col = 1 + + elseif c === '\e' + # ANSI control character + # see https://en.wikipedia.org/wiki/ANSI_escape_code for descriptions of these. + + ind += 1 + # ignoring this character, it should be a '[' + + "will contain the characters between ] and the stopper character" + buffer_vec = Char[] + + # keep reading until we have the stopper character + local stopper = '\0' + while ind <= L - 1 + ind += 1 + next_c = str[ind] + if next_c ∈ stoppers + stopper = next_c + break + end + push!(buffer_vec, next_c) + end + + + # @info "Escape sequence read" stopper buffer + + + if stopper === 'l' || stopper === 'h' + # ignored + elseif stopper === '\0' + # this means that no stop was found, ignoring... + + elseif stopper === 'K'# && buffer == "2" + # @assert buffer_vec == ['2'] + + line = getline(state) + line .= ' ' + elseif stopper === 'A' + state.row = max(1, state.row - parse(Int, String(buffer_vec))) + + elseif stopper === 'G' + state.col = parse(Int, String(buffer_vec)) + + elseif stopper === 'J'# && buffer == "0" + # @assert buffer_vec == ['0'] + + # clear the remainder of this line + resize!(getline(state), state.col - 1) + # and clear all rows below + for row in state.row+1 : maximum(keys(state.lines)) + delete!(state.lines, row) + end + + elseif stopper === 'm' + # keep it in the output because we use ansiup to handle colors in the frontend + line = getline(state) + push!(line, '\e', '[') + append!(line, buffer_vec) + push!(line, stopper) + + state.col += 3 + length(buffer_vec) + + elseif stopper === 'S' + diff = isempty(buffer_vec) ? 1 : parse(Int, String(buffer_vec)) + state.row += diff + + else + @warn "Unrecogized escape sequence" stopper String(buffer_vec) + end + + else + # no escape character, just a regular char + line = getline(state) + + while length(line) < state.col + push!(line, ' ') + end + line[state.col] = c + state.col += 1 + end + end +end + +# ╔═╡ 2c02ca66-e3fe-479a-b3f1-13ea0850f3d7 +function consume_safe!(state::ANSITerminalState, str::AbstractString) + try + consume!(state, str) + catch e + @debug "ANSI escape sequence glitch" exception=(e,catch_backtrace()) + line = getline(state) + append!(line, codeunits(str)) + state.row += ncodeunits(str) + end +end + +# ╔═╡ 6a8f71f5-7113-4074-8009-14eea11cc958 +#=╠═╡ +@bind L Slider(1:length(str)) + ╠═╡ =# + +# ╔═╡ f9232436-618c-401f-9d18-f9f8f1f04a77 +function build_str(state::ANSITerminalState) + d = state.lines + join( + (String(get(() -> Char[], d, i)) for i in 1:maximum(keys(d))), "\n" + ) +end + +# ╔═╡ a1ebfaf3-dadb-40dc-95c5-ae8a9d6de1ec +# ╠═╡ skip_as_script = true +#=╠═╡ +function solve(str::AbstractString) + state = ANSITerminalState() + consume_safe!(state, str) + build_str(state) +end + ╠═╡ =# + +# ╔═╡ 6dc56641-7d0d-4bd7-a1ef-22e373908207 +#=╠═╡ +@benchmark solve($str) seconds=1 + ╠═╡ =# + +# ╔═╡ 48c686f9-722f-4d84-ac9d-9b11c934370c +#=╠═╡ +solve(str) |> Text + ╠═╡ =# + +# ╔═╡ ee9a24d4-7a9f-4024-8100-f7ce4ef436cb +#=╠═╡ +collect(str) => collect(solve(str)) + ╠═╡ =# + +# ╔═╡ 2453d8e0-ca26-4033-a272-c5c51fc8d16d +#=╠═╡ +solve(SubString(str, 1, nextind(str, 0, L))) |> Text + ╠═╡ =# + +# ╔═╡ 535f471d-a049-4d74-aa52-9be86e2d4352 +#=╠═╡ +let + + state = ANSITerminalState() + + mid = nextind(str, 0, L ÷ 2) + top = nextind(str, 0, L) + + consume!(state, SubString(str, 1, mid)) + consume!(state, SubString(str, nextind(str, mid), top)) + + build_str(state) |> Text +end + ╠═╡ =# + +# ╔═╡ 195a8e3c-427f-487f-9c7c-d31ce374de81 +# ╠═╡ skip_as_script = true +#=╠═╡ +ANSITerminalState( + lines=Dict(3 => Char['a', 't'], 1 => ['c']) +) |> build_str |> Text + ╠═╡ =# + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" + +[compat] +BenchmarkTools = "~1.3.2" +PlutoUI = "~0.7.50" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.9.0-rc2" +manifest_format = "2.0" +project_hash = "ce886088241d89ce6a9168ebf44701e0c6f4421f" + +[[deps.AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.1.4" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BenchmarkTools]] +deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "d9a9701b899b30332bbcb3e1679c41cce81fb0e8" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.3.2" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.4" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.0.2+0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[deps.Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.4" + +[[deps.HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.4" + +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.2" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.3" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.84.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.10.2+0" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.MIMEs]] +git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" +uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +version = "0.1.4" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+0" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2022.10.11" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.21+4" + +[[deps.Parsers]] +deps = ["Dates", "SnoopPrecompile"] +git-tree-sha1 = "478ac6c952fddd4399e71d4779797c538d0ff2bf" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.5.8" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.9.0" + +[[deps.PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] +git-tree-sha1 = "5bb5129fdd62a2bbbe17c2756932259acf467386" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.50" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.3.0" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SnoopPrecompile]] +deps = ["Preferences"] +git-tree-sha1 = "e760a70afdcd461cf01a575947738d359234665c" +uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" +version = "1.0.3" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.9.0" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "5.10.1+6" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.Tricks]] +git-tree-sha1 = "6bac775f2d42a611cdfcd1fb217ee719630c4175" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.6" + +[[deps.URIs]] +git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.4.2" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.4.0+0" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.48.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+0" +""" + +# ╔═╡ Cell order: +# ╠═e665ae4e-bf4e-11ed-330a-f3670dd00a95 +# ╠═032a10cc-8b2b-4e85-bac4-b9623b91d016 +# ╠═209f221c-be89-4976-b712-2b9214c3291c +# ╠═dff16b61-7fa6-4702-95a6-a0d2913c3070 +# ╠═b6fe176d-cfbe-4aac-ad46-3345b0acbb74 +# ╠═c952da01-ba67-4a49-99df-c61939ba81be +# ╠═f661240f-4950-4be0-a2b2-98ed77f6e4a2 +# ╠═af48f80f-345d-4d90-9cf1-b8be9004a53d +# ╠═f54f7282-87fd-4f05-8f8a-220d83186e9a +# ╠═0a4587f7-55b2-4621-89e8-a9492d32bc09 +# ╠═2c02ca66-e3fe-479a-b3f1-13ea0850f3d7 +# ╠═84a457d4-1e3c-4797-aa94-a7ca9ce628e4 +# ╠═a1ebfaf3-dadb-40dc-95c5-ae8a9d6de1ec +# ╠═6dc56641-7d0d-4bd7-a1ef-22e373908207 +# ╠═6f1cb799-21b7-459a-a7c5-6c42b1376b11 +# ╠═48c686f9-722f-4d84-ac9d-9b11c934370c +# ╠═ee9a24d4-7a9f-4024-8100-f7ce4ef436cb +# ╠═2453d8e0-ca26-4033-a272-c5c51fc8d16d +# ╠═535f471d-a049-4d74-aa52-9be86e2d4352 +# ╠═98ac036d-1a37-457c-b89d-8e954ab6f039 +# ╠═6a8f71f5-7113-4074-8009-14eea11cc958 +# ╠═f9232436-618c-401f-9d18-f9f8f1f04a77 +# ╠═195a8e3c-427f-487f-9c7c-d31ce374de81 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/src/packages/IOListener.jl b/src/packages/IOListener.jl new file mode 100644 index 0000000000..f1dab23982 --- /dev/null +++ b/src/packages/IOListener.jl @@ -0,0 +1,49 @@ + +module ANSIEmulation include("./ANSIEmulation.jl") end + + +"A polling system to watch for writes to an IOBuffer. Up-to-date content will be passed as string to the `callback` function." +Base.@kwdef struct IOListener + callback::Function + interval::Real=1.0/60 + running::Ref{Bool}=Ref(false) + + buffer::IOBuffer=IOBuffer() + last_size::Ref{Int}=Ref(0) + ansi_state::ANSIEmulation.ANSITerminalState=ANSIEmulation.ANSITerminalState() +end + +function trigger(listener::IOListener) + old_size = listener.last_size[] + new_size = listener.buffer.size + if new_size > old_size + # @debug "making string" + s = String(@view listener.buffer.data[old_size+1:new_size]) + # @debug "making ansi" + ANSIEmulation.consume_safe!( + listener.ansi_state, + s + ) + # @debug "building string" s listener.ansi_state + new_contents = ANSIEmulation.build_str(listener.ansi_state) + + listener.last_size[] = new_size + listener.callback(new_contents) + end +end + +function startlistening(listener::IOListener) + if !listener.running[] + listener.running[] = true + @async while listener.running[] + trigger(listener) + sleep(listener.interval) + end + end +end +function stoplistening(listener::IOListener) + if listener.running[] + listener.running[] = false + trigger(listener) + end +end diff --git a/src/packages/Packages.jl b/src/packages/Packages.jl index 60735abd26..37a3437438 100644 --- a/src/packages/Packages.jl +++ b/src/packages/Packages.jl @@ -2,6 +2,9 @@ import .ExpressionExplorer: external_package_names import .PkgCompat import .PkgCompat: select, is_stdlib +import Logging +import LoggingExtras +import .Configuration: CompilerOptions, _merge_notebook_compiler_options, _convert_to_flags const tiers = [ Pkg.PRESERVE_ALL, @@ -12,6 +15,8 @@ const tiers = [ const pkg_token = Token() +_default_cleanup() = nothing + # This list appears multiple times in our codebase. Be sure to match edits everywhere. function use_plutopkg(topology::NotebookTopology) !any(values(topology.nodes)) do node @@ -49,21 +54,32 @@ Update the notebook package environment to match the notebook's code. This will: - Make sure that the environment is instantiated. - Detect the use of `Pkg.activate` and enable/disabled nbpkg accordingly. """ -function sync_nbpkg_core(notebook::Notebook; on_terminal_output::Function=((args...) -> nothing)) +function sync_nbpkg_core( + notebook::Notebook, + old_topology::NotebookTopology, + new_topology::NotebookTopology; + on_terminal_output::Function=((args...) -> nothing), + cleanup::Ref{Function}=Ref{Function}(_default_cleanup), + lag::Real=0, + compiler_options::CompilerOptions=CompilerOptions(), +) + pkg_status = Status.report_business_started!(notebook.status_tree, :pkg) + Status.report_business_started!(pkg_status, :analysis) 👺 = false use_plutopkg_old = notebook.nbpkg_ctx !== nothing - use_plutopkg_new = use_plutopkg(notebook.topology) + use_plutopkg_new = use_plutopkg(new_topology) if !use_plutopkg_old && use_plutopkg_new - @debug "Started using PlutoPkg!! HELLO reproducibility!" + @debug "PlutoPkg: Started using PlutoPkg!! HELLO reproducibility!" notebook.path 👺 = true notebook.nbpkg_ctx = PkgCompat.create_empty_ctx() + notebook.nbpkg_install_time_ns = 0 end if use_plutopkg_old && !use_plutopkg_new - @debug "Stopped using PlutoPkg 💔😟😢" + @debug "PlutoPkg: Stopped using PlutoPkg 💔😟😢" notebook.path no_packages_loaded_yet = ( notebook.nbpkg_restart_required_msg === nothing && @@ -72,86 +88,146 @@ function sync_nbpkg_core(notebook::Notebook; on_terminal_output::Function=((args ) 👺 = !no_packages_loaded_yet notebook.nbpkg_ctx = nothing + notebook.nbpkg_install_time_ns = nothing + end + if !use_plutopkg_new + notebook.nbpkg_install_time_ns = nothing + notebook.nbpkg_ctx_instantiated = true end + (lag > 0) && sleep(lag * (0.5 + rand())) # sleep(0) would yield to the process manager which we dont want - if notebook.nbpkg_ctx !== nothing + if use_plutopkg_new + @assert notebook.nbpkg_ctx !== nothing + PkgCompat.mark_original!(notebook.nbpkg_ctx) old_packages = String.(keys(PkgCompat.project(notebook.nbpkg_ctx).dependencies)) - new_packages = String.(external_package_names(notebook.topology)) # search all cells for imports and usings + new_packages = String.(external_package_names(new_topology)) # search all cells for imports and usings removed = setdiff(old_packages, new_packages) added = setdiff(new_packages, old_packages) + can_skip = isempty(removed) && isempty(added) && notebook.nbpkg_ctx_instantiated iolistener = let busy_packages = notebook.nbpkg_ctx_instantiated ? added : new_packages - IOListener(callback=(s -> on_terminal_output(busy_packages, s))) + report_to = ["nbpkg_sync", busy_packages...] + IOListener(callback=(s -> on_terminal_output(report_to, s))) end + cleanup[] = () -> stoplistening(iolistener) + + + + Status.report_business_finished!(pkg_status, :analysis) # We remember which Pkg.Types.PreserveLevel was used. If it's too low, we will recommend/require a notebook restart later. local used_tier = Pkg.PRESERVE_ALL - - if !isready(pkg_token) - println(iolistener.buffer, "Waiting for other notebooks to finish Pkg operations...") - trigger(iolistener) - end - - can_skip = isempty(removed) && isempty(added) && notebook.nbpkg_ctx_instantiated - if !can_skip + # We have a global lock, `pkg_token`, on Pluto-managed Pkg operations, which is shared between all notebooks. If this lock is not ready right now then that means that we are going to wait at the `withtoken(pkg_token)` line below. + # We want to report that we are waiting, with a best guess of why. + wait_business = if !isready(pkg_token) + reg = !PkgCompat._updated_registries_compat[] + + # Print something in the terminal logs + println(iolistener.buffer, "Waiting for $(reg ? "the package registry to update" : "other notebooks to finish Pkg operations")...") + trigger(iolistener) # manual trigger because we did not start listening yet + + # Create a business item + Status.report_business_started!(pkg_status, + reg ? :registry_update : :waiting_for_others + ) + end + return withtoken(pkg_token) do - PkgCompat.refresh_registry_cache() + withlogcapture(iolistener) do - if !notebook.nbpkg_ctx_instantiated - notebook.nbpkg_ctx = PkgCompat.clear_stdlib_compat_entries(notebook.nbpkg_ctx) - PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true)) do - withinteractive(false) do - try - Pkg.resolve(notebook.nbpkg_ctx) - catch e - @warn "Failed to resolve Pkg environment. Removing Manifest and trying again..." exception=e - reset_nbpkg(notebook; keep_project=true, save=false, backup=false) - Pkg.resolve(notebook.nbpkg_ctx) + let # Status stuff + isnothing(wait_business) || Status.report_business_finished!(wait_business) + + if !notebook.nbpkg_ctx_instantiated + Status.report_business_planned!(pkg_status, :instantiate1) + Status.report_business_planned!(pkg_status, :resolve) + Status.report_business_planned!(pkg_status, :precompile) + end + + isempty(removed) || Status.report_business_planned!(pkg_status, :remove) + isempty(added) || Status.report_business_planned!(pkg_status, :add) + if !isempty(added) || !isempty(removed) + Status.report_business_planned!(pkg_status, :instantiate2) + Status.report_business_planned!(pkg_status, :precompile) + end + end + + should_precompile_later = false + + PkgCompat.refresh_registry_cache() + PkgCompat.clear_stdlib_compat_entries!(notebook.nbpkg_ctx) + + + should_instantiate_initially = !notebook.nbpkg_ctx_instantiated + if should_instantiate_initially + + should_precompile_later = true + + # First, we instantiate. This will: + # - Verify that the Manifest can be parsed and is in the correct format (important for compat across Julia versions). If not, we will fix it by deleting the Manifest. + # - If no Manifest exists, resolve the environment and create one. + # - Start downloading all registered packages, artifacts. + # - Start downloading all unregistered packages, which are added through a URL. This also makes the Project.tomls of those packages available. + # - Precompile all packages. + Status.report_business!(pkg_status, :instantiate1) do + with_auto_fixes(notebook) do + _instantiate(notebook, iolistener) + end + end + + # Second, we resolve. This will: + # - Verify that the Manifest contains a correct dependency tree (e.g. all versions exists in a registry). If not, we will fix it using `with_auto_fixes` + # - If we are tracking local packages by path (] dev), their Project.tomls are reparsed and everything is updated. + Status.report_business!(pkg_status, :resolve) do + with_auto_fixes(notebook) do + _resolve(notebook, iolistener) end end end - end - - to_remove = filter(removed) do p - haskey(PkgCompat.project(notebook.nbpkg_ctx).dependencies, p) - end - if !isempty(to_remove) - @debug to_remove - # See later comment - mkeys() = Set(filter(!is_stdlib, [m.name for m in values(PkgCompat.dependencies(notebook.nbpkg_ctx))])) - old_manifest_keys = mkeys() - - Pkg.rm(notebook.nbpkg_ctx, [ - Pkg.PackageSpec(name=p) - for p in to_remove - ]) - - # We record the manifest before and after, to prevent recommending a reboot when nothing got removed from the manifest (e.g. when removing GR, but leaving Plots), or when only stdlibs got removed. - new_manifest_keys = mkeys() - # TODO: we might want to upgrade other packages now that constraints have loosened? Does this happen automatically? - end - - - # TODO: instead of Pkg.PRESERVE_ALL, we actually want: - # "Pkg.PRESERVE_DIRECT, but preserve exact verisons of Base.loaded_modules" - - to_add = filter(PkgCompat.package_exists, added) - - if !isempty(to_add) - @debug to_add - startlistening(iolistener) + to_add = filter(PkgCompat.package_exists, added) + to_remove = filter(removed) do p + haskey(PkgCompat.project(notebook.nbpkg_ctx).dependencies, p) + end + @debug "PlutoPkg:" notebook.path to_add to_remove + + if !isempty(to_remove) + Status.report_business_started!(pkg_status, :remove) + # See later comment + mkeys() = Set(filter(!is_stdlib, [m.name for m in values(PkgCompat.dependencies(notebook.nbpkg_ctx))])) + old_manifest_keys = mkeys() + + Pkg.rm(notebook.nbpkg_ctx, [ + Pkg.PackageSpec(name=p) + for p in to_remove + ]) + + notebook.nbpkg_install_time_ns = nothing # we lose our estimate of install time + # We record the manifest before and after, to prevent recommending a reboot when nothing got removed from the manifest (e.g. when removing GR, but leaving Plots), or when only stdlibs got removed. + new_manifest_keys = mkeys() + + # TODO: we might want to upgrade other packages now that constraints have loosened? Does this happen automatically? + Status.report_business_finished!(pkg_status, :remove) + end - PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true)) do - withinteractive(false) do + + # TODO: instead of Pkg.PRESERVE_ALL, we actually want: + # "Pkg.PRESERVE_DIRECT, but preserve exact verisons of Base.loaded_modules" + + if !isempty(to_add) + Status.report_business_started!(pkg_status, :add) + start_time = time_ns() + with_io_setup(notebook, iolistener) do + println(iolistener.buffer, "\nAdding packages...") + # We temporarily clear the "semver-compatible" [deps] entries, because Pkg already respects semver, unless it doesn't, in which case we don't want to force it. - notebook.nbpkg_ctx = PkgCompat.clear_auto_compat_entries(notebook.nbpkg_ctx) + PkgCompat.clear_auto_compat_entries!(notebook.nbpkg_ctx) try for tier in [ @@ -167,7 +243,7 @@ function sync_nbpkg_core(notebook::Notebook; on_terminal_output::Function=((args Pkg.PackageSpec(name=p) for p in to_add ]; preserve=used_tier) - + break catch e if used_tier == Pkg.PRESERVE_NONE @@ -177,58 +253,56 @@ function sync_nbpkg_core(notebook::Notebook; on_terminal_output::Function=((args end end finally - notebook.nbpkg_ctx = PkgCompat.write_auto_compat_entries(notebook.nbpkg_ctx) + PkgCompat.write_auto_compat_entries!(notebook.nbpkg_ctx) end # Now that Pkg is set up, the notebook process will call `using Package`, which can take some time. We write this message to the io, to notify the user. println(iolistener.buffer, "\e[32m\e[1mLoading\e[22m\e[39m packages...") end + + notebook.nbpkg_install_time_ns = notebook.nbpkg_install_time_ns === nothing ? nothing : (notebook.nbpkg_install_time_ns + (time_ns() - start_time)) + Status.report_business_finished!(pkg_status, :add) + @debug "PlutoPkg: done" notebook.path end - @debug "PlutoPkg done" - end - - should_instantiate = !notebook.nbpkg_ctx_instantiated || !isempty(to_add) || !isempty(to_remove) - if should_instantiate - startlistening(iolistener) - PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true)) do - @debug "Instantiating" - - # Pkg.instantiate assumes that the environment to be instantiated is active, so we will have to modify the LOAD_PATH of this Pluto server - # We could also run the Pkg calls on the notebook process, but somehow I think that doing it on the server is more charming, though it requires this workaround. - env_dir = PkgCompat.env_dir(notebook.nbpkg_ctx) - pushfirst!(LOAD_PATH, env_dir) - - # update registries if this is the first time - PkgCompat.update_registries(notebook.nbpkg_ctx) - # instantiate without forcing registry update - PkgCompat.instantiate(notebook.nbpkg_ctx; update_registry=false) - - @assert LOAD_PATH[1] == env_dir - popfirst!(LOAD_PATH) + should_instantiate_again = !notebook.nbpkg_ctx_instantiated || !isempty(to_add) || !isempty(to_remove) + + if should_instantiate_again + should_precompile_later = true + Status.report_business!(pkg_status, :instantiate2) do + _instantiate(notebook, iolistener) + end + end + + if should_precompile_later + Status.report_business!(pkg_status, :precompile) do + _precompile(notebook, iolistener, compiler_options) + end end - notebook.nbpkg_ctx_instantiated = true - end - - stoplistening(iolistener) - return ( - did_something=👺 || ( - should_instantiate || (use_plutopkg_old != use_plutopkg_new) - ), - used_tier=used_tier, - # changed_versions=Dict{String,Pair}(), - restart_recommended=👺 || ( - (!isempty(to_remove) && old_manifest_keys != new_manifest_keys) || - used_tier != Pkg.PRESERVE_ALL - ), - restart_required=👺 || ( - used_tier ∈ [Pkg.PRESERVE_SEMVER, Pkg.PRESERVE_NONE] - ), - ) + stoplistening(iolistener) + Status.report_business_finished!(pkg_status) + + return ( + did_something=👺 || ( + should_instantiate_initially || should_instantiate_again || (use_plutopkg_old != use_plutopkg_new) + ), + used_tier=used_tier, + # changed_versions=Dict{String,Pair}(), + restart_recommended=👺 || ( + (!isempty(to_remove) && old_manifest_keys != new_manifest_keys) || + used_tier != Pkg.PRESERVE_ALL + ), + restart_required=👺 || ( + used_tier ∈ [Pkg.PRESERVE_SEMVER, Pkg.PRESERVE_NONE] + ), + ) + end end end end + Status.report_business_finished!(pkg_status) + return ( did_something=👺 || (use_plutopkg_old != use_plutopkg_new), used_tier=Pkg.PRESERVE_ALL, @@ -248,46 +322,67 @@ In addition to the steps performed by [`sync_nbpkg_core`](@ref): - Update the clients connected to `notebook` - `try` `catch` and reset the package environment on failure. """ -function sync_nbpkg(session, notebook; save::Bool=true) +function sync_nbpkg(session, notebook, old_topology::NotebookTopology, new_topology::NotebookTopology; save::Bool=true, take_token::Bool=true) + @assert will_run_pkg(notebook) + + cleanup = Ref{Function}(_default_cleanup) try - pkg_result = withtoken(notebook.executetoken) do + Status.report_business_started!(notebook.status_tree, :pkg) + + pkg_result = (take_token ? withtoken : (f, _) -> f())(notebook.executetoken) do function iocallback(pkgs, s) notebook.nbpkg_busy_packages = pkgs for p in pkgs notebook.nbpkg_terminal_outputs[p] = s end + # incoming IO is a good sign that something might have changed, so we update the cache. update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + + # This is throttled "automatically": + # If io is coming in very fast, then it won't build up a queue of updates for the client. That's because `send_notebook_changes!` is a blocking call, including the websocket transfer. So this `iocallback` function will only return when the last message has been sent. + # The nice thing is that IOCallback is not actually implemented as a callback when IO comes in, but it is an async loop that sleeps, maybe calls iocallback with the latest buffer content, and repeats. So a blocking iocallback avoids overflowing the queue. + send_notebook_changes!(ClientRequest(; session, notebook)) end - sync_nbpkg_core(notebook; on_terminal_output=iocallback) + sync_nbpkg_core( + notebook, + old_topology, + new_topology; + on_terminal_output=iocallback, + cleanup, + lag=session.options.server.simulated_pkg_lag, + compiler_options=_merge_notebook_compiler_options(notebook, session.options.compiler), + ) end if pkg_result.did_something - @debug "PlutoPkg: success!" pkg_result - - if pkg_result.restart_recommended - @debug "PlutoPkg: Notebook restart recommended" - notebook.nbpkg_restart_recommended_msg = "Yes, something changed during regular sync." - end - if pkg_result.restart_required - @debug "PlutoPkg: Notebook restart REQUIRED" - notebook.nbpkg_restart_required_msg = "Yes, something changed during regular sync." - end + @debug "PlutoPkg: success!" notebook.path pkg_result + + if _has_executed_effectful_code(session, notebook) + if pkg_result.restart_recommended + notebook.nbpkg_restart_recommended_msg = "Yes, something changed during regular sync." + @debug "PlutoPkg: Notebook restart recommended" notebook.path notebook.nbpkg_restart_recommended_msg + end + if pkg_result.restart_required + notebook.nbpkg_restart_required_msg = "Yes, something changed during regular sync." + @debug "PlutoPkg: Notebook restart REQUIRED" notebook.path notebook.nbpkg_restart_required_msg + end + end notebook.nbpkg_busy_packages = String[] update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) save && save_notebook(session, notebook) end catch e bt = catch_backtrace() old_packages = try String.(keys(PkgCompat.project(notebook.nbpkg_ctx).dependencies)); catch; ["unknown"] end - new_packages = try String.(external_package_names(notebook.topology)); catch; ["unknown"] end + new_packages = try String.(external_package_names(new_topology)); catch; ["unknown"] end @warn """ PlutoPkg: Failed to add/remove packages! Resetting package environment... """ PLUTO_VERSION VERSION old_packages new_packages exception=(e, bt) # TODO: send to user - + showerror(stderr, e, bt) + error_text = sprint(showerror, e, bt) for p in notebook.nbpkg_busy_packages old = get(notebook.nbpkg_terminal_outputs, p, "") @@ -295,19 +390,29 @@ function sync_nbpkg(session, notebook; save::Bool=true) end notebook.nbpkg_busy_packages = String[] update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) # Clear the embedded Project and Manifest and require a restart from the user. - reset_nbpkg(notebook; keep_project=false, save=save) + reset_nbpkg!(notebook, new_topology; keep_project=false, save=save) notebook.nbpkg_restart_required_msg = "Yes, because sync_nbpkg_core failed. \n\n$(error_text)" + notebook.nbpkg_install_time_ns = nothing notebook.nbpkg_ctx_instantiated = false update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) save && save_notebook(session, notebook) - end + finally + cleanup[]() + Status.report_business_finished!(notebook.status_tree, :pkg) + end end +function _has_executed_effectful_code(session::ServerSession, notebook::Notebook) + workspace = WorkspaceManager.get_workspace((session, notebook); allow_creation=false) + workspace === nothing ? false : workspace.has_executed_effectful_code +end + + function writebackup(notebook::Notebook) backup_path = backup_filename(notebook.path) Pluto.readwrite(notebook.path, backup_path) @@ -317,7 +422,102 @@ function writebackup(notebook::Notebook) backup_path end -function reset_nbpkg(notebook::Notebook; keep_project::Bool=false, backup::Bool=true, save::Bool=true) + +function _instantiate(notebook::Notebook, iolistener::IOListener) + start_time = time_ns() + with_io_setup(notebook, iolistener) do + println(iolistener.buffer, "\nInstantiating...") + @debug "PlutoPkg: Instantiating" notebook.path + + # update registries if this is the first time + PkgCompat.update_registries(; force=false) + + # Pkg.instantiate assumes that the environment to be instantiated is active, so we will have to modify the LOAD_PATH of this Pluto server + # We could also run the Pkg calls on the notebook process, but somehow I think that doing it on the server is more charming, though it requires this workaround. + env_dir = PkgCompat.env_dir(notebook.nbpkg_ctx) + pushfirst!(LOAD_PATH, env_dir) + + try + # instantiate without forcing registry update + PkgCompat.instantiate(notebook.nbpkg_ctx; update_registry=false, allow_autoprecomp=false) + finally + # reset the LOAD_PATH + if LOAD_PATH[1] == env_dir + popfirst!(LOAD_PATH) + else + @warn "LOAD_PATH modified during Pkg.instantiate... this is unexpected!" + end + end + end + notebook.nbpkg_install_time_ns = notebook.nbpkg_install_time_ns === nothing ? nothing : (notebook.nbpkg_install_time_ns + (time_ns() - start_time)) + notebook.nbpkg_ctx_instantiated = true +end + +function _precompile(notebook::Notebook, iolistener::IOListener, compiler_options::CompilerOptions) + start_time = time_ns() + with_io_setup(notebook, iolistener) do + println(iolistener.buffer, "\nPrecompiling...") + @debug "PlutoPkg: Precompiling" notebook.path + + env_dir = PkgCompat.env_dir(notebook.nbpkg_ctx) + precompile_isolated(env_dir; + io=iolistener.buffer, + compiler_options, + ) + end + notebook.nbpkg_install_time_ns = notebook.nbpkg_install_time_ns === nothing ? nothing : (notebook.nbpkg_install_time_ns + (time_ns() - start_time)) +end + +function _resolve(notebook::Notebook, iolistener::IOListener) + startlistening(iolistener) + with_io_setup(notebook, iolistener) do + println(iolistener.buffer, "\nResolving...") + @debug "PlutoPkg: Resolving" notebook.path + Pkg.resolve(notebook.nbpkg_ctx) + end +end + + +""" +Run `f` (e.g. `Pkg.instantiate`) on the notebook's package environment. Keep trying more and more invasive strategies to fix problems until the operation succeeds. +""" +function with_auto_fixes(f::Function, notebook::Notebook) + try + f() + catch e + @info "Operation failed. Updating registries and trying again..." exception=e + + PkgCompat.update_registries(; force=true) + try + f() + catch e + @warn "Operation failed. Removing Manifest and trying again..." exception=e + + reset_nbpkg!(notebook; keep_project=true, save=false, backup=false) + notebook.nbpkg_ctx_instantiated = false + try + f() + catch e + @warn "Operation failed. Removing Project compat entries and Manifest and trying again..." exception=(e, catch_backtrace()) + + reset_nbpkg!(notebook; keep_project=true, save=false, backup=false) + PkgCompat.clear_compat_entries!(notebook.nbpkg_ctx) + notebook.nbpkg_ctx_instantiated = false + + f() + end + end + end +end + +""" +Reset the package environment of a notebook. This will remove the `Project.toml` and `Manifest.toml` files from the notebook's secret package environment folder, and if `save` is `true`, it will then save the notebook without embedded Project and Manifest. + +If `keep_project` is `true` (default `false`), the `Project.toml` file will be kept, but the `Manifest.toml` file will be removed. + +This function is useful when we are not able to resolve/activate/instantiate a notebook's environment after loading, which happens when e.g. the environment was created on a different OS or Julia version. +""" +function reset_nbpkg!(notebook::Notebook, topology::Union{NotebookTopology,Nothing}=nothing; keep_project::Bool=false, backup::Bool=true, save::Bool=true) backup && save && writebackup(notebook) if notebook.nbpkg_ctx !== nothing @@ -326,15 +526,25 @@ function reset_nbpkg(notebook::Notebook; keep_project::Bool=false, backup::Bool= keep_project || (isfile(p) && rm(p)) isfile(m) && rm(m) - notebook.nbpkg_ctx = PkgCompat.load_ctx(PkgCompat.env_dir(notebook.nbpkg_ctx)) + PkgCompat.load_ctx!(notebook.nbpkg_ctx, PkgCompat.env_dir(notebook.nbpkg_ctx)) else - notebook.nbpkg_ctx = use_plutopkg(notebook.topology) ? PkgCompat.create_empty_ctx() : nothing + notebook.nbpkg_ctx = if use_plutopkg(something(topology, notebook.topology)) + PkgCompat.load_empty_ctx!(notebook.nbpkg_ctx) + else + nothing + end end save && save_notebook(notebook) end -function update_nbpkg_core(notebook::Notebook; level::Pkg.UpgradeLevel=Pkg.UPLEVEL_MAJOR, on_terminal_output::Function=((args...) -> nothing)) +function update_nbpkg_core( + notebook::Notebook; + level::Pkg.UpgradeLevel=Pkg.UPLEVEL_MAJOR, + on_terminal_output::Function=((args...) -> nothing), + cleanup::Ref{Function}=Ref{Function}(default_cleanup), + compiler_options::CompilerOptions=CompilerOptions(), +) if notebook.nbpkg_ctx !== nothing PkgCompat.mark_original!(notebook.nbpkg_ctx) @@ -342,8 +552,10 @@ function update_nbpkg_core(notebook::Notebook; level::Pkg.UpgradeLevel=Pkg.UPLEV iolistener = let # we don't know which packages will be updated, so we send terminal output to all installed packages - IOListener(callback=(s -> on_terminal_output(old_packages, s))) + report_to = ["nbpkg_update", old_packages...] + IOListener(callback=(s -> on_terminal_output(report_to, s))) end + cleanup[] = () -> stoplistening(iolistener) # We remember which Pkg.Types.PreserveLevel was used. If it's too low, we will recommend/require a notebook restart later. local used_tier = Pkg.PRESERVE_ALL @@ -354,46 +566,52 @@ function update_nbpkg_core(notebook::Notebook; level::Pkg.UpgradeLevel=Pkg.UPLEV end return withtoken(pkg_token) do - PkgCompat.refresh_registry_cache() - - if !notebook.nbpkg_ctx_instantiated - notebook.nbpkg_ctx = PkgCompat.clear_stdlib_compat_entries(notebook.nbpkg_ctx) - PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true)) do - withinteractive(false) do - try - Pkg.resolve(notebook.nbpkg_ctx) - catch e - @warn "Failed to resolve Pkg environment. Removing Manifest and trying again..." exception=e - reset_nbpkg(notebook; keep_project=true, save=false, backup=false) - Pkg.resolve(notebook.nbpkg_ctx) - end + withlogcapture(iolistener) do + PkgCompat.refresh_registry_cache() + PkgCompat.clear_stdlib_compat_entries!(notebook.nbpkg_ctx) + + if !notebook.nbpkg_ctx_instantiated + with_auto_fixes(notebook) do + _instantiate(notebook, iolistener) + end + + with_auto_fixes(notebook) do + _resolve(notebook, iolistener) end end - end - startlistening(iolistener) + with_io_setup(notebook, iolistener) do + # We temporarily clear the "semver-compatible" [deps] entries, because it is difficult to update them after the update 🙈. TODO + PkgCompat.clear_auto_compat_entries!(notebook.nbpkg_ctx) + + try + ### + Pkg.update(notebook.nbpkg_ctx; level=level) + ### + finally + PkgCompat.write_auto_compat_entries!(notebook.nbpkg_ctx) + end + end - PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true)) do - # We temporarily clear the "semver-compatible" [deps] entries, because it is difficult to update them after the update 🙈. TODO - notebook.nbpkg_ctx = PkgCompat.clear_auto_compat_entries(notebook.nbpkg_ctx) - try - ### - Pkg.update(notebook.nbpkg_ctx; level=level) - ### - finally - notebook.nbpkg_ctx = PkgCompat.write_auto_compat_entries(notebook.nbpkg_ctx) + 🐧 = !PkgCompat.is_original(notebook.nbpkg_ctx) + should_instantiate_again = !notebook.nbpkg_ctx_instantiated || 🐧 + + if should_instantiate_again + # Status.report_business!(pkg_status, :instantiate2) do + _instantiate(notebook, iolistener) + _precompile(notebook, iolistener, compiler_options) + # end end - end - stoplistening(iolistener) + stoplistening(iolistener) - 🐧 = !PkgCompat.is_original(notebook.nbpkg_ctx) - ( - did_something=🐧, - restart_recommended=🐧, - restart_required=🐧, - ) + ( + did_something=🐧, + restart_recommended=🐧, + restart_required=🐧, + ) + end end end ( @@ -405,9 +623,12 @@ end function update_nbpkg(session, notebook::Notebook; level::Pkg.UpgradeLevel=Pkg.UPLEVEL_MAJOR, backup::Bool=true, save::Bool=true) - if backup && save - bp = writebackup(notebook) + @assert will_run_pkg(notebook) + + bp = if backup && save + writebackup(notebook) end + cleanup = Ref{Function}(_default_cleanup) try pkg_result = withtoken(notebook.executetoken) do @@ -419,27 +640,34 @@ function update_nbpkg(session, notebook::Notebook; level::Pkg.UpgradeLevel=Pkg.U notebook.nbpkg_terminal_outputs[p] = original * "\n\n" * s end update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) end - update_nbpkg_core(notebook; level=level, on_terminal_output=iocallback) + update_nbpkg_core( + notebook; + level, + on_terminal_output=iocallback, + cleanup, + compiler_options=_merge_notebook_compiler_options(notebook, session.options.compiler), + ) end if pkg_result.did_something if pkg_result.restart_recommended - @debug "PlutoPkg: Notebook restart recommended" notebook.nbpkg_restart_recommended_msg = "Yes, something changed during regular update_nbpkg." + @debug "PlutoPkg: Notebook restart recommended" notebook.path notebook.nbpkg_restart_recommended_msg end if pkg_result.restart_required - @debug "PlutoPkg: Notebook restart REQUIRED" notebook.nbpkg_restart_required_msg = "Yes, something changed during regular update_nbpkg." + @debug "PlutoPkg: Notebook restart REQUIRED" notebook.path notebook.nbpkg_restart_required_msg end else - isfile(bp) && rm(bp) + !isnothing(bp) && isfile(bp) && rm(bp) end finally + cleanup[]() notebook.nbpkg_busy_packages = String[] update_nbpkg_cache!(notebook) - send_notebook_changes!(ClientRequest(session=session, notebook=notebook)) + send_notebook_changes!(ClientRequest(; session, notebook)) save && save_notebook(session, notebook) end end @@ -484,6 +712,22 @@ function is_nbpkg_equal(a::Union{Nothing,PkgContext}, b::Union{Nothing,PkgContex end end +function with_io_setup(f::Function, notebook::Notebook, iolistener::IOListener) + startlistening(iolistener) + PkgCompat.withio(notebook.nbpkg_ctx, IOContext(iolistener.buffer, :color => true, :sneaky_enable_tty => true)) do + withinteractive(false) do + f() + end + end +end + +withlogcapture(f::Function, iolistener::IOListener) = + Logging.with_logger(f, LoggingExtras.TeeLogger( + Logging.current_logger(), + Logging.ConsoleLogger(IOContext(iolistener.buffer, :color => true), Logging.Info) + )) + + const is_interactive_defined = isdefined(Base, :is_interactive) && !Base.isconst(Base, :is_interactive) function withinteractive(f::Function, value::Bool) old_value = isinteractive() @@ -498,35 +742,3 @@ function withinteractive(f::Function, value::Bool) end end end - -"A polling system to watch for writes to an IOBuffer. Up-to-date content will be passed as string to the `callback` function." -Base.@kwdef struct IOListener - callback::Function - buffer::IOBuffer=IOBuffer() - interval::Real=1.0/60 - running::Ref{Bool}=Ref(false) - last_size::Ref{Int}=Ref(-1) -end -function trigger(listener::IOListener) - new_size = listener.buffer.size - if new_size > listener.last_size[] - listener.last_size[] = new_size - new_contents = String(listener.buffer.data[1:new_size]) - listener.callback(new_contents) - end -end -function startlistening(listener::IOListener) - if !listener.running[] - listener.running[] = true - @async while listener.running[] - trigger(listener) - sleep(listener.interval) - end - end -end -function stoplistening(listener::IOListener) - if listener.running[] - listener.running[] = false - trigger(listener) - end -end diff --git a/src/packages/PkgCompat.jl b/src/packages/PkgCompat.jl index 414f8170d9..f0e857fc00 100644 --- a/src/packages/PkgCompat.jl +++ b/src/packages/PkgCompat.jl @@ -4,7 +4,7 @@ export package_versions, package_completions import Pkg import Pkg.Types: VersionRange - +import RegistryInstances import ..Pluto # Should be in Base @@ -60,23 +60,42 @@ else Pkg.Types.Context end +function PkgContext!(ctx::PkgContext; kwargs...) + for (k, v) in kwargs + setfield!(ctx, k, v) + end + ctx +end + # 🐸 "Public API", but using PkgContext -load_ctx(env_dir)::PkgContext = PkgContext(env=Pkg.Types.EnvCache(joinpath(env_dir, "Project.toml"))) +load_ctx(env_dir)::PkgContext = PkgContext(;env=Pkg.Types.EnvCache(joinpath(env_dir, "Project.toml"))) # 🐸 "Public API", but using PkgContext -create_empty_ctx()::PkgContext = load_ctx(mktempdir()) +load_ctx!(ctx::PkgContext, env_dir)::PkgContext = PkgContext!(ctx; env=Pkg.Types.EnvCache(joinpath(env_dir, "Project.toml"))) + +# 🐸 "Public API", but using PkgContext +load_empty_ctx!(ctx) = @static if :io ∈ fieldnames(PkgContext) + PkgContext!(create_empty_ctx(); io=ctx.io) +else + create_empty_ctx() +end + +# 🐸 "Public API", but using PkgContext +create_empty_ctx()::PkgContext = load_ctx!(PkgContext(), mktempdir()) # ⚠️ Internal API with fallback -function load_ctx(original::PkgContext) - new = load_ctx(env_dir(original)) - +function load_ctx!(original::PkgContext) + original_project = deepcopy(original.env.original_project) + original_manifest = deepcopy(original.env.original_manifest) + new = load_ctx!(original, env_dir(original)) + try - new.env.original_project = original.env.original_project - new.env.original_manifest = original.env.original_manifest + new.env.original_project = original_project + new.env.original_manifest = original_manifest catch e @warn "Pkg compat: failed to set original_project" exception=(e,catch_backtrace()) end - + new end @@ -137,76 +156,109 @@ function withio(f::Function, ctx::PkgContext, io::IO) end end +# I'm a pirate harrr 🏴‍☠️ +@static if isdefined(Pkg, :can_fancyprint) + Pkg.can_fancyprint(io::IOContext{IOBuffer}) = get(io, :sneaky_enable_tty, false) === true +end ### # REGISTRIES ### -# (⛔️ Internal API) -"Return paths to all installed registries." -_get_registry_paths() = @static if isdefined(Pkg, :Types) && isdefined(Pkg.Types, :registries) - Pkg.Types.registries() -elseif isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :reachable_registries) - registry_specs = Pkg.Registry.reachable_registries() - [s.path for s in registry_specs] -elseif isdefined(Pkg, :Types) && isdefined(Pkg.Types, :collect_registries) - registry_specs = Pkg.Types.collect_registries() - [s.path for s in registry_specs] -else - String[] -end - -# (⛔️ Internal API) -_get_registries() = map(_get_registry_paths()) do r - @static if isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :RegistryInstance) - Pkg.Registry.RegistryInstance(r) - else - r => Pkg.Types.read_registry(joinpath(r, "Registry.toml")) - end -end +# (✅ "Public" API using RegistryInstances) +"Return all installed registries as `RegistryInstances.RegistryInstance` structs." +_get_registries() = RegistryInstances.reachable_registries() -# (⛔️ Internal API) -"Contains all registries as `Pkg.Types.Registry` structs." +# (✅ "Public" API using RegistryInstances) +"The cached output value of `_get_registries`." const _parsed_registries = Ref(_get_registries()) -# (⛔️ Internal API) +# (✅ "Public" API using RegistryInstances) "Re-parse the installed registries from disk." function refresh_registry_cache() _parsed_registries[] = _get_registries() end -const _updated_registries_compat = Ref(false) +# ⚠️✅ Internal API with fallback +const _updated_registries_compat = @static if isdefined(Pkg, :UPDATED_REGISTRY_THIS_SESSION) && Pkg.UPDATED_REGISTRY_THIS_SESSION isa Ref{Bool} + Pkg.UPDATED_REGISTRY_THIS_SESSION +else + Ref(false) +end -# ⚠️✅ Internal API with good fallback -function update_registries(ctx) - @static if isdefined(Pkg, :Types) && isdefined(Pkg.Types, :update_registries) - Pkg.Types.update_registries(ctx) - else - if !_updated_registries_compat[] - _updated_registries_compat[] = true - Pkg.Registry.update() +# ✅ Public API +function update_registries(; force::Bool=false) + if force || !_updated_registries_compat[] + Pkg.Registry.update() + try + refresh_registry_cache() + catch end + _updated_registries_compat[] = true end end -# ⚠️✅ Internal API with fallback -function instantiate(ctx; update_registry::Bool) - @static if hasmethod(Pkg.instantiate, Tuple{}, (:update_registry,)) - Pkg.instantiate(ctx; update_registry=update_registry) - else - Pkg.instantiate(ctx) +# ✅ Public API +""" +Check when the registries were last updated. If it is recent (max 7 days), then `Pkg.UPDATED_REGISTRY_THIS_SESSION[]` is set to `true`, which will prevent Pkg from doing an automatic registry update. + +Returns the new value of `Pkg.UPDATED_REGISTRY_THIS_SESSION[]`. +""" +function check_registry_age(max_age_ms = 1000.0 * 60 * 60 * 24 * 7)::Bool + if get(ENV, "GITHUB_ACTIONS", "false") == "true" + # don't do this optimization in CI + return false + end + paths = [s.path for s in _get_registries()] + isempty(paths) && return _updated_registries_compat[] + + mtimes = map(paths) do p + try + mtime(p) + catch + zero(time()) + end end + + if all(mtimes .> time() - max_age_ms) + _updated_registries_compat[] = true + end + _updated_registries_compat[] end +### +# Instantiate +### + +# ⚠️ Internal API +function instantiate(ctx; update_registry::Bool, allow_autoprecomp::Bool) + Pkg.instantiate(ctx; update_registry, allow_autoprecomp) + # Not sure how to make a fallback: + # - hasmethod cannot test for kwargs because instantiate takes kwargs... that are passed on somewhere else + # - can't catch for a CallError because the error is weird +end + + +### +# Standard Libraries +### # (⚠️ Internal API with fallback) _stdlibs() = try - values(Pkg.Types.stdlibs()) + stdlibs = values(Pkg.Types.stdlibs()) + T = eltype(stdlibs) + if T == String + stdlibs + elseif T <: Tuple{String,Any} + first.(stdlibs) + else + error() + end catch e @warn "Pkg compat: failed to load standard libraries." exception=(e,catch_backtrace()) - String["CRC32c", "Future", "Sockets", "MbedTLS_jll", "Random", "ArgTools", "libLLVM_jll", "GMP_jll", "Pkg", "Serialization", "LibSSH2_jll", "SHA", "OpenBLAS_jll", "REPL", "LibUV_jll", "nghttp2_jll", "Unicode", "Profile", "SparseArrays", "LazyArtifacts", "CompilerSupportLibraries_jll", "Base64", "Artifacts", "PCRE2_jll", "Printf", "p7zip_jll", "UUIDs", "Markdown", "TOML", "OpenLibm_jll", "Test", "MPFR_jll", "Mmap", "SuiteSparse", "LibGit2", "LinearAlgebra", "Logging", "NetworkOptions", "LibGit2_jll", "LibOSXUnwind_jll", "Dates", "LibUnwind_jll", "Libdl", "LibCURL_jll", "dSFMT_jll", "Distributed", "InteractiveUtils", "Downloads", "SharedArrays", "SuiteSparse_jll", "LibCURL", "Statistics", "Zlib_jll", "FileWatching", "DelimitedFiles", "Tar", "MozillaCACerts_jll"] + String["ArgTools", "Artifacts", "Base64", "CRC32c", "CompilerSupportLibraries_jll", "Dates", "DelimitedFiles", "Distributed", "Downloads", "FileWatching", "Future", "GMP_jll", "InteractiveUtils", "LLD_jll", "LLVMLibUnwind_jll", "LazyArtifacts", "LibCURL", "LibCURL_jll", "LibGit2", "LibGit2_jll", "LibOSXUnwind_jll", "LibSSH2_jll", "LibUV_jll", "LibUnwind_jll", "Libdl", "LinearAlgebra", "Logging", "MPFR_jll", "Markdown", "MbedTLS_jll", "Mmap", "MozillaCACerts_jll", "NetworkOptions", "OpenBLAS_jll", "OpenLibm_jll", "PCRE2_jll", "Pkg", "Printf", "Profile", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "SuiteSparse", "SuiteSparse_jll", "TOML", "Tar", "Test", "UUIDs", "Unicode", "Zlib_jll", "dSFMT_jll", "libLLVM_jll", "libblastrampoline_jll", "nghttp2_jll", "p7zip_jll"] end # ⚠️ Internal API with fallback @@ -245,7 +297,7 @@ end # Package versions ### -# (⛔️ Internal API) +# (✅ "Public" API) """ Return paths to all found registry entries of a given package name. @@ -257,17 +309,17 @@ julia> Pluto.PkgCompat._registry_entries("Pluto") ``` """ function _registry_entries(package_name::AbstractString, registries::Vector=_parsed_registries[])::Vector{String} - flatmap(registries) do (rpath, r) - packages = values(r["packages"]) + flatmap(registries) do reg + packages = values(reg.pkgs) String[ - joinpath(rpath, d["path"]) + joinpath(reg.path, d.path) for d in packages - if d["name"] == package_name + if d.name == package_name ] end end -# (⛔️ Internal API) +# (🐸 "Public API", but using PkgContext) function _package_versions_from_path(registry_entry_fullpath::AbstractString)::Vector{VersionNumber} # compat vd = @static if isdefined(Pkg, :Operations) && isdefined(Pkg.Operations, :load_versions) && hasmethod(Pkg.Operations.load_versions, (String,)) @@ -278,8 +330,7 @@ function _package_versions_from_path(registry_entry_fullpath::AbstractString)::V vd |> keys |> collect end -# ⚠️ Internal API with fallback -# See https://github.com/JuliaLang/Pkg.jl/issues/2607 +# ✅ "Public" API using RegistryInstances """ Return all registered versions of the given package. Returns `["stdlib"]` for standard libraries, and a `Vector{VersionNumber}` for registered packages. """ @@ -288,23 +339,18 @@ function package_versions(package_name::AbstractString)::Vector ["stdlib"] else try - @static(if isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :uuids_from_name) - flatmap(_parsed_registries[]) do reg - uuids_with_name = Pkg.Registry.uuids_from_name(reg, package_name) - flatmap(uuids_with_name) do u - pkg = get(reg, u, nothing) - if pkg !== nothing - info = Pkg.Registry.registry_info(pkg) - collect(keys(info.version_info)) - else - [] - end + flatmap(_parsed_registries[]) do reg + uuids_with_name = RegistryInstances.uuids_from_name(reg, package_name) + flatmap(uuids_with_name) do u + pkg = get(reg, u, nothing) + if pkg !== nothing + info = RegistryInstances.registry_info(pkg) + collect(keys(info.version_info)) + else + [] end end - else - ps = _registry_entries(package_name) - flatmap(_package_versions_from_path, ps) - end) |> sort + end catch e @warn "Pkg compat: failed to get installable versions." exception=(e,catch_backtrace()) ["latest"] @@ -319,32 +365,31 @@ package_exists(package_name::AbstractString)::Bool = # 🐸 "Public API", but using PkgContext function dependencies(ctx) - # Pkg.dependencies(ctx) should also work on 1.5, but there is some weird bug (run the tests without this patch). This is probably some Pkg bug that got fixed. - @static if VERSION < v"1.6.0-a" - ctx.env.manifest - else - try - # ctx.env.manifest - @static if hasmethod(Pkg.dependencies, (PkgContext,)) - Pkg.dependencies(ctx) - else - Pkg.dependencies(ctx.env) - end - catch e - if !occursin(r"expected.*exist.*manifest", sprint(showerror, e)) - @error """ - Pkg error: you might need to use - - Pluto.reset_notebook_environment(notebook_path) + try + # ctx.env.manifest + @static if hasmethod(Pkg.dependencies, (PkgContext,)) + Pkg.dependencies(ctx) + else + Pkg.dependencies(ctx.env) + end + catch e + if !any(occursin(sprint(showerror, e)), ( + r"expected.*exist.*manifest", + r"no method.*project_rel_path.*Nothing\)", # https://github.com/JuliaLang/Pkg.jl/issues/3404 + )) + @error """ + Pkg error: you might need to use - to reset this notebook's environment. + Pluto.reset_notebook_environment(notebook_path) - Before doing so, consider sending your notebook file to https://github.com/fonsp/Pluto.jl/issues together with the following info: - """ Pluto.PLUTO_VERSION VERSION exception=(e,catch_backtrace()) - end + to reset this notebook's environment. - Dict() + Before doing so, consider sending your notebook file to https://github.com/fonsp/Pluto.jl/issues together with the following info: + """ Pluto.PLUTO_VERSION VERSION exception=(e,catch_backtrace()) end + + Dict() + end end @@ -384,19 +429,38 @@ project_key_order(key::String) = something(findfirst(x -> x == key, _project_key_order), length(_project_key_order) + 1) # ✅ Public API -function _modify_compat(f!::Function, ctx::PkgContext)::PkgContext - toml = Pkg.TOML.parsefile(project_file(ctx)) - compat = get!(Dict, toml, "compat") - +function _modify_compat!(f!::Function, ctx::PkgContext)::PkgContext + project_path = project_file(ctx) + + toml = if isfile(project_path) + Pkg.TOML.parsefile(project_path) + else + Dict{String,Any}() + end + compat = get!(Dict{String,Any}, toml, "compat") + f!(compat) isempty(compat) && delete!(toml, "compat") - write(project_file(ctx), sprint() do io + write(project_path, sprint() do io Pkg.TOML.print(io, toml; sorted=true, by=(key -> (project_key_order(key), key))) end) - return load_ctx(ctx) + return _update_project_hash!(load_ctx!(ctx)) +end + +# ✅ Internal API with fallback +"Update the project hash in the manifest file (https://github.com/JuliaLang/Pkg.jl/pull/2815)" +function _update_project_hash!(ctx::PkgContext) + VERSION >= v"1.8.0" && isfile(manifest_file(ctx)) && try + Pkg.Operations.record_project_hash(ctx.env) + Pkg.Types.write_manifest(ctx.env) + catch e + @info "Failed to update project hash." exception=(e,catch_backtrace()) + end + + ctx end @@ -406,8 +470,8 @@ Add any missing [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entr The automatic compat entry is: `"~" * string(installed_version)`. """ -function write_auto_compat_entries(ctx::PkgContext)::PkgContext - _modify_compat(ctx) do compat +function write_auto_compat_entries!(ctx::PkgContext)::PkgContext + _modify_compat!(ctx) do compat for p in keys(project(ctx).dependencies) if !haskey(compat, p) m_version = get_manifest_version(ctx, p) @@ -422,11 +486,24 @@ end # ✅ Public API """ -Remove any automatically-generated [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml`. This will undo the effects of [`write_auto_compat_entries`](@ref) but leave other (e.g. manual) compat entries intact. Return the new `PkgContext`. +Remove all [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml`. +""" +function clear_compat_entries!(ctx::PkgContext)::PkgContext + if isfile(project_file(ctx)) + _modify_compat!(empty!, ctx) + else + ctx + end +end + + +# ✅ Public API +""" +Remove any automatically-generated [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml`. This will undo the effects of [`write_auto_compat_entries!`](@ref) but leave other (e.g. manual) compat entries intact. Return the new `PkgContext`. """ -function clear_auto_compat_entries(ctx::PkgContext)::PkgContext +function clear_auto_compat_entries!(ctx::PkgContext)::PkgContext if isfile(project_file(ctx)) - _modify_compat(ctx) do compat + _modify_compat!(ctx) do compat for p in keys(compat) m_version = get_manifest_version(ctx, p) if m_version !== nothing && !is_stdlib(p) @@ -445,9 +522,9 @@ end """ Remove any [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml` for standard libraries. These entries are created when an old version of Julia uses a package that later became a standard library, like https://github.com/JuliaPackaging/Artifacts.jl. Return the new `PkgContext`. """ -function clear_stdlib_compat_entries(ctx::PkgContext)::PkgContext +function clear_stdlib_compat_entries!(ctx::PkgContext)::PkgContext if isfile(project_file(ctx)) - _modify_compat(ctx) do compat + _modify_compat!(ctx) do compat for p in keys(compat) if is_stdlib(p) @info "Removing compat entry for stdlib" p diff --git a/src/packages/PkgUtils.jl b/src/packages/PkgUtils.jl index 52f3d91662..01d50e488b 100644 --- a/src/packages/PkgUtils.jl +++ b/src/packages/PkgUtils.jl @@ -81,10 +81,10 @@ nb_and_dir_environments_equal(notebook_path::String, dir::String) = nb_and_dir_e reset_notebook_environment(notebook_path::String; keep_project::Bool=false, backup::Bool=true) ``` -Remove the embedded `Project.toml` and `Manifest.toml` from a notebook file, modifying the file. If `keep_project` is true, only `Manifest.toml` will be deleted. A backup file is created by default. +Remove the embedded `Project.toml` and `Manifest.toml` from a notebook file, modifying the file. If `keep_project` is true, only `Manifest.toml` will be deleted. A backup of the notebook file is created by default. """ function reset_notebook_environment(path::String; kwargs...) - Pluto.reset_nbpkg( + Pluto.reset_nbpkg!( load_notebook_nobackup(path); kwargs... ) @@ -235,4 +235,4 @@ function testnb() t end -end \ No newline at end of file +end diff --git a/src/packages/precompile_isolated.jl b/src/packages/precompile_isolated.jl new file mode 100644 index 0000000000..b1619181ce --- /dev/null +++ b/src/packages/precompile_isolated.jl @@ -0,0 +1,36 @@ +function precompile_isolated( + environment::String; + compiler_options::Configuration.CompilerOptions=Configuration.CompilerOptions(), + io::IO, +) + flags = Configuration._convert_to_flags(compiler_options) + + code = """ + # import Pkg with safe load path + pushfirst!(LOAD_PATH, "@stdlib") + import Pkg + popfirst!(LOAD_PATH) + + out_stream = IOContext(stdout, :color => true) + # I'm a pirate harrr 🏴‍☠️ + @static if isdefined(Pkg, :can_fancyprint) + Pkg.can_fancyprint(io::IO) = true + end + + Pkg.activate($(repr(environment)); io=out_stream) + if VERSION >= v"1.8.0" # https://github.com/JuliaLang/Pkg.jl/pull/2816 + Pkg.precompile(; already_instantiated=true, io=out_stream) + else + Pkg.precompile(; io=out_stream) + end + """ + + cmd = `$(Base.julia_cmd()[1]) $(flags) -e $(code)` + + Base.run(pipeline( + cmd; stdout=io, #dont capture stderr because we want it to show in the server terminal when something goes wrong + )) + + # In the future we could allow interrupting the precompilation process (e.g. when the notebook is shut down) + # by running this code using Malt.jl +end diff --git a/src/precompile.jl b/src/precompile.jl new file mode 100644 index 0000000000..69ad276bf9 --- /dev/null +++ b/src/precompile.jl @@ -0,0 +1,81 @@ +using PrecompileTools: PrecompileTools + +const __TEST_NOTEBOOK_ID = uuid1() + +PrecompileTools.@compile_workload begin + let + channel = Channel{Any}(10) + Pluto.PlutoRunner.setup_plutologger( + __TEST_NOTEBOOK_ID, + channel, + ) + end + expr = Expr(:toplevel, :(1 + 1)) + Pluto.PlutoRunner.run_expression(Module(), expr, __TEST_NOTEBOOK_ID, uuid1(), nothing); + + nb = Pluto.Notebook([ + Pluto.Cell("""md"Hello *world*" """) + Pluto.Cell("""[f(x)]""") + Pluto.Cell("""x = 1""") + Pluto.Cell( + """ + function f(z::Integer) + z / 123 + end + """) + Pluto.Cell( + """ + "asdf" + begin + while false + local p = 123 + try + [(x,a...) for x in (a for a in b)] + A.B.hello() do z + @gensym z + (z) -> z/:(z / z) + end + catch + end + end + end + """ + ) + ]) + let + topology = Pluto.updated_topology(nb.topology, nb, nb.cells) + # Our reactive sorting algorithm. + Pluto.topological_order(topology, topology.cell_order) + end + + let + io = IOBuffer() + # Notebook file format. + Pluto.save_notebook(io, nb) + seekstart(io) + Pluto.load_notebook_nobackup(io, "whatever.jl") + end + + let + state1 = Pluto.notebook_to_js(nb) + state2 = Pluto.notebook_to_js(nb) + # MsgPack + Pluto.unpack(Pluto.pack(state1)) + # State diffing + Pluto.Firebasey.diff(state1, state2) + end + + s = Pluto.ServerSession(; + options=Pluto.Configuration.from_flat_kwargs( + disable_writing_notebook_files=true, + workspace_use_distributed=false, + auto_reload_from_file=false, + run_notebook_on_load=false, + lazy_workspace_creation=true, + capture_stdout=false, + ) + ) +end + +using PrecompileSignatures: @precompile_signatures +@precompile_signatures(Pluto) diff --git a/src/runner/Loader.jl b/src/runner/Loader.jl index d1933e7367..73a65e68f3 100644 --- a/src/runner/Loader.jl +++ b/src/runner/Loader.jl @@ -1,51 +1,67 @@ -begin -pushfirst!(LOAD_PATH, "@stdlib") -import Pkg -popfirst!(LOAD_PATH) +# The goal of this file is to import PlutoRunner into Main. +# +# This is difficult because PlutoRunner uses standard libraries and packages that are not necessarily available in the standard environment. +# +# Our solution is to create a temporary environment just for loading PlutoRunner. This environment is stored in a scratchspace parameterized by the Pluto version and julia version, +# and used by all notebook launches. Reusing the environment means extra speed. + -# We need to Pkg.instantiate the package environment that this notebook worker process will launch in -local my_dir = @__DIR__ -local pluto_dir = joinpath(my_dir, "..", "..") +begin + pushfirst!(LOAD_PATH, "@stdlib") + import Pkg + popfirst!(LOAD_PATH) -local runner_env_dir = mkpath(joinpath(Pkg.envdir(Pkg.depots()[1]), "__pluto_boot_v2_" * string(VERSION))) -local new_ptoml_path = joinpath(runner_env_dir, "Project.toml") + local original_LP = copy(LOAD_PATH) + local original_AP = Base.ACTIVE_PROJECT[] -local ptoml_contents = read(joinpath(my_dir, "NotebookProcessProject.toml"), String) -write(new_ptoml_path, ptoml_contents) + # Path to our notebook boot package environment which is set by WorkspaceManager + # when spawning the process. + local runner_env_dir = pluto_boot_environment_path -local pkg_ctx = Pkg.Types.Context(env=Pkg.Types.EnvCache(new_ptoml_path)) + local new_LP = ["@", "@stdlib"] + local new_AP = runner_env_dir -try - Pkg.resolve(pkg_ctx; io=devnull) # supress IO -catch - # if it failed, do it again without suppressing io try - Pkg.resolve(pkg_ctx) - catch e - @error "Failed to resolve notebook boot environment" exception=(e, catch_backtrace()) - end -end -try - # we don't suppress IO for this one because it can take very long, and that would be a frustrating experience without IO - if VERSION >= v"1.6.0-a" - # precompilation switched off because of https://github.com/fonsp/Pluto.jl/issues/875 - Pkg.instantiate(pkg_ctx; update_registry=false, allow_autoprecomp=false) - elseif VERSION >= v"1.3.0" - # registry update is not required here and may save some time for startup - Pkg.instantiate(pkg_ctx; update_registry=false) - else - Pkg.instantiate(pkg_ctx) - end -catch e - @error "Failed to instantiate notebook boot environment" exception=(e, catch_backtrace()) -end + # Activate the environment + copy!(LOAD_PATH, new_LP) + Base.ACTIVE_PROJECT[] = new_AP + + # Set up our notebook boot package environment by adding a single package: + path = joinpath(@__DIR__, "PlutoRunner") + try + Pkg.develop([Pkg.PackageSpec(; path)]; io=devnull) + catch + # if it failed, do it again without suppressing io + Pkg.develop([Pkg.PackageSpec(; path)]) + end + # Resolve + try + Pkg.resolve(; io=devnull) # supress IO + catch + # if it failed, do it again without suppressing io + try + Pkg.resolve() + catch e + @error "Failed to resolve notebook boot environment" exception = (e, catch_backtrace()) + end + end -pushfirst!(LOAD_PATH, runner_env_dir) + # Instantiate + try + # we don't suppress IO for this one because it can take very long, and that would be a frustrating experience without IO + # precompilation switched off because of https://github.com/fonsp/Pluto.jl/issues/875 + Pkg.instantiate(; update_registry=false, allow_autoprecomp=false) + catch e + @error "Failed to instantiate notebook boot environment" exception = (e, catch_backtrace()) + end -# -include(joinpath(my_dir, "PlutoRunner.jl")) -# + # Import PlutoRunner into Main + import PlutoRunner -popfirst!(LOAD_PATH) -end \ No newline at end of file + finally + # Reset the pkg environment + copy!(LOAD_PATH, original_LP) + Base.ACTIVE_PROJECT[] = original_AP + end +end diff --git a/src/runner/NotebookProcessProject.toml b/src/runner/PlutoRunner/Project.toml similarity index 70% rename from src/runner/NotebookProcessProject.toml rename to src/runner/PlutoRunner/Project.toml index c4ab0afd8b..191b55efc1 100644 --- a/src/runner/NotebookProcessProject.toml +++ b/src/runner/PlutoRunner/Project.toml @@ -1,3 +1,8 @@ +name = "PlutoRunner" +uuid = "dc6b355a-2368-4481-ae6d-ae0351418d79" +authors = ["Michiel Dral ", "Fons van der Plas ", "Paul Berg "] +version = "29.12.98" + [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" @@ -12,4 +17,4 @@ Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] -FuzzyCompletions = "0.3,0.4" +FuzzyCompletions = "0.3,0.4,0.5" diff --git a/src/runner/PlutoRunner.jl b/src/runner/PlutoRunner/src/PlutoRunner.jl similarity index 58% rename from src/runner/PlutoRunner.jl rename to src/runner/PlutoRunner/src/PlutoRunner.jl index 688d6d5855..f9f4f7b915 100644 --- a/src/runner/PlutoRunner.jl +++ b/src/runner/PlutoRunner/src/PlutoRunner.jl @@ -1,11 +1,22 @@ # Will be evaluated _inside_ the workspace process. -# Pluto does most things on process 1 (the server), and it uses little workspace processes to evaluate notebook code in. -# These baby processes don't import Pluto, they only import this module. Functions from this module are called by WorkspaceManager.jl, using Distributed +# Pluto does most things on the server, but it uses worker processes to evaluate notebook code in. +# These processes don't import Pluto, they only import this module. +# Functions from this module are called by WorkspaceManager.jl via Malt. -# So when reading this file, pretend that you are living in process 2, and you are communicating with Pluto's server, who lives in process 1. +# When reading this file, pretend that you are living in a worker process, +# and you are communicating with Pluto's server, who lives in the main process. # The package environment that this file is loaded with is the NotebookProcessProject.toml file in this directory. +# SOME EXTRA NOTES + +# 1. The entire PlutoRunner should be a single file. +# 2. Restrict the communication between this PlutoRunner and the Pluto server to only use *Base Julia types*, like `String`, `Dict`, `NamedTuple`, etc. + +# These restriction are there to allow flexibility in the way that this file is +# loaded on a runner process, which is something that we might want to change +# in the future. + module PlutoRunner # import these two so that they can be imported from Main on the worker process if it launches without the stdlibs in its LOAD_PATH @@ -14,26 +25,29 @@ import InteractiveUtils using Markdown import Markdown: html, htmlinline, LaTeX, withtag, htmlesc -import Distributed import Base64 -import FuzzyCompletions: Completion, ModuleCompletion, PropertyCompletion, FieldCompletion, PathCompletion, DictCompletion, completions, completion_text, score +import FuzzyCompletions: Completion, BslashCompletion, ModuleCompletion, PropertyCompletion, FieldCompletion, PathCompletion, DictCompletion, completions, completion_text, score import Base: show, istextmime import UUIDs: UUID, uuid4 import Dates: DateTime import Logging +import REPL export @bind -MimedOutput = Tuple{Union{String,Vector{UInt8},Dict{Symbol,Any}},MIME} +# This is not a struct to make it easier to pass these objects between processes. +const MimedOutput = Tuple{Union{String,Vector{UInt8},Dict{Symbol,Any}},MIME} + const ObjectID = typeof(objectid("hello computer")) const ObjectDimPair = Tuple{ObjectID,Int64} -Base.@kwdef struct CachedMacroExpansion +struct CachedMacroExpansion original_expr_hash::UInt64 expanded_expr::Expr expansion_duration::UInt64 has_pluto_hook_features::Bool - did_mention_expansion_time::Bool=false + did_mention_expansion_time::Bool + expansion_logs::Vector{Any} end const cell_expanded_exprs = Dict{UUID,CachedMacroExpansion}() @@ -71,13 +85,18 @@ const workspace_preamble = [ :(show, showable, showerror, repr, string, print, println), # https://github.com/JuliaLang/julia/issues/18181 ] +const PLUTO_INNER_MODULE_NAME = Symbol("#___this_pluto_module_name") + const moduleworkspace_count = Ref(0) function increment_current_module()::Symbol id = (moduleworkspace_count[] += 1) new_workspace_name = Symbol("workspace#", id) - new_module = Core.eval(Main, :( - module $(new_workspace_name) $(workspace_preamble...) end + Core.eval(Main, :( + module $(new_workspace_name) + $(workspace_preamble...) + const $(PLUTO_INNER_MODULE_NAME) = $(new_workspace_name) + end )) new_workspace_name @@ -107,8 +126,7 @@ We don't re-build the macro in every workspace, so we need to remove these refs TODO? Don't remove the refs, but instead replace them with a new ref pointing to the new module? """ function collect_and_eliminate_globalrefs!(ref::GlobalRef, mutable_ref_list=[]) - test_mod_name = nameof(ref.mod) |> string - if startswith(test_mod_name, "workspace#") + if is_pluto_workspace(ref.mod) new_name = gensym(ref.name) push!(mutable_ref_list, ref.name => new_name) new_name @@ -144,6 +162,7 @@ function globalref_to_workspaceref(expr) # Create new lines to assign to the replaced names of the global refs. # This way the expression explorer doesn't care (it just sees references to variables outside of the workspace), # and the variables don't get overwriten by local assigments to the same name (because we have special names). + (mutable_ref_list .|> ref -> :(local $(ref[2])))..., map(mutable_ref_list) do ref # I can just do Expr(:isdefined, ref[1]) here, but it feels better to macroexpand, # because it's more obvious what's going on, and when they ever change the ast, we're safe :D @@ -162,12 +181,28 @@ replace_pluto_properties_in_expr(::GiveMeCellID; cell_id, kwargs...) = cell_id replace_pluto_properties_in_expr(::GiveMeRerunCellFunction; rerun_cell_function, kwargs...) = rerun_cell_function replace_pluto_properties_in_expr(::GiveMeRegisterCleanupFunction; register_cleanup_function, kwargs...) = register_cleanup_function replace_pluto_properties_in_expr(expr::Expr; kwargs...) = Expr(expr.head, map(arg -> replace_pluto_properties_in_expr(arg; kwargs...), expr.args)...) +replace_pluto_properties_in_expr(m::Module; kwargs...) = if is_pluto_workspace(m) + PLUTO_INNER_MODULE_NAME +else + m +end replace_pluto_properties_in_expr(other; kwargs...) = other +function replace_pluto_properties_in_expr(ln::LineNumberNode; cell_id, kwargs...) # See https://github.com/fonsp/Pluto.jl/pull/2241 + file = string(ln.file) + out = if endswith(file, string(cell_id)) + # We already have the correct cell_id in this LineNumberNode + ln + else + # We append to the LineNumberNode file #@#==# + cell_id + LineNumberNode(ln.line, Symbol(file * "#@#==#$(cell_id)")) + end + return out +end "Similar to [`replace_pluto_properties_in_expr`](@ref), but just checks for existance and doesn't check for [`GiveMeCellID`](@ref)" has_hook_style_pluto_properties_in_expr(::GiveMeRerunCellFunction) = true has_hook_style_pluto_properties_in_expr(::GiveMeRegisterCleanupFunction) = true -has_hook_style_pluto_properties_in_expr(expr::Expr) = any(has_hook_style_pluto_properties_in_expr, expr.args) +has_hook_style_pluto_properties_in_expr(expr::Expr)::Bool = any(has_hook_style_pluto_properties_in_expr, expr.args) has_hook_style_pluto_properties_in_expr(other) = false @@ -207,7 +242,7 @@ module CantReturnInPluto We do macro expansion now, so we can also check for `return` statements "statically". This method goes through an expression and replaces all `return` statements with `throw(CantReturnInPlutoException())` """ - function replace_returns_with_error(expr::Expr) + function replace_returns_with_error(expr::Expr)::Expr if expr.head == :return :(throw($(CantReturnInPlutoException()))) elseif expr.head == :quote @@ -224,9 +259,9 @@ module CantReturnInPluto replace_returns_with_error(other) = other "Go through a quoted expression and remove returns" - function replace_returns_with_error_in_interpolation(ex::Expr) - if ex.head == :$ - Expr(:$, replace_returns_with_error_in_interpolation(ex.args[1])) + function replace_returns_with_error_in_interpolation(expr::Expr) + if expr.head == :$ + Expr(:$, replace_returns_with_error_in_interpolation(expr.args[1])) else # We are still in a quote, so we do go deeper, but we keep ignoring everything except :$'s Expr(expr.head, map(arg -> replace_returns_with_error_in_interpolation(arg), expr.args)...) @@ -235,56 +270,78 @@ module CantReturnInPluto replace_returns_with_error_in_interpolation(ex) = ex end - -function try_macroexpand(mod, cell_uuid, expr) +function try_macroexpand(mod::Module, notebook_id::UUID, cell_id::UUID, expr; capture_stdout::Bool=true) # Remove the precvious cached expansion, so when we error somewhere before we update, # the old one won't linger around and get run accidentally. - delete!(cell_expanded_exprs, cell_uuid) + pop!(cell_expanded_exprs, cell_id, nothing) # Remove toplevel block, as that screws with the computer and everything - expr_not_toplevel = if expr.head == :toplevel || expr.head == :block + expr_not_toplevel = if Meta.isexpr(expr, (:toplevel, :block)) Expr(:block, expr.args...) else @warn "try_macroexpand expression not :toplevel or :block" expr Expr(:block, expr) end - - elapsed_ns = time_ns() - expanded_expr = macroexpand(mod, expr_not_toplevel) - elapsed_ns = time_ns() - elapsed_ns + + logger = get!(() -> PlutoCellLogger(notebook_id, cell_id), pluto_cell_loggers, cell_id) + if logger.workspace_count < moduleworkspace_count[] + logger = pluto_cell_loggers[cell_id] = PlutoCellLogger(notebook_id, cell_id) + end + + capture_logger = CaptureLogger(nothing, logger, Dict[]) + + expanded_expr, elapsed_ns = with_logger_and_io_to_logs(capture_logger; capture_stdout, stdio_loglevel=stdout_log_level) do + elapsed_ns = time_ns() + expanded_expr = macroexpand(mod, expr_not_toplevel)::Expr + elapsed_ns = time_ns() - elapsed_ns + expanded_expr, elapsed_ns + end + + logs = capture_logger.logs # Removes baked in references to the module this was macroexpanded in. # Fix for https://github.com/fonsp/Pluto.jl/issues/1112 - expr_without_return = CantReturnInPluto.replace_returns_with_error(expanded_expr) + expr_without_return = CantReturnInPluto.replace_returns_with_error(expanded_expr)::Expr expr_without_globalrefs = globalref_to_workspaceref(expr_without_return) has_pluto_hook_features = has_hook_style_pluto_properties_in_expr(expr_without_globalrefs) - expr_to_save = replace_pluto_properties_in_expr(expr_without_globalrefs, - cell_id=cell_uuid, - rerun_cell_function=() -> rerun_cell_from_notebook(cell_uuid), - register_cleanup_function=(fn) -> UseEffectCleanups.register_cleanup(fn, cell_uuid), + expr_to_save = replace_pluto_properties_in_expr(expr_without_globalrefs; + cell_id, + rerun_cell_function=() -> rerun_cell_from_notebook(cell_id), + register_cleanup_function=(fn) -> UseEffectCleanups.register_cleanup(fn, cell_id), ) - cell_expanded_exprs[cell_uuid] = CachedMacroExpansion( - original_expr_hash=expr_hash(expr), - expanded_expr=expr_to_save, - expansion_duration=elapsed_ns, - has_pluto_hook_features=has_pluto_hook_features, + did_mention_expansion_time = false + cell_expanded_exprs[cell_id] = CachedMacroExpansion( + expr_hash(expr), + expr_to_save, + elapsed_ns, + has_pluto_hook_features, + did_mention_expansion_time, + logs, ) return (sanitize_expr(expr_to_save), expr_hash(expr_to_save)) end +function exported_names(mod::Module) + @static if VERSION ≥ v"1.11.0-DEV.469" + filter!(Base.Fix1(Base.isexported, mod), names(mod; all=true)) + else + names(mod) + end +end + function get_module_names(workspace_module, module_ex::Expr) try - Core.eval(workspace_module, Expr(:call, :names, module_ex)) |> Set{Symbol} + Core.eval(workspace_module, Expr(:call, exported_names, module_ex)) |> Set{Symbol} catch Set{Symbol}() end end function collect_soft_definitions(workspace_module, modules::Set{Expr}) - mapreduce(module_ex -> get_module_names(workspace_module, module_ex), union!, modules; init=Set{Symbol}()) + mapreduce(module_ex -> get_module_names(workspace_module, module_ex), union!, modules; init=Set{Symbol}()) end @@ -379,7 +436,10 @@ struct OutputNotDefined end function compute(m::Module, computer::Computer) # 1. get the referenced global variables # this might error if the global does not exist, which is exactly what we want - input_global_values = getfield.([m], computer.input_globals) + input_global_values = Vector{Any}(undef, length(computer.input_globals)) + for (i, s) in enumerate(computer.input_globals) + input_global_values[i] = getfield(m, s) + end # 2. run the function out = Base.invokelatest(computer.f, input_global_values...) @@ -451,7 +511,16 @@ If the third argument is a `Tuple{Set{Symbol}, Set{Symbol}}` containing the refe This function is memoized: running the same expression a second time will simply call the same generated function again. This is much faster than evaluating the expression, because the function only needs to be Julia-compiled once. See https://github.com/fonsp/Pluto.jl/pull/720 """ -function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_info::Union{Nothing,Tuple{Set{Symbol},Set{Symbol}}}=nothing, forced_expr_id::Union{ObjectID,Nothing}=nothing; user_requested_run::Bool=true) +function run_expression( + m::Module, + expr::Any, + notebook_id::UUID, + cell_id::UUID, + @nospecialize(function_wrapped_info::Union{Nothing,Tuple{Set{Symbol},Set{Symbol}}}=nothing), + @nospecialize(forced_expr_id::Union{ObjectID,Nothing}=nothing); + user_requested_run::Bool=true, + capture_stdout::Bool=true, + ) if user_requested_run # TODO Time elapsed? Possibly relays errors in cleanup function? UseEffectCleanups.trigger_cleanup(cell_id) @@ -459,15 +528,18 @@ function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_in # TODO Could also put explicit `try_macroexpand` here, to make clear that user_requested_run => fresh macro identity end + old_currently_running_cell_id = currently_running_cell_id[] currently_running_cell_id[] = cell_id + logger = get!(() -> PlutoCellLogger(notebook_id, cell_id), pluto_cell_loggers, cell_id) + if logger.workspace_count < moduleworkspace_count[] + logger = pluto_cell_loggers[cell_id] = PlutoCellLogger(notebook_id, cell_id) + end + # reset published objects cell_published_objects[cell_id] = Dict{String,Any}() # reset registered bonds - for s in get(cell_registered_bond_names, cell_id, Set{Symbol}()) - delete!(registered_bond_elements, s) - end cell_registered_bond_names[cell_id] = Set{Symbol}() # If the cell contains macro calls, we want those macro calls to preserve their identity, @@ -479,7 +551,7 @@ function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_in # .... But ideally we wouldn't re-macroexpand and store the error the first time (TODO-ish) if !haskey(cell_expanded_exprs, cell_id) || cell_expanded_exprs[cell_id].original_expr_hash != expr_hash(expr) try - try_macroexpand(m, cell_id, expr) + try_macroexpand(m, notebook_id, cell_id, expr; capture_stdout) catch e result = CapturedException(e, stacktrace(catch_backtrace())) cell_results[cell_id], cell_runtimes[cell_id] = (result, nothing) @@ -492,16 +564,24 @@ function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_in original_expr = expr expr = expanded_cache.expanded_expr + # Re-play logs from expansion cache + for log in expanded_cache.expansion_logs + (level, msg, _module, group, id, file, line, kwargs) = log + Logging.handle_message(logger, level, msg, _module, group, id, file, line; kwargs...) + end + empty!(expanded_cache.expansion_logs) + # We add the time it took to macroexpand to the time for the first call, # but we make sure we don't mention it on subsequent calls expansion_runtime = if expanded_cache.did_mention_expansion_time === false - # Is this really the easiest way to clone a struct with some changes? Pfffft + did_mention_expansion_time = true cell_expanded_exprs[cell_id] = CachedMacroExpansion( - original_expr_hash=expanded_cache.original_expr_hash, - expanded_expr=expanded_cache.expanded_expr, - expansion_duration=expanded_cache.expansion_duration, - did_mention_expansion_time=true, - has_pluto_hook_features=expanded_cache.has_pluto_hook_features, + expanded_cache.original_expr_hash, + expanded_cache.expanded_expr, + expanded_cache.expansion_duration, + expanded_cache.has_pluto_hook_features, + did_mention_expansion_time, + expanded_cache.expansion_logs, ) expanded_cache.expansion_duration else @@ -513,35 +593,40 @@ function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_in throw("Expression still contains macro calls!!") end - result, runtime = if function_wrapped_info === nothing - toplevel_expr = Expr(:toplevel, expr) - wrapped = timed_expr(toplevel_expr) - ans, runtime = run_inside_trycatch(m, wrapped) - (ans, add_runtimes(runtime, expansion_runtime)) - else - expr_id = forced_expr_id !== nothing ? forced_expr_id : expr_hash(expr) - local computer = get(computers, cell_id, nothing) - if computer === nothing || computer.expr_id !== expr_id - try - computer = register_computer(expr, expr_id, cell_id, collect.(function_wrapped_info)...) - catch e - # @error "Failed to generate computer function" expr exception=(e,stacktrace(catch_backtrace())) - return run_expression(m, original_expr, cell_id, nothing; user_requested_run=user_requested_run) + result, runtime = with_logger_and_io_to_logs(logger; capture_stdout, stdio_loglevel=stdout_log_level) do # about 200ns + 3ms overhead + if function_wrapped_info === nothing + toplevel_expr = Expr(:toplevel, expr) + wrapped = timed_expr(toplevel_expr) + ans, runtime = run_inside_trycatch(m, wrapped) + (ans, add_runtimes(runtime, expansion_runtime)) + else + expr_id = forced_expr_id !== nothing ? forced_expr_id : expr_hash(expr) + local computer = get(computers, cell_id, nothing) + if computer === nothing || computer.expr_id !== expr_id + try + computer = register_computer(expr, expr_id, cell_id, collect.(function_wrapped_info)...) + catch e + # @error "Failed to generate computer function" expr exception=(e,stacktrace(catch_backtrace())) + return run_expression(m, original_expr, notebook_id, cell_id, nothing; user_requested_run=user_requested_run) + end end - end - # This check solves the problem of a cell like `false && variable_that_does_not_exist`. This should run without error, but will fail in our function-wrapping-magic because we get the value of `variable_that_does_not_exist` before calling the generated function. - # The fix is to detect this situation and run the expression in the classical way. - ans, runtime = if any(name -> !isdefined(m, name), computer.input_globals) - # Do run_expression but with function_wrapped_info=nothing so it doesn't go in a Computer() - # @warn "Got variables that don't exist, running outside of computer" not_existing=filter(name -> !isdefined(m, name), computer.input_globals) - run_expression(m, original_expr, cell_id; user_requested_run) - else - run_inside_trycatch(m, () -> compute(m, computer)) - end + # This check solves the problem of a cell like `false && variable_that_does_not_exist`. This should run without error, but will fail in our function-wrapping-magic because we get the value of `variable_that_does_not_exist` before calling the generated function. + # The fix is to detect this situation and run the expression in the classical way. + ans, runtime = if any(name -> !isdefined(m, name), computer.input_globals) + # Do run_expression but with function_wrapped_info=nothing so it doesn't go in a Computer() + # @warn "Got variables that don't exist, running outside of computer" not_existing=filter(name -> !isdefined(m, name), computer.input_globals) + run_expression(m, original_expr, notebook_id, cell_id; user_requested_run) + else + run_inside_trycatch(m, () -> compute(m, computer)) + end - ans, add_runtimes(runtime, expansion_runtime) + ans, add_runtimes(runtime, expansion_runtime) + end end + + currently_running_cell_id[] = old_currently_running_cell_id + if (result isa CapturedException) && (result.ex isa InterruptException) throw(result.ex) @@ -549,6 +634,7 @@ function run_expression(m::Module, expr::Any, cell_id::UUID, function_wrapped_in cell_results[cell_id], cell_runtimes[cell_id] = result, runtime end +precompile(run_expression, (Module, Expr, UUID, UUID, Nothing, Nothing)) # Channel to trigger implicits run const run_channel = Channel{UUID}(10) @@ -563,7 +649,6 @@ function rerun_cell_from_notebook(cell_id::UUID) push!(new_uuids, uuid) end end - size = length(new_uuids) for uuid in new_uuids put!(run_channel, uuid) end @@ -575,12 +660,12 @@ end - - ### # DELETING GLOBALS ### +# This function checks whether the symbol provided to it represents a name of a memoized_cache variable from Memoize.jl, see https://github.com/fonsp/Pluto.jl/issues/2305 for more details +is_memoized_cache(s::Symbol) = startswith(string(s), "##") && endswith(string(s), "_memoized_cache") function do_reimports(workspace_name, module_imports_to_move::Set{Expr}) for expr in module_imports_to_move @@ -597,14 +682,26 @@ Notebook code does run in `Main` - it runs in workspace modules. Every time that The trick boils down to two things: 1. When we create a new workspace module, we move over some of the global from the old workspace. (But not the ones that we want to 'delete'!) -2. If a function used to be defined, but now we want to delete it, then we go through the method table of that function and snoop out all methods that we defined by us, and not by another package. This is how we reverse extending external functions. For example, if you run a cell with `Base.sqrt(s::String) = "the square root of" * s`, and then delete that cell, then you can still call `sqrt(1)` but `sqrt("one")` will err. Cool right! +2. If a function used to be defined, but now we want to delete it, then we go through the method table of that function and snoop out all methods that were defined by us, and not by another package. This is how we reverse extending external functions. For example, if you run a cell with `Base.sqrt(s::String) = "the square root of" * s`, and then delete that cell, then you can still call `sqrt(1)` but `sqrt("one")` will err. Cool right! """ -function move_vars(old_workspace_name::Symbol, new_workspace_name::Symbol, vars_to_delete::Set{Symbol}, methods_to_delete::Set{Tuple{UUID,Vector{Symbol}}}, module_imports_to_move::Set{Expr}) +function move_vars( + old_workspace_name::Symbol, + new_workspace_name::Symbol, + vars_to_delete::Set{Symbol}, + methods_to_delete::Set{Tuple{UUID,Tuple{Vararg{Symbol}}}}, + module_imports_to_move::Set{Expr}, + invalidated_cell_uuids::Set{UUID}, + keep_registered::Set{Symbol}, +) old_workspace = getfield(Main, old_workspace_name) new_workspace = getfield(Main, new_workspace_name) do_reimports(new_workspace, module_imports_to_move) + for uuid in invalidated_cell_uuids + pop!(cell_expanded_exprs, uuid, nothing) + end + # TODO: delete Core.eval(new_workspace, :(import ..($(old_workspace_name)))) @@ -618,6 +715,10 @@ function move_vars(old_workspace_name::Symbol, new_workspace_name::Symbol, vars_ if (symbol ∈ vars_to_delete) || (symbol ∈ name_symbols_of_funcs_with_no_methods_left) # var will be redefined - unreference the value so that GC can snoop it + if haskey(registered_bond_elements, symbol) && symbol ∉ keep_registered + delete!(registered_bond_elements, symbol) + end + # free memory for other variables # & delete methods created in the old module: # for example, the old module might extend an imported function: @@ -628,15 +729,19 @@ function move_vars(old_workspace_name::Symbol, new_workspace_name::Symbol, vars_ try # We are clearing this variable from the notebook, so we need to find it's root - # Just clearing out the definition in the old_module, besides giving an error (so that's what that `catch; end` is for) + # If its root is "controlled" by Pluto's workspace system (and is not a package module for example), + # we are just clearing out the definition in the old_module, besides giving an error + # (so that's what that `catch; end` is for) # will not actually free it from Julia, the older module will still have a reference. module_to_remove_from = which(old_workspace, symbol) - Core.eval(module_to_remove_from, :($(symbol) = nothing)) + if is_pluto_controlled(module_to_remove_from) && !isconst(module_to_remove_from, symbol) + Core.eval(module_to_remove_from, :($(symbol) = nothing)) + end catch; end # sometimes impossible, eg. when $symbol was constant end else # var will not be redefined in the new workspace, move it over - if !(symbol == :eval || symbol == :include || string(symbol)[1] == '#' || startswith(string(symbol), "workspace#")) + if !(symbol == :eval || symbol == :include || (string(symbol)[1] == '#' && !is_memoized_cache(symbol)) || startswith(string(symbol), "workspace#")) try getfield(old_workspace, symbol) @@ -645,7 +750,7 @@ function move_vars(old_workspace_name::Symbol, new_workspace_name::Symbol, vars_ catch ex if !(ex isa UndefVarError) @warn "Failed to move variable $(symbol) to new workspace:" - showerror(stderr, ex, stacktrace(catch_backtrace())) + showerror(original_stderr, ex, stacktrace(catch_backtrace())) end end end @@ -658,9 +763,33 @@ end "Return whether the `method` was defined inside this notebook, and not in external code." isfromcell(method::Method, cell_id::UUID) = endswith(String(method.file), string(cell_id)) -"Delete all methods of `f` that were defined in this notebook, and leave the ones defined in other packages, base, etc. ✂ +""" + delete_method_doc(m::Method) + +Tries to delete the documentation for this method, this is used when methods are removed. +""" +function delete_method_doc(m::Method) + binding = Docs.Binding(m.module, m.name) + meta = Docs.meta(m.module) + if haskey(meta, binding) + method_sig = Tuple{m.sig.parameters[2:end]...} + multidoc = meta[binding] + filter!(multidoc.order) do msig + if method_sig == msig + pop!(multidoc.docs, msig) + false + else + true + end + end + end +end + +""" +Delete all methods of `f` that were defined in this notebook, and leave the ones defined in other packages, base, etc. ✂ -Return whether the function has any methods left after deletion." +Return whether the function has any methods left after deletion. +""" function delete_toplevel_methods(f::Function, cell_id::UUID)::Bool # we can delete methods of functions! # instead of deleting all methods, we only delete methods that were defined in this notebook. This is necessary when the notebook code extends a function from remote code @@ -669,6 +798,7 @@ function delete_toplevel_methods(f::Function, cell_id::UUID)::Bool Base.visit(methods_table) do method # iterates through all methods of `f`, including overridden ones if isfromcell(method, cell_id) && getfield(method, deleted_world) == alive_world_val Base.delete_method(method) + delete_method_doc(method) push!(deleted_sigs, method.sig) end end @@ -699,7 +829,7 @@ end # try_delete_toplevel_methods(workspace, [name]) # end -function try_delete_toplevel_methods(workspace::Module, (cell_id, name_parts)::Tuple{UUID,Vector{Symbol}})::Bool +function try_delete_toplevel_methods(workspace::Module, (cell_id, name_parts)::Tuple{UUID,Tuple{Vararg{Symbol}}})::Bool try val = workspace for name in name_parts @@ -709,7 +839,7 @@ function try_delete_toplevel_methods(workspace::Module, (cell_id, name_parts)::T (val isa Function) && delete_toplevel_methods(val, cell_id) catch ex @warn "Failed to delete methods for $(name_parts)" - showerror(stderr, ex, stacktrace(catch_backtrace())) + showerror(original_stderr, ex, stacktrace(catch_backtrace())) false end catch @@ -759,13 +889,18 @@ const table_column_display_limit_increase = 30 const tree_display_extra_items = Dict{UUID,Dict{ObjectDimPair,Int64}}() +# This is not a struct to make it easier to pass these objects between processes. +const FormattedCellResult = NamedTuple{(:output_formatted, :errored, :interrupted, :process_exited, :runtime, :published_objects, :has_pluto_hook_features),Tuple{PlutoRunner.MimedOutput,Bool,Bool,Bool,Union{UInt64,Nothing},Dict{String,Any},Bool}} + function formatted_result_of( + notebook_id::UUID, cell_id::UUID, ends_with_semicolon::Bool, known_published_objects::Vector{String}=String[], showmore::Union{ObjectDimPair,Nothing}=nothing, - workspace::Module=Main, -)::NamedTuple{(:output_formatted, :errored, :interrupted, :process_exited, :runtime, :published_objects, :has_pluto_hook_features),Tuple{PlutoRunner.MimedOutput,Bool,Bool,Bool,Union{UInt64,Nothing},Dict{String,Any},Bool}} + workspace::Module=Main; + capture_stdout::Bool=true, +)::FormattedCellResult load_integrations_if_needed() currently_running_cell_id[] = cell_id @@ -782,27 +917,36 @@ function formatted_result_of( errored = ans isa CapturedException output_formatted = if (!ends_with_semicolon || errored) - format_output(ans; context=IOContext(default_iocontext, :extra_items=>extra_items, :module => workspace)) + logger = get!(() -> PlutoCellLogger(notebook_id, cell_id), pluto_cell_loggers, cell_id) + with_logger_and_io_to_logs(logger; capture_stdout, stdio_loglevel=stdout_log_level) do + format_output(ans; context=IOContext( + default_iocontext, + :extra_items=>extra_items, + :module => workspace, + :pluto_notebook_id => notebook_id, + :pluto_cell_id => cell_id, + )) + end else ("", MIME"text/plain"()) end - + published_objects = get(cell_published_objects, cell_id, Dict{String,Any}()) - + for k in known_published_objects if haskey(published_objects, k) published_objects[k] = nothing end end - - return ( - output_formatted = output_formatted, - errored = errored, - interrupted = false, - process_exited = false, + + return (; + output_formatted, + errored, + interrupted = false, + process_exited = false, runtime = get(cell_runtimes, cell_id, nothing), - published_objects = published_objects, - has_pluto_hook_features = has_pluto_hook_features, + published_objects, + has_pluto_hook_features, ) end @@ -839,9 +983,23 @@ end Base.IOContext(io::IOContext, ::Nothing) = io "The `IOContext` used for converting arbitrary objects to pretty strings." -const default_iocontext = IOContext(devnull, :color => false, :limit => true, :displaysize => (18, 88), :is_pluto => true, :pluto_supported_integration_features => supported_integration_features) +const default_iocontext = IOContext(devnull, + :color => false, + :limit => true, + :displaysize => (18, 88), + :is_pluto => true, + :pluto_supported_integration_features => supported_integration_features, + :pluto_published_to_js => (io, x) -> core_published_to_js(io, x), +) -const imagemimes = [MIME"image/svg+xml"(), MIME"image/png"(), MIME"image/jpg"(), MIME"image/jpeg"(), MIME"image/bmp"(), MIME"image/gif"()] +const default_stdout_iocontext = IOContext(devnull, + :color => true, + :limit => true, + :displaysize => (18, 75), + :is_pluto => false, +) + +const imagemimes = MIME[MIME"image/svg+xml"(), MIME"image/png"(), MIME"image/jpg"(), MIME"image/jpeg"(), MIME"image/bmp"(), MIME"image/gif"()] # in descending order of coolness # text/plain always matches - almost always """ @@ -849,7 +1007,7 @@ The MIMEs that Pluto supports, in order of how much I like them. `text/plain` should always match - the difference between `show(::IO, ::MIME"text/plain", x)` and `show(::IO, x)` is an unsolved mystery. """ -const allmimes = [MIME"application/vnd.pluto.table+object"(); MIME"application/vnd.pluto.divelement+object"(); MIME"text/html"(); imagemimes; MIME"application/vnd.pluto.tree+object"(); MIME"text/latex"(); MIME"text/plain"()] +const allmimes = MIME[MIME"application/vnd.pluto.table+object"(); MIME"application/vnd.pluto.divelement+object"(); MIME"text/html"(); imagemimes; MIME"application/vnd.pluto.tree+object"(); MIME"text/latex"(); MIME"text/plain"()] """ @@ -859,12 +1017,12 @@ See [`allmimes`](@ref) for the ordered list of supported MIME types. """ function format_output_default(@nospecialize(val), @nospecialize(context=default_iocontext))::MimedOutput try - io_sprinted, (value, mime) = sprint_withreturned(show_richest, val; context=context) + io_sprinted, (value, mime) = show_richest_withreturned(context, val) if value === nothing if mime ∈ imagemimes (io_sprinted, mime) else - (String(io_sprinted), mime) + (String(io_sprinted)::String, mime) end else (value, mime) @@ -880,53 +1038,218 @@ format_output(@nospecialize(x); context=default_iocontext) = format_output_defau format_output(::Nothing; context=default_iocontext) = ("", MIME"text/plain"()) +"Downstream packages can set this to false to obtain unprettified stack traces." +const PRETTY_STACKTRACES = Ref(true) + +# @codemirror/lint has only three levels +function convert_julia_syntax_level(level) + level == :error ? "error" : + level == :warning ? "warning" : "info" +end + +""" + map_byte_range_to_utf16_codepoints(s::String, start_byte::Int, end_byte::Int)::Tuple{Int,Int} + +Taken from `Base.transcode(::Type{UInt16}, src::Vector{UInt8})` +but without line constraints. It also does not support invalid +UTF-8 encoding which `String` should never be anyway. + +This maps the given raw byte range `(start_byte, end_byte)` range to UTF-16 codepoints indices. + +The resulting range can then be used by code-mirror on the frontend, quoting from the code-mirror docs: + +> Character positions are counted from zero, and count each line break and UTF-16 code unit as one unit. + +Examples: +```julia + 123 + vv +julia> map_byte_range_to_utf16_codepoints("abc", 2, 3) +(2, 3) + + 1122 + v v +julia> map_byte_range_to_utf16_codepoints("🍕🍕", 1, 8) +(1, 4) + + 11233 + v v +julia> map_byte_range_to_utf16_codepoints("🍕c🍕", 1, 5) +(1, 3) +``` +""" +function map_byte_range_to_utf16_codepoints(s, start_byte, end_byte) + invalid_utf8() = error("invalid UTF-8 string") + codeunit(s) == UInt8 || invalid_utf8() + + i, n = 1, ncodeunits(s) + u16 = 0 + + from, to = -1, -1 + a = codeunit(s, 1) + while true + if i == start_byte + from = u16 + end + if i == end_byte + to = u16 + break + end + if i < n && -64 <= a % Int8 <= -12 # multi-byte character + i += 1 + b = codeunit(s, i) + if -64 <= (b % Int8) || a == 0xf4 && 0x8f < b + # invalid UTF-8 (non-continuation of too-high code point) + invalid_utf8() + elseif a < 0xe0 # 2-byte UTF-8 + if i == start_byte + from = u16 + end + if i == end_byte + to = u16 + break + end + elseif i < n # 3/4-byte character + i += 1 + c = codeunit(s, i) + if -64 <= (c % Int8) # invalid UTF-8 (non-continuation) + invalid_utf8() + elseif a < 0xf0 # 3-byte UTF-8 + if i == start_byte + from = u16 + end + if i == end_byte + to = u16 + break + end + elseif i < n + i += 1 + d = codeunit(s, i) + if -64 <= (d % Int8) # invalid UTF-8 (non-continuation) + invalid_utf8() + elseif a == 0xf0 && b < 0x90 # overlong encoding + invalid_utf8() + else # 4-byte UTF-8 && 2 codeunits UTF-16 + u16 += 1 + if i == start_byte + from = u16 + end + if i == end_byte + to = u16 + break + end + end + else # too short + invalid_utf8() + end + else # too short + invalid_utf8() + end + else + # ASCII or invalid UTF-8 (continuation byte or too-high code point) + end + u16 += 1 + if i >= n + break + end + i += 1 + a = codeunit(s, i) + end + + if from == -1 + from = u16 + end + if to == -1 + to = u16 + end + + return (from, to) +end + +function convert_diagnostic_to_dict(source, diag) + code = source.code + + # JuliaSyntax uses `last_byte < first_byte` to signal an empty range. + # https://github.com/JuliaLang/JuliaSyntax.jl/blob/97e2825c68e770a3f56f0ec247deda1a8588070c/src/diagnostics.jl#L67-L75 + # it references the byte range as such: `source[first_byte:last_byte]` whereas codemirror + # is non inclusive, therefore we move the `last_byte` to the next valid character in the string, + # an empty range then becomes `from == to`, also JuliaSyntax is one based whereas code-mirror is zero-based + # but this is handled in `map_byte_range_to_utf16_codepoints` with `u16 = 0` initially. + first_byte = min(diag.first_byte, lastindex(code) + 1) + last_byte = min(nextind(code, diag.last_byte), lastindex(code) + 1) + + from, to = map_byte_range_to_utf16_codepoints(code, first_byte, last_byte) + + Dict(:from => from, + :to => to, + :message => diag.message, + :source => "JuliaSyntax.jl", + :line => first(Base.JuliaSyntax.source_location(source, diag.first_byte)), + :severity => convert_julia_syntax_level(diag.level)) +end + +function convert_parse_error_to_dict(ex) + Dict( + :source => ex.source.code, + :diagnostics => [ + convert_diagnostic_to_dict(ex.source, diag) + for diag in ex.diagnostics + ] + ) +end + +function throw_syntax_error(@nospecialize(syntax_err)) + syntax_err isa String && (syntax_err = "syntax: $syntax_err") + syntax_err isa Exception || (syntax_err = ErrorException(syntax_err)) + throw(syntax_err) +end + +const has_julia_syntax = isdefined(Base, :JuliaSyntax) && fieldcount(Base.Meta.ParseError) == 2 + function format_output(val::CapturedException; context=default_iocontext) - ## We hide the part of the stacktrace that belongs to Pluto's evalling of user code. - stack = [s for (s, _) in val.processed_bt] + if has_julia_syntax && val.ex isa Base.Meta.ParseError && val.ex.detail isa Base.JuliaSyntax.ParseError + dict = convert_parse_error_to_dict(val.ex.detail) + return dict, MIME"application/vnd.pluto.parseerror+object"() + end + + stacktrace = if PRETTY_STACKTRACES[] + ## We hide the part of the stacktrace that belongs to Pluto's evalling of user code. + stack = [s for (s, _) in val.processed_bt] - # function_wrap_index = findfirst(f -> occursin("function_wrapped_cell", String(f.func)), stack) + # function_wrap_index = findfirst(f -> occursin("function_wrapped_cell", String(f.func)), stack) - function_wrap_index = findlast(f -> occursin("#==#", String(f.file)), stack) + function_wrap_index = findlast(f -> occursin("#==#", String(f.file)), stack) - if function_wrap_index === nothing - for _ in 1:2 - until = findfirst(b -> b.func == :eval, reverse(stack)) - stack = until === nothing ? stack : stack[1:end - until] + if function_wrap_index === nothing + for _ in 1:2 + until = findfirst(b -> b.func == :eval, reverse(stack)) + stack = until === nothing ? stack : stack[1:end - until] + end + else + stack = stack[1:function_wrap_index] + end + + pretty = map(stack) do s + Dict( + :call => pretty_stackcall(s, s.linfo), + :inlined => s.inlined, + :file => basename(String(s.file)), + :path => String(s.file), + :line => s.line, + ) end else - stack = stack[1:function_wrap_index] + val end - pretty = map(stack) do s - Dict( - :call => pretty_stackcall(s, s.linfo), - :inlined => s.inlined, - :file => basename(String(s.file)), - :path => String(s.file), - :line => s.line, - ) - end - Dict{Symbol,Any}(:msg => sprint(try_showerror, val.ex), :stacktrace => pretty), MIME"application/vnd.pluto.stacktrace+object"() + Dict{Symbol,Any}(:msg => sprint(try_showerror, val.ex), :stacktrace => stacktrace), MIME"application/vnd.pluto.stacktrace+object"() end function format_output(binding::Base.Docs.Binding; context=default_iocontext) try (""" -
- $(binding.var) +
+ $(binding.var) $(repr(MIME"text/html"(), Base.Docs.doc(binding)))
""", MIME"text/html"()) @@ -961,11 +1284,19 @@ function pretty_stackcall(frame::Base.StackFrame, linfo::Core.MethodInstance) end end -"Like `Base.sprint`, but return a `(String, Any)` tuple containing function output as the second entry." -function sprint_withreturned(f::Function, args...; context=nothing, sizehint::Integer=0) - buffer = IOBuffer(sizehint=sizehint) - val = f(IOContext(buffer, context), args...) - resize!(buffer.data, buffer.size), val +function pretty_stackcall(frame::Base.StackFrame, linfo::Method) + sprint(Base.show_tuple_as_call, linfo.name, linfo.sig) +end + +function pretty_stackcall(frame::Base.StackFrame, linfo::Module) + sprint(Base.show, linfo) +end + +"Return a `(String, Any)` tuple containing function output as the second entry." +function show_richest_withreturned(context::IOContext, @nospecialize(args)) + buffer = IOBuffer(; sizehint=0) + val = show_richest(IOContext(buffer, context), args) + return (resize!(buffer.data, buffer.size), val) end "Super important thing don't change." @@ -993,6 +1324,24 @@ function use_tree_viewer_for_struct(@nospecialize(x::T))::Bool where T end end +""" + is_mime_enabled(::MIME) -> Bool + +Return whether the argument's mimetype is enabled. +This defaults to `true`, but additional dispatches can be set to `false` by downstream packages. +""" +is_mime_enabled(::MIME) = true + +"Return the first mimetype in `allmimes` which can show `x`." +function mimetype(x) + # ugly code to fix an ugly performance problem + for m in allmimes + if pluto_showable(m, x) && is_mime_enabled(m) + return m + end + end +end + """ Like two-argument `Base.show`, except: 1. the richest MIME type available to Pluto will be used @@ -1000,21 +1349,24 @@ Like two-argument `Base.show`, except: 3. if the first returned element is `nothing`, then we wrote our data to `io`. If it is something else (a Dict), then that object will be the cell's output, instead of the buffered io stream. This allows us to output rich objects to the frontend that are not necessarily strings or byte streams """ function show_richest(io::IO, @nospecialize(x))::Tuple{<:Any,MIME} - # ugly code to fix an ugly performance problem - local mime = nothing - for m in allmimes - if pluto_showable(m, x) - mime = m - break - end - end + mime = mimetype(x) - if mime isa MIME"text/plain" && use_tree_viewer_for_struct(x) + if mime isa MIME"text/plain" && is_mime_enabled(MIME"application/vnd.pluto.tree+object"()) && use_tree_viewer_for_struct(x) tree_data(x, io), MIME"application/vnd.pluto.tree+object"() elseif mime isa MIME"application/vnd.pluto.tree+object" - tree_data(x, IOContext(io, :compact => true)), mime + try + tree_data(x, IOContext(io, :compact => true)), mime + catch + show(io, MIME"text/plain"(), x) + nothing, MIME"text/plain"() + end elseif mime isa MIME"application/vnd.pluto.table+object" - table_data(x, IOContext(io, :compact => true)), mime + try + table_data(x, IOContext(io, :compact => true)), mime + catch + show(io, MIME"text/plain"(), x) + nothing, MIME"text/plain"() + end elseif mime isa MIME"application/vnd.pluto.divelement+object" tree_data(x, io), mime elseif mime ∈ imagemimes @@ -1047,7 +1399,7 @@ pluto_showable(m::MIME, @nospecialize(x))::Bool = Base.invokelatest(showable, m, # We invent our own MIME _because we can_ but don't use it somewhere else because it might change :) -pluto_showable(::MIME"application/vnd.pluto.tree+object", ::AbstractArray{<:Any,1}) = true +pluto_showable(::MIME"application/vnd.pluto.tree+object", x::AbstractVector{<:Any}) = try eltype(eachindex(x)) === Int; catch; false; end pluto_showable(::MIME"application/vnd.pluto.tree+object", ::AbstractSet{<:Any}) = true pluto_showable(::MIME"application/vnd.pluto.tree+object", ::AbstractDict{<:Any,<:Any}) = true pluto_showable(::MIME"application/vnd.pluto.tree+object", ::Tuple) = true @@ -1062,7 +1414,9 @@ pluto_showable(::MIME"application/vnd.pluto.tree+object", ::Any) = false # in the next functions you see a `context` argument # this is really only used for the circular reference tracking -function tree_data_array_elements(@nospecialize(x::AbstractArray{<:Any,1}), indices::AbstractVector{I}, context::IOContext)::Vector{Tuple{I,Any}} where {I<:Integer} +const Context = IOContext{IOBuffer} + +function tree_data_array_elements(@nospecialize(x::AbstractVector{<:Any}), indices::AbstractVector{I}, context::Context) where {I<:Integer} Tuple{I,Any}[ if isassigned(x, i) i, format_output_default(x[i], context) @@ -1072,17 +1426,18 @@ function tree_data_array_elements(@nospecialize(x::AbstractArray{<:Any,1}), indi for i in indices ] |> collect end +precompile(tree_data_array_elements, (Vector{Any}, Vector{Int}, Context)) -function array_prefix(@nospecialize(x::Array{<:Any,1}))::String - string(eltype(x)) +function array_prefix(@nospecialize(x::Vector{<:Any})) + string(eltype(x))::String end -function array_prefix(@nospecialize(x))::String - original = sprint(Base.showarg, x, false) - lstrip(original, ':') * ": " +function array_prefix(@nospecialize(x)) + original = sprint(Base.showarg, x, false; context=:limit => true) + string(lstrip(original, ':'), ": ")::String end -function get_my_display_limit(@nospecialize(x), dim::Integer, depth::Integer, context::IOContext, a::Integer, b::Integer)::Int # needs to be system-dependent Int because it is used as array index +function get_my_display_limit(@nospecialize(x), dim::Integer, depth::Integer, context::Context, a::Integer, b::Integer)::Int # needs to be system-dependent Int because it is used as array index let if depth < 3 a ÷ (1 + 2 * depth) @@ -1099,12 +1454,18 @@ function get_my_display_limit(@nospecialize(x), dim::Integer, depth::Integer, co end end -function tree_data(@nospecialize(x::AbstractSet{<:Any}), context::IOContext) +objectid2str(@nospecialize(x)) = string(objectid(x); base=16)::String + +function circular(@nospecialize(x)) + return Dict{Symbol,Any}( + :objectid => objectid2str(x), + :type => :circular + ) +end + +function tree_data(@nospecialize(x::AbstractSet{<:Any}), context::Context) if Base.show_circular(context, x) - Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), - :type => :circular, - ) + return circular(x) else depth = get(context, :tree_viewer_depth, 0) recur_io = IOContext(context, Pair{Symbol,Any}(:SHOWN_SET, x), Pair{Symbol,Any}(:tree_viewer_depth, depth + 1)) @@ -1127,21 +1488,18 @@ function tree_data(@nospecialize(x::AbstractSet{<:Any}), context::IOContext) Dict{Symbol,Any}( :prefix => string(typeof(x)), :prefix_short => string(typeof(x) |> trynameof), - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :Set, :elements => elements ) end end -function tree_data(@nospecialize(x::AbstractArray{<:Any,1}), context::IOContext) +function tree_data(@nospecialize(x::AbstractVector{<:Any}), context::Context) if Base.show_circular(context, x) - Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), - :type => :circular, - ) + return circular(x) else - depth = get(context, :tree_viewer_depth, 0) + depth = get(context, :tree_viewer_depth, 0)::Int recur_io = IOContext(context, Pair{Symbol,Any}(:SHOWN_SET, x), Pair{Symbol,Any}(:tree_viewer_depth, depth + 1)) indices = eachindex(x) @@ -1154,9 +1512,9 @@ function tree_data(@nospecialize(x::AbstractArray{<:Any,1}), context::IOContext) firsti = firstindex(x) from_end = my_limit > 20 ? 10 : my_limit > 1 ? 1 : 0 Any[ - tree_data_array_elements(x, indices[firsti:firsti-1+my_limit-from_end], recur_io)..., - "more", - tree_data_array_elements(x, indices[end+1-from_end:end], recur_io)..., + tree_data_array_elements(x, indices[firsti:firsti-1+my_limit-from_end], recur_io); + "more"; + tree_data_array_elements(x, indices[end+1-from_end:end], recur_io) ] end @@ -1164,30 +1522,32 @@ function tree_data(@nospecialize(x::AbstractArray{<:Any,1}), context::IOContext) Dict{Symbol,Any}( :prefix => prefix, :prefix_short => x isa Vector ? "" : prefix, # if not abstract - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :Array, :elements => elements ) end end -function tree_data(@nospecialize(x::Tuple), context::IOContext) +function tree_data(@nospecialize(x::Tuple), context::Context) depth = get(context, :tree_viewer_depth, 0) recur_io = IOContext(context, Pair{Symbol,Any}(:tree_viewer_depth, depth + 1)) + elements = Tuple[] + for val in x + out = format_output_default(val, recur_io) + push!(elements, out) + end Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :Tuple, - :elements => collect(enumerate(format_output_default.(x, [recur_io]))), + :elements => collect(enumerate(elements)), ) end -function tree_data(@nospecialize(x::AbstractDict{<:Any,<:Any}), context::IOContext) +function tree_data(@nospecialize(x::AbstractDict{<:Any,<:Any}), context::Context) if Base.show_circular(context, x) - Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), - :type => :circular, - ) + return circular(x) else depth = get(context, :tree_viewer_depth, 0) recur_io = IOContext(context, Pair{Symbol,Any}(:SHOWN_SET, x), Pair{Symbol,Any}(:tree_viewer_depth, depth + 1)) @@ -1210,47 +1570,50 @@ function tree_data(@nospecialize(x::AbstractDict{<:Any,<:Any}), context::IOConte Dict{Symbol,Any}( :prefix => string(typeof(x)), :prefix_short => string(typeof(x) |> trynameof), - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :Dict, :elements => elements ) end end -function tree_data_nt_row(pair::Tuple, context::IOContext) +function tree_data_nt_row(@nospecialize(pair::Tuple), context::Context) # this is an entry of a NamedTuple, the first element of the Tuple is a Symbol, which we want to print as `x` instead of `:x` k, element = pair string(k), format_output_default(element, context) end -function tree_data(@nospecialize(x::NamedTuple), context::IOContext) +function tree_data(@nospecialize(x::NamedTuple), context::Context) depth = get(context, :tree_viewer_depth, 0) recur_io = IOContext(context, Pair{Symbol,Any}(:tree_viewer_depth, depth + 1)) + elements = Tuple[] + for key in eachindex(x) + val = x[key] + data = tree_data_nt_row((key, val), recur_io) + push!(elements, data) + end Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :NamedTuple, - :elements => tree_data_nt_row.(zip(eachindex(x), x), (recur_io,)) + :elements => elements ) end -function tree_data(@nospecialize(x::Pair), context::IOContext) +function tree_data(@nospecialize(x::Pair), context::Context) k, v = x Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :type => :Pair, :key_value => (format_output_default(k, context), format_output_default(v, context)), ) end # Based on Julia source code but without writing to IO -function tree_data(@nospecialize(x::Any), context::IOContext) +function tree_data(@nospecialize(x::Any), context::Context) if Base.show_circular(context, x) - Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), - :type => :circular, - ) + return circular(x) else depth = get(context, :tree_viewer_depth, 0) recur_io = IOContext(context, @@ -1262,7 +1625,7 @@ function tree_data(@nospecialize(x::Any), context::IOContext) t = typeof(x) nf = nfields(x) nb = sizeof(x) - + elements = Any[ let f = fieldname(t, i) @@ -1277,9 +1640,9 @@ function tree_data(@nospecialize(x::Any), context::IOContext) ] Dict{Symbol,Any}( - :prefix => repr(t; context=context), - :prefix_short => string(t |> trynameof), - :objectid => string(objectid(x), base=16), + :prefix => repr(t; context), + :prefix_short => string(trynameof(t)), + :objectid => objectid2str(x), :type => :struct, :elements => elements, ) @@ -1316,20 +1679,32 @@ end # This is similar to how Requires.jl works, except we don't use a callback, we just check every time. const integrations = Integration[ Integration( - id = Base.PkgId(Base.UUID(reinterpret(Int128, codeunits("Paul Berg Berlin")) |> first), "AbstractPlutoDingetjes"), + id = Base.PkgId(Base.UUID(reinterpret(UInt128, codeunits("Paul Berg Berlin")) |> first), "AbstractPlutoDingetjes"), code = quote @assert v"1.0.0" <= AbstractPlutoDingetjes.MY_VERSION < v"2.0.0" - initial_value_getter_ref[] = AbstractPlutoDingetjes.Bonds.initial_value - transform_value_ref[] = AbstractPlutoDingetjes.Bonds.transform_value - possible_bond_values_ref[] = AbstractPlutoDingetjes.Bonds.possible_values - - push!(supported_integration_features, + + supported!(xs...) = append!(supported_integration_features, xs) + + # don't need feature checks for these because they existed in every version of AbstractPlutoDingetjes: + supported!( AbstractPlutoDingetjes, AbstractPlutoDingetjes.Bonds, AbstractPlutoDingetjes.Bonds.initial_value, AbstractPlutoDingetjes.Bonds.transform_value, AbstractPlutoDingetjes.Bonds.possible_values, ) + initial_value_getter_ref[] = AbstractPlutoDingetjes.Bonds.initial_value + transform_value_ref[] = AbstractPlutoDingetjes.Bonds.transform_value + possible_bond_values_ref[] = AbstractPlutoDingetjes.Bonds.possible_values + + # feature checks because these were added in a later release of AbstractPlutoDingetjes + if isdefined(AbstractPlutoDingetjes, :Display) + supported!(AbstractPlutoDingetjes.Display) + if isdefined(AbstractPlutoDingetjes.Display, :published_to_js) + supported!(AbstractPlutoDingetjes.Display.published_to_js) + end + end + end, ), Integration( @@ -1354,9 +1729,8 @@ const integrations = Integration[ end end - function table_data(x::Any, io::IOContext) + function table_data(x::Any, io::Context) rows = Tables.rows(x) - my_row_limit = get_my_display_limit(x, 1, 0, io, table_row_display_limit, table_row_display_limit_increase) # TODO: the commented line adds support for lazy loading columns, but it uses the same extra_items counter as the rows. So clicking More Rows will also give more columns, and vice versa, which isn't ideal. To fix, maybe use (objectid,dimension) as index instead of (objectid)? @@ -1382,15 +1756,18 @@ const integrations = Integration[ # not enumerate(rows) because of some silliness # not rows[i] because `getindex` is not guaranteed to exist L = truncate_rows ? my_row_limit : length(rows) - row_data = Array{Any,1}(undef, L) + row_data = Vector{Any}(undef, L) for (i, row) in zip(1:L,rows) row_data[i] = (i, row_data_for(row)) end if truncate_rows push!(row_data, "more") - if applicable(lastindex, rows) - push!(row_data, (length(rows), row_data_for(last(rows)))) + + # In some environments this fails. Not sure why. + last_row = applicable(lastindex, rows) ? try last(rows) catch e nothing end : nothing + if !isnothing(last_row) + push!(row_data, (length(rows), row_data_for(last_row))) end end @@ -1403,17 +1780,23 @@ const integrations = Integration[ ) Dict{Symbol,Any}( - :objectid => string(objectid(x), base=16), + :objectid => objectid2str(x), :schema => schema_data, :rows => row_data, ) end + #= + If the object we're trying to fileview provides rowaccess, let's try to show it. This is guaranteed to be fast + (while Table.rows() may be slow). If the object is a lazy iterator, the show method will probably crash and return text repr. + That's good because we don't want the show method of lazy iterators (e.g. database cursors) to be changing the (external) + iterator implicitly =# pluto_showable(::MIME"application/vnd.pluto.table+object", x::Any) = try Tables.rowaccess(x)::Bool catch; false end pluto_showable(::MIME"application/vnd.pluto.table+object", t::Type) = false pluto_showable(::MIME"application/vnd.pluto.table+object", t::AbstractVector{<:NamedTuple}) = false pluto_showable(::MIME"application/vnd.pluto.table+object", t::AbstractVector{<:Dict{Symbol,<:Any}}) = false + pluto_showable(::MIME"application/vnd.pluto.table+object", t::AbstractVector{Union{}}) = false end, ), @@ -1421,18 +1804,34 @@ const integrations = Integration[ id = Base.PkgId(UUID("91a5bcdd-55d7-5caf-9e0b-520d859cae80"), "Plots"), code = quote approx_size(p::Plots.Plot) = try - sum(p.series_list) do series - length(series[:y]) + sum(p.series_list; init=0) do series + length(something(get(series, :y, ()), ())) end catch e @warn "Failed to guesstimate plot size" exception=(e,catch_backtrace()) 0 end const max_plot_size = 8000 - pluto_showable(::MIME"image/svg+xml", p::Plots.Plot{Plots.GRBackend}) = approx_size(p) <= max_plot_size + function pluto_showable(::MIME"image/svg+xml", p::Plots.Plot{Plots.GRBackend}) + format = try + p.attr[:html_output_format] + catch + :auto + end + + format === :svg || ( + format === :auto && approx_size(p) <= max_plot_size + ) + end pluto_showable(::MIME"text/html", p::Plots.Plot{Plots.GRBackend}) = false end, - ) + ), + Integration( + id = Base.PkgId(UUID("4e3cecfd-b093-5904-9786-8bbb286a6a31"), "ImageShow"), + code = quote + pluto_showable(::MIME"text/html", ::AbstractMatrix{<:ImageShow.Colorant}) = false + end, + ), ] function load_integration_if_needed(integration::Integration) @@ -1487,9 +1886,46 @@ catch end completion_description(::Completion) = nothing +completion_detail(::Completion) = nothing +completion_detail(completion::BslashCompletion) = + haskey(REPL.REPLCompletions.latex_symbols, completion.bslash) ? + REPL.REPLCompletions.latex_symbols[completion.bslash] : + haskey(REPL.REPLCompletions.emoji_symbols, completion.bslash) ? + REPL.REPLCompletions.emoji_symbols[completion.bslash] : + nothing + function is_pluto_workspace(m::Module) - mod_name = nameof(m) |> string - startswith(mod_name, "workspace#") + isdefined(m, PLUTO_INNER_MODULE_NAME) && + which(m, PLUTO_INNER_MODULE_NAME) == m +end + +""" +Returns wether the module is a pluto workspace or any of its ancestors is. + +For example, writing the following julia code in Pluto: + +```julia +import Plots + +module A +end +``` + +will give the following module tree: + +``` +Main (not pluto controlled) +└── var"workspace#1" (pluto controlled) + └── A (pluto controlled) +└── var"workspace#2" (pluto controlled) + └── A (pluto controlled) +Plots (not pluto controlled) +``` +""" +function is_pluto_controlled(m::Module) + is_pluto_workspace(m) && return true + parent = parentmodule(m) + parent != m && is_pluto_controlled(parent) end function completions_exported(cs::Vector{<:Completion}) @@ -1505,12 +1941,16 @@ function completions_exported(cs::Vector{<:Completion}) end end -completion_from_notebook(c::ModuleCompletion) = is_pluto_workspace(c.parent) && c.mod != "include" && c.mod != "eval" +completion_from_notebook(c::ModuleCompletion) = + is_pluto_workspace(c.parent) && + c.mod != "include" && + c.mod != "eval" && + !startswith(c.mod, "#") completion_from_notebook(c::Completion) = false -only_special_completion_types(c::PathCompletion) = :path -only_special_completion_types(c::DictCompletion) = :dict -only_special_completion_types(c::Completion) = nothing +only_special_completion_types(::PathCompletion) = :path +only_special_completion_types(::DictCompletion) = :dict +only_special_completion_types(::Completion) = nothing "You say Linear, I say Algebra!" function completion_fetcher(query, pos, workspace::Module) @@ -1530,13 +1970,16 @@ function completion_fetcher(query, pos, workspace::Module) filter!(isenough ∘ score, results) # too many candiates otherwise end - texts = completion_text.(results) - descriptions = completion_description.(results) exported = completions_exported(results) - from_notebook = completion_from_notebook.(results) - completion_type = only_special_completion_types.(results) - - smooshed_together = collect(zip(texts, descriptions, exported, from_notebook, completion_type)) + smooshed_together = [ + (completion_text(result), + completion_description(result), + rexported, + completion_from_notebook(result), + only_special_completion_types(result), + completion_detail(result)) + for (result, rexported) in zip(results, exported) + ] p = if endswith(query, '.') sortperm(smooshed_together; alg=MergeSort, by=basic_completion_priority) @@ -1546,8 +1989,8 @@ function completion_fetcher(query, pos, workspace::Module) sortperm(scores .+ 3.0 * exported; alg=MergeSort, rev=true) end - final = smooshed_together[p] - (final, loc, found) + permute!(smooshed_together, p) + (smooshed_together, loc, found) end is_dot_completion(::Union{ModuleCompletion,PropertyCompletion,FieldCompletion}) = true @@ -1604,24 +2047,99 @@ binding_from(s::Symbol, workspace::Module) = Docs.Binding(workspace, s) binding_from(r::GlobalRef, workspace::Module) = Docs.Binding(r.mod, r.name) binding_from(other, workspace::Module) = error("Invalid @var syntax `$other`.") +const DOC_SUGGESTION_LIMIT = 10 + +struct Suggestion + match::String + query::String +end + +# inspired from REPL.printmatch() +function Base.show(io::IO, ::MIME"text/html", suggestion::Suggestion) + print(io, "") + is, _ = REPL.bestmatch(suggestion.query, suggestion.match) + for (i, char) in enumerate(suggestion.match) + esc_c = get(Markdown._htmlescape_chars, char, char) + if i in is + print(io, "", esc_c, "") + else + print(io, esc_c) + end + end + print(io, "") +end + "You say doc_fetcher, I say You say doc_fetcher, I say You say doc_fetcher, I say You say doc_fetcher, I say ...!!!!" function doc_fetcher(query, workspace::Module) try - value = binding_from(Meta.parse(query), workspace) - doc_md = Docs.doc(value) + parsed_query = Meta.parse(query; raise=false, depwarn=false) + + doc_md = if Meta.isexpr(parsed_query, (:incomplete, :error, :return)) && haskey(Docs.keywords, Symbol(query)) + Docs.parsedoc(Docs.keywords[Symbol(query)]) + else + binding = binding_from(parsed_query, workspace) + doc_md = Docs.doc(binding) + + if !showable(MIME("text/html"), doc_md) + # PyPlot returns `Text{String}` objects from their docs... + # which is a bit silly, but turns out it actuall is markdown if you look hard enough. + doc_md = Markdown.parse(repr(doc_md)) + end - if !showable(MIME("text/html"), doc_md) - # PyPlot returns `Text{String}` objects from their docs... - # which is a bit silly, but turns out it actuall is markdown if you look hard enough. - doc_md = Markdown.parse(repr(doc_md)) + improve_docs!(doc_md, parsed_query, binding) end - + (repr(MIME("text/html"), doc_md), :👍) catch ex (nothing, :👎) end end +function improve_docs!(doc_md::Markdown.MD, query::Symbol, binding::Docs.Binding) + # Reverse latex search ("\scrH" -> "\srcH") + + symbol = string(query) + latex = REPL.symbol_latex(symbol) + + if !isempty(latex) + push!(doc_md.content, + Markdown.HorizontalRule(), + Markdown.Paragraph([ + Markdown.Code(symbol), + " can be typed by ", + Markdown.Code(latex), + Base.Docs.HTML("<tab>"), + ".", + ])) + end + + # Add suggestions results if no docstring was found + + if !Docs.defined(binding) && + haskey(doc_md.meta, :results) && + isempty(doc_md.meta[:results]) + + suggestions = REPL.accessible(binding.mod) + suggestions_scores = map(s -> REPL.fuzzyscore(symbol, s), suggestions) + removed_indices = [i for (i, s) in enumerate(suggestions_scores) if s < 0] + deleteat!(suggestions_scores, removed_indices) + deleteat!(suggestions, removed_indices) + + perm = sortperm(suggestions_scores; rev=true) + permute!(suggestions, perm) + links = map(s -> Suggestion(s, symbol), @view(suggestions[begin:min(end,DOC_SUGGESTION_LIMIT)])) + + if length(links) > 0 + push!(doc_md.content, + Markdown.HorizontalRule(), + Markdown.Paragraph(["Similar result$(length(links) > 1 ? "s" : ""):"]), + Markdown.List(links)) + end + end + + doc_md +end +improve_docs!(other, _, _) = other @@ -1650,11 +2168,21 @@ function transform_bond_value(s::Symbol, value_from_js) return try transform_value_ref[](element, value_from_js) catch e - @error "AbstractPlutoDingetjes: Bond value transformation errored." exception=(e, catch_backtrace()) - (Text("❌ AbstractPlutoDingetjes: Bond value transformation errored."), e, stacktrace(catch_backtrace()), value_from_js) + @error "🚨 AbstractPlutoDingetjes: Bond value transformation errored." exception=(e, catch_backtrace()) + (; + message=Text("🚨 AbstractPlutoDingetjes: Bond value transformation errored."), + exception=Text( + sprint(showerror, e, stacktrace(catch_backtrace())) + ), + value_from_js, + ) end end +function get_bond_names(cell_id) + get(cell_registered_bond_names, cell_id, Set{Symbol}()) +end + function possible_bond_values(s::Symbol; get_length::Bool=false) element = registered_bond_elements[s] possible_values = possible_bond_values_ref[](element) @@ -1675,15 +2203,15 @@ function possible_bond_values(s::Symbol; get_length::Bool=false) try length(possible_values) catch - length(make_distributed_serializable(possible_values)) + length(make_serializable(possible_values)) end : - make_distributed_serializable(possible_values) + make_serializable(possible_values) end end -make_distributed_serializable(x::Any) = x -make_distributed_serializable(x::Union{AbstractVector,AbstractSet,Base.Generator}) = collect(x) -make_distributed_serializable(x::Union{Vector,Set,OrdinalRange}) = x +make_serializable(x::Any) = x +make_serializable(x::Union{AbstractVector,AbstractSet,Base.Generator}) = collect(x) +make_serializable(x::Union{Vector,Set,OrdinalRange}) = x """ @@ -1710,19 +2238,19 @@ The actual reactive-interactive functionality is not done in Julia - it is handl struct Bond element::Any defines::Symbol - Bond(element, defines::Symbol) = showable(MIME"text/html"(), element) ? new(element, defines) : error("""Can only bind to html-showable objects, ie types T for which show(io, ::MIME"text/html", x::T) is defined.""") + unique_id::String + Bond(element, defines::Symbol) = showable(MIME"text/html"(), element) ? new(element, defines, Base64.base64encode(rand(UInt8,9))) : error("""Can only bind to html-showable objects, ie types T for which show(io, ::MIME"text/html", x::T) is defined.""") end -function create_bond(element, defines::Symbol) - push!(cell_registered_bond_names[currently_running_cell_id[]], defines) +function create_bond(element, defines::Symbol, cell_id::UUID) + push!(cell_registered_bond_names[cell_id], defines) registered_bond_elements[defines] = element Bond(element, defines) end -import Base: show -function show(io::IO, ::MIME"text/html", bond::Bond) - withtag(io, :bond, :def => bond.defines) do - show(io, MIME"text/html"(), bond.element) +function Base.show(io::IO, m::MIME"text/html", bond::Bond) + withtag(io, :bond, :def => bond.defines, :unique_id => bond.unique_id) do + show(io, m, bond.element) end end @@ -1731,7 +2259,9 @@ const transform_value_ref = Ref{Function}((element, x) -> x) const possible_bond_values_ref = Ref{Function}((_args...; _kwargs...) -> :NotGiven) """ - `@bind symbol element` +```julia +@bind symbol element +``` Return the HTML `element`, and use its latest JavaScript value as the definition of `symbol`. @@ -1751,10 +2281,10 @@ The second cell will show the square of `x`, and is updated in real-time as the macro bind(def, element) if def isa Symbol quote - $(load_integrations_if_needed)() + $(load_integrations_if_needed)() local el = $(esc(element)) - global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : $(initial_value_getter_ref)[](el) - PlutoRunner.create_bond(el, $(Meta.quot(def))) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : $(initial_value_getter_ref)[](el) + PlutoRunner.create_bond(el, $(Meta.quot(def)), $(GiveMeCellID())) end else :(throw(ArgumentError("""\nMacro example usage: \n\n\t@bind my_number html""\n\n"""))) @@ -1795,72 +2325,48 @@ end""" """ const currently_running_cell_id = Ref{UUID}(uuid4()) -function _publish(x, id_start)::String +function core_published_to_js(io, x) assertpackable(x) + + id_start = objectid2str(x) + + _notebook_id = get(io, :pluto_notebook_id, notebook_id[])::UUID + _cell_id = get(io, :pluto_cell_id, currently_running_cell_id[])::UUID + + # The unique identifier of this object + id = "$_notebook_id/$id_start" - id = string(notebook_id[], "/", currently_running_cell_id[], "/", id_start) - d = get!(Dict{String,Any}, cell_published_objects, currently_running_cell_id[]) + d = get!(Dict{String,Any}, cell_published_objects, _cell_id) d[id] = x - return id + + write(io, "/* See the documentation for AbstractPlutoDingetjes.Display.published_to_js */ getPublishedObject(\"$(id)\")") + + return nothing end -_publish(x) = _publish(x, string(objectid(x), base=16)) - -# TODO? Possibly move this to it's own package, with fallback that actually msgpack? -# ..... Ideally we'd make this require `await` on the javascript side too... -Base.@kwdef struct PublishedToJavascript - published_id - cell_id +# TODO: This is the deprecated old function. Remove me at some point. +struct PublishedToJavascript + published_object end function Base.show(io::IO, ::MIME"text/javascript", published::PublishedToJavascript) - if published.cell_id != currently_running_cell_id[] - error("Showing result from PlutoRunner.publish_to_js() in a cell different from where it was created, not (yet?) supported.") - end - write(io, "/* See the documentation for PlutoRunner.publish_to_js */ getPublishedObject(\"$(published.published_id)\")") + core_published_to_js(io, published.published_object) end Base.show(io::IO, ::MIME"text/plain", published::PublishedToJavascript) = show(io, MIME("text/javascript"), published) Base.show(io::IO, published::PublishedToJavascript) = show(io, MIME("text/javascript"), published) -""" - publish_to_js(x) - -Make the object `x` available to the JS runtime of this cell. The returned string is a JS command that, when executed in this cell's output, gives the object. +# TODO: This is the deprecated old function. Remove me at some point. +function publish_to_js(x) + @warn "Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`." -!!! warning - - This function is not yet public API, it will become public in the next weeks. Only use for experiments. - -# Example -```julia -let - x = Dict( - "data" => rand(Float64, 20), - "name" => "juliette", - ) - - HTML("\"" - - "\"") -end -``` -""" -function publish_to_js(args...) - PublishedToJavascript( - published_id=_publish(args...), - cell_id=currently_running_cell_id[], - ) + assertpackable(x) + PublishedToJavascript(x) end const Packable = Union{Nothing,Missing,String,Symbol,Int64,Int32,Int16,Int8,UInt64,UInt32,UInt16,UInt8,Float32,Float64,Bool,MIME,UUID,DateTime} -assertpackable(::Packable) = true +assertpackable(::Packable) = nothing assertpackable(t::Any) = throw(ArgumentError("Only simple objects can be shared with JS, like vectors and dictionaries. $(string(typeof(t))) is not compatible.")) -assertpackable(::Vector{<:Packable}) = true -assertpackable(::Dict{<:Packable,<:Packable}) = true +assertpackable(::Vector{<:Packable}) = nothing +assertpackable(::Dict{<:Packable,<:Packable}) = nothing assertpackable(x::Vector) = foreach(assertpackable, x) assertpackable(d::Dict) = let foreach(assertpackable, keys(d)) @@ -1887,7 +2393,7 @@ function Base.show(io::IO, m::MIME"text/html", e::EmbeddableDisplay) // see https://plutocon2021-demos.netlify.app/fonsp%20%E2%80%94%20javascript%20inside%20pluto to learn about the techniques used in this script - const body = $(publish_to_js(body, e.script_id)); + const body = $(PublishedToJavascript(body)); const mime = "$(string(mime))"; const create_new = this == null || this._mime !== mime; @@ -1895,6 +2401,7 @@ function Base.show(io::IO, m::MIME"text/html", e::EmbeddableDisplay) const display = create_new ? currentScript.previousElementSibling : this; display.persist_js_state = true; + display.sanitize_html = false; display.body = body; if(create_new) { // only set the mime if necessary, it triggers a second preact update @@ -1966,7 +2473,7 @@ Base.@kwdef struct DivElement class::Union{String,Nothing}=nothing end -tree_data(@nospecialize(e::DivElement), context::IOContext) = Dict{Symbol, Any}( +tree_data(@nospecialize(e::DivElement), context::Context) = Dict{Symbol, Any}( :style => e.style, :classname => e.class, :children => Any[ @@ -1983,45 +2490,213 @@ end # LOGGING ### -const log_channel = Channel{Any}(10) -const old_logger = Ref{Any}(nothing) +const original_stdout = stdout +const original_stderr = stderr + +const old_logger = Ref{Union{Logging.AbstractLogger,Nothing}}(nothing) -struct PlutoLogger <: Logging.AbstractLogger +struct PlutoCellLogger <: Logging.AbstractLogger + stream # some packages expect this field to exist... + log_channel::Channel{Any} + cell_id::UUID + workspace_count::Int # Used to invalidate previous logs + message_limits::Dict{Any,Int} +end +function PlutoCellLogger(notebook_id, cell_id) + notebook_log_channel = pluto_log_channels[notebook_id] + PlutoCellLogger(nothing, + notebook_log_channel, cell_id, + moduleworkspace_count[], + Dict{Any,Int}()) +end + +struct CaptureLogger <: Logging.AbstractLogger stream + logger::PlutoCellLogger + logs::Vector{Any} +end + +Logging.shouldlog(cl::CaptureLogger, args...) = Logging.shouldlog(cl.logger, args...) +Logging.min_enabled_level(cl::CaptureLogger) = Logging.min_enabled_level(cl.logger) +Logging.catch_exceptions(cl::CaptureLogger) = Logging.catch_exceptions(cl.logger) +function Logging.handle_message(cl::CaptureLogger, level, msg, _module, group, id, file, line; kwargs...) + push!(cl.logs, (level, msg, _module, group, id, file, line, kwargs)) end -function Logging.shouldlog(::PlutoLogger, level, _module, _...) + +const pluto_cell_loggers = Dict{UUID,PlutoCellLogger}() # One logger per cell +const pluto_log_channels = Dict{UUID,Channel{Any}}() # One channel per notebook + +function Logging.shouldlog(logger::PlutoCellLogger, level, _module, _...) # Accept logs + # - Only if the logger is the latest for this cell using the increasing workspace_count tied to each logger # - From the user's workspace module # - Info level and above for other modules - (_module isa Module && is_pluto_workspace(_module)) || convert(Logging.LogLevel, level) >= Logging.Info -end -Logging.min_enabled_level(::PlutoLogger) = Logging.Debug -Logging.catch_exceptions(::PlutoLogger) = false -function Logging.handle_message(::PlutoLogger, level, msg, _module, group, id, file, line; kwargs...) + # - LogLevel(-1) because that's what ProgressLogging.jl uses for its messages + current_logger = pluto_cell_loggers[logger.cell_id] + if current_logger.workspace_count > logger.workspace_count + return false + end + + level = convert(Logging.LogLevel, level) + (_module isa Module && is_pluto_workspace(_module)) || + level >= Logging.Info || + level == progress_log_level || + level == stdout_log_level +end + +const BuiltinInts = @static isdefined(Core, :BuiltinInts) ? Core.BuiltinInts : Union{Bool, Int32, Int64, UInt32, UInt64, UInt8, Int128, Int16, Int8, UInt128, UInt16} + +Logging.min_enabled_level(::PlutoCellLogger) = min(Logging.Debug, stdout_log_level) +Logging.catch_exceptions(::PlutoCellLogger) = false +function Logging.handle_message(pl::PlutoCellLogger, level, msg, _module, group, id, file, line; kwargs...) + # println("receiving msg from ", _module, " ", group, " ", id, " ", msg, " ", level, " ", line, " ", file) + # println("with types: ", "_module: ", typeof(_module), ", ", "msg: ", typeof(msg), ", ", "group: ", typeof(group), ", ", "id: ", typeof(id), ", ", "file: ", typeof(file), ", ", "line: ", typeof(line), ", ", "kwargs: ", typeof(kwargs)) # thanks Copilot + + # https://github.com/JuliaLang/julia/blob/eb2e9687d0ac694d0aa25434b30396ee2cfa5cd3/stdlib/Logging/src/ConsoleLogger.jl#L110-L115 + if get(kwargs, :maxlog, nothing) isa BuiltinInts + maxlog = kwargs[:maxlog] + remaining = get!(pl.message_limits, id, Int(maxlog)::Int) + pl.message_limits[id] = remaining - 1 + if remaining <= 0 + return + end + end + try - put!(log_channel, (level=string(level), - msg=(msg isa String) ? msg : repr(msg), - group=group, - # id=id, - file=file, - line=line, - kwargs=Dict((k=>repr(v) for (k, v) in kwargs)...),)) - # also print to console - Logging.handle_message(old_logger[], level, msg, _module, group, id, file, line; kwargs...) + yield() + + po() = get(cell_published_objects, pl.cell_id, Dict{String,Any}()) + before_published_object_keys = collect(keys(po())) + + # Render the log arguments: + msg_formatted = format_output_default(msg isa AbstractString ? Text(msg) : msg) + kwargs_formatted = Tuple{String,Any}[(string(k), format_log_value(v)) for (k, v) in kwargs if k != :maxlog] + + after_published_object_keys = collect(keys(po())) + new_published_object_keys = setdiff(after_published_object_keys, before_published_object_keys) + + # (Running `put!(pl.log_channel, x)` will send `x` to the pluto server. See `start_relaying_logs` for the receiving end.) + put!(pl.log_channel, Dict{String,Any}( + "level" => string(level), + "msg" => msg_formatted, + # This is a dictionary containing all published objects that were published during the rendering of the log arguments (we cannot track which objects were published during the execution of the log statement itself i think...) + "new_published_objects" => Dict{String,Any}( + key => po()[key] for key in new_published_object_keys + ), + "group" => string(group), + "id" => string(id), + "file" => string(file), + "cell_id" => pl.cell_id, + "line" => line isa Union{Int32,Int64} ? line : nothing, + "kwargs" => kwargs_formatted, + )) + + yield() + catch e - println(stderr, "Failed to relay log from PlutoRunner") - showerror(stderr, e, stacktrace(catch_backtrace())) + println(original_stderr, "Failed to relay log from PlutoRunner") + showerror(original_stderr, e, stacktrace(catch_backtrace())) + + nothing end end -# we put this in __init__ to fix a world age problem -function __init__() - if !isdefined(Main, Symbol("##Pluto_logger_switched")) && Distributed.myid() != 1 - old_logger[] = Logging.global_logger() - Logging.global_logger(PlutoLogger(nothing)) - Core.eval(Main, Expr(:(=), Symbol("##Pluto_logger_switched"), true)) # if Pluto is loaded again on the same process, prevent it from also setting the logger +format_log_value(v) = format_output_default(v) +format_log_value(v::Tuple{<:Exception,Vector{<:Any}}) = format_output(CapturedException(v...)) + +function _send_stdio_output!(output, loglevel) + output_str = String(take!(output)) + if !isempty(output_str) + Logging.@logmsg loglevel output_str end end +const stdout_log_level = Logging.LogLevel(-555) # https://en.wikipedia.org/wiki/555_timer_IC +const progress_log_level = Logging.LogLevel(-1) # https://github.com/JuliaLogging/ProgressLogging.jl/blob/0e7933005233722d6214b0debe3316c82b4d14a7/src/ProgressLogging.jl#L36 +function with_io_to_logs(f::Function; enabled::Bool=true, loglevel::Logging.LogLevel=Logging.LogLevel(1)) + if !enabled + return f() + end + # Taken from https://github.com/JuliaDocs/IOCapture.jl/blob/master/src/IOCapture.jl with some modifications to make it log. + + # Original implementation from Documenter.jl (MIT license) + # Save the default output streams. + default_stdout = stdout + default_stderr = stderr + # Redirect both the `stdout` and `stderr` streams to a single `Pipe` object. + pipe = Pipe() + Base.link_pipe!(pipe; reader_supports_async = true, writer_supports_async = true) + pe_stdout = pipe.in + pe_stderr = pipe.in + redirect_stdout(pe_stdout) + redirect_stderr(pe_stderr) + + # Bytes written to the `pipe` are captured in `output` and eventually converted to a + # `String`. We need to use an asynchronous task to continously tranfer bytes from the + # pipe to `output` in order to avoid the buffer filling up and stalling write() calls in + # user code. + execution_done = Ref(false) + output = IOBuffer() + + @async begin + pipe_reader = Base.pipe_reader(pipe) + try + while !eof(pipe_reader) + write(output, readavailable(pipe_reader)) + + # NOTE: we don't really have to wait for the end of execution to stream output logs + # so maybe we should just enable it? + if execution_done[] + _send_stdio_output!(output, loglevel) + end + end + _send_stdio_output!(output, loglevel) + catch err + @error "Failed to redirect stdout/stderr to logs" exception=(err,catch_backtrace()) + if err isa InterruptException + rethrow(err) + end + end + end + + # To make the `display` function work. + redirect_display = TextDisplay(IOContext(pe_stdout, default_stdout_iocontext)) + pushdisplay(redirect_display) + + # Run the function `f`, capturing all output that it might have generated. + # Success signals whether the function `f` did or did not throw an exception. + result = try + f() + finally + # Restore display + try + popdisplay(redirect_display) + catch e + # This happens when the user calls `popdisplay()`, fine. + # @warn "Pluto's display was already removed?" e + end + + execution_done[] = true + + # Restore the original output streams. + redirect_stdout(default_stdout) + redirect_stderr(default_stderr) + close(pe_stdout) + close(pe_stderr) + end + + result +end + +function with_logger_and_io_to_logs(f, logger; capture_stdout=true, stdio_loglevel=Logging.LogLevel(1)) + Logging.with_logger(logger) do + with_io_to_logs(f; enabled=capture_stdout, loglevel=stdio_loglevel) + end +end + +function setup_plutologger(notebook_id::UUID, log_channel::Channel{Any}) + pluto_log_channels[notebook_id] = log_channel +end + end diff --git a/src/webserver/Authentication.jl b/src/webserver/Authentication.jl new file mode 100644 index 0000000000..45644703d5 --- /dev/null +++ b/src/webserver/Authentication.jl @@ -0,0 +1,115 @@ + +""" +Return whether the `request` was authenticated in one of two ways: +1. the session's `secret` was included in the URL as a search parameter, or +2. the session's `secret` was included in a cookie. +""" +function is_authenticated(session::ServerSession, request::HTTP.Request) + ( + secret_in_url = try + uri = HTTP.URI(request.target) + query = HTTP.queryparams(uri) + get(query, "secret", "") == session.secret + catch e + @warn "Failed to authenticate request using URL" exception = (e, catch_backtrace()) + false + end + ) || ( + secret_in_cookie = try + cookies = HTTP.cookies(request) + any(cookies) do cookie + cookie.name == "secret" && cookie.value == session.secret + end + catch e + @warn "Failed to authenticate request using cookies" exception = (e, catch_backtrace()) + false + end + ) + # that ) || ( kind of looks like Krabs from spongebob +end + +# Function to log the url with secret on the Julia CLI when a request comes to the server without the secret. Executes at most once every 5 seconds +const log_secret_throttled = simple_leading_throttle(5) do session::ServerSession, request::HTTP.Request + host = HTTP.header(request, "Host") + target = request.target + url = Text(string(HTTP.URI(HTTP.URI("http://$host/"); query=Dict("secret" => session.secret)))) + @info("No longer authenticated? Visit this URL to continue:", url) +end + + +function add_set_secret_cookie!(session::ServerSession, response::HTTP.Response) + HTTP.setheader(response, "Set-Cookie" => "secret=$(session.secret); SameSite=Strict; HttpOnly") + response +end + +# too many layers i know +""" +Generate a middleware (i.e. a function `HTTP.Handler -> HTTP.Handler`) that stores the `session` in every `request`'s context. +""" +function create_session_context_middleware(session::ServerSession) + function session_context_middleware(handler::Function)::Function + function(request::HTTP.Request) + request.context[:pluto_session] = session + handler(request) + end + end +end + + +session_from_context(request::HTTP.Request) = request.context[:pluto_session]::ServerSession + + +function auth_required(session::ServerSession, request::HTTP.Request) + path = HTTP.URI(request.target).path + ext = splitext(path)[2] + security = session.options.security + + if path ∈ ("/ping", "/possible_binder_token_please") || ext ∈ (".ico", ".js", ".css", ".png", ".gif", ".svg", ".ico", ".woff2", ".woff", ".ttf", ".eot", ".otf", ".json", ".map") + false + elseif path ∈ ("", "/") + # / does not need security.require_secret_for_open_links, because this is how we handle the configuration where: + # require_secret_for_open_links == true + # require_secret_for_access == false + # + # This means that access to all 'risky' endpoints is restricted to authenticated requests (to prevent CSRF), but we allow an unauthenticated request to visit the `/` page and acquire the cookie (see `add_set_secret_cookie!`). + # + # (By default, `require_secret_for_access` (and `require_secret_for_open_links`) is `true`.) + security.require_secret_for_access + else + security.require_secret_for_access || + security.require_secret_for_open_links + end +end + + +""" + auth_middleware(f::HTTP.Handler) -> HTTP.Handler + +Returns an `HTTP.Handler` (i.e. a function `HTTP.Request → HTTP.Response`) which does three things: +1. Check whether the request is authenticated (by calling `is_authenticated`), if not, return a 403 error. +2. Call your `f(request)` to create the response message. +3. Add a `Set-Cookie` header to the response with the session's `secret`. + +This is for HTTP requests, the authentication mechanism for WebSockets is separate. +""" +function auth_middleware(handler) + return function (request::HTTP.Request) + session = session_from_context(request) + required = auth_required(session, request) + + if !required || is_authenticated(session, request) + response = handler(request) + if !required + filter!(p -> p[1] != "Access-Control-Allow-Origin", response.headers) + HTTP.setheader(response, "Access-Control-Allow-Origin" => "*") + end + if required || HTTP.URI(request.target).path ∈ ("", "/") + add_set_secret_cookie!(session, response) + end + response + else + log_secret_throttled(session, request) + error_response(403, "Not yet authenticated", "Open the link that was printed in the terminal where you launched Pluto. It includes a secret, which is needed to access this server.

If you are running the server yourself and want to change this configuration, have a look at the keyword arguments to Pluto.run.

Please report this error if you did not expect it!") + end + end +end diff --git a/src/webserver/Dynamic.jl b/src/webserver/Dynamic.jl index 832569cb56..867d5f6399 100644 --- a/src/webserver/Dynamic.jl +++ b/src/webserver/Dynamic.jl @@ -1,6 +1,7 @@ import UUIDs: uuid1 import .PkgCompat +import .Status "Will hold all 'response handlers': functions that respond to a WebSocket request from the client." const responses = Dict{Symbol,Function}() @@ -78,10 +79,16 @@ Besides `:update_notebook`, you will find more functions in [`responses`](@ref) """ module Firebasey include("./Firebasey.jl") end +module FirebaseyUtils + # I put Firebasey here manually THANKS JULIA + import ..Firebasey + include("./FirebaseyUtils.jl") +end # All of the arrays in the notebook_to_js object are 'immutable' (we write code as if they are), so we can enable this optimization: Firebasey.use_triple_equals_for_arrays[] = true + # the only possible Arrays are: # - cell_order # - cell_execution_order @@ -92,10 +99,11 @@ Firebasey.use_triple_equals_for_arrays[] = true function notebook_to_js(notebook::Notebook) Dict{String,Any}( + "pluto_version" => PLUTO_VERSION_STR, "notebook_id" => notebook.notebook_id, "path" => notebook.path, - "in_temp_dir" => startswith(notebook.path, new_notebooks_directory()), "shortpath" => basename(notebook.path), + "in_temp_dir" => startswith(notebook.path, new_notebooks_directory()), "process_status" => notebook.process_status, "last_save_time" => notebook.last_save_time, "last_hot_reload_time" => notebook.last_hot_reload_time, @@ -104,7 +112,7 @@ function notebook_to_js(notebook::Notebook) "cell_id" => cell.cell_id, "code" => cell.code, "code_folded" => cell.code_folded, - "running_disabled" => cell.running_disabled, + "metadata" => cell.metadata, ) for (id, cell) in notebook.cells_dict), "cell_dependencies" => Dict{UUID,Dict{String,Any}}( @@ -125,41 +133,40 @@ function notebook_to_js(notebook::Notebook) id => Dict{String,Any}( "cell_id" => cell.cell_id, "depends_on_disabled_cells" => cell.depends_on_disabled_cells, - "output" => Dict( - "body" => cell.output.body, - "mime" => cell.output.mime, - "rootassignee" => cell.output.rootassignee, - "last_run_timestamp" => cell.output.last_run_timestamp, - "persist_js_state" => cell.output.persist_js_state, - "has_pluto_hook_features" => cell.output.has_pluto_hook_features, - ), - "published_object_keys" => keys(cell.published_objects), + "output" => FirebaseyUtils.ImmutableMarker(cell.output), + "published_object_keys" => collect(keys(cell.published_objects)), "queued" => cell.queued, "running" => cell.running, "errored" => cell.errored, "runtime" => cell.runtime, + "logs" => FirebaseyUtils.AppendonlyMarker(cell.logs), + "depends_on_skipped_cells" => cell.depends_on_skipped_cells, ) for (id, cell) in notebook.cells_dict), "cell_order" => notebook.cell_order, "published_objects" => merge!(Dict{String,Any}(), (c.published_objects for c in values(notebook.cells_dict))...), "bonds" => Dict{String,Dict{String,Any}}( - String(key) => Dict( + String(key) => Dict{String,Any}( "value" => bondvalue.value, ) for (key, bondvalue) in notebook.bonds), + "metadata" => notebook.metadata, "nbpkg" => let ctx = notebook.nbpkg_ctx Dict{String,Any}( "enabled" => ctx !== nothing, + "waiting_for_permission" => notebook.process_status === ProcessStatus.waiting_for_permission, + "waiting_for_permission_but_probably_disabled" => notebook.process_status === ProcessStatus.waiting_for_permission && !use_plutopkg(notebook.topology), "restart_recommended_msg" => notebook.nbpkg_restart_recommended_msg, "restart_required_msg" => notebook.nbpkg_restart_required_msg, - # TODO: cache this "installed_versions" => ctx === nothing ? Dict{String,String}() : notebook.nbpkg_installed_versions_cache, "terminal_outputs" => notebook.nbpkg_terminal_outputs, + "install_time_ns" => notebook.nbpkg_install_time_ns, "busy_packages" => notebook.nbpkg_busy_packages, "instantiated" => notebook.nbpkg_ctx_instantiated, ) end, + "status_tree" => Status.tojs(notebook.status_tree), "cell_execution_order" => cell_id.(collect(topological_order(notebook))), ) end @@ -168,33 +175,40 @@ end For each connected client, we keep a copy of their current state. This way we know exactly which updates to send when the server-side state changes. """ const current_state_for_clients = WeakKeyDict{ClientSession,Any}() +const current_state_for_clients_lock = ReentrantLock() """ Update the local state of all clients connected to this notebook. """ -function send_notebook_changes!(🙋::ClientRequest; commentary::Any=nothing) - notebook_dict = notebook_to_js(🙋.notebook) - # @info "Connected clients" length(🙋.session.connected_clients) Set(c -> c.stream for c in 🙋.session.connected_clients) - for (_, client) in 🙋.session.connected_clients - if client.connected_notebook !== nothing && client.connected_notebook.notebook_id == 🙋.notebook.notebook_id - current_dict = get(current_state_for_clients, client, :empty) - patches = Firebasey.diff(current_dict, notebook_dict) - patches_as_dicts::Array{Dict} = patches - current_state_for_clients[client] = deep_enough_copy(notebook_dict) - - # Make sure we do send a confirmation to the client who made the request, even without changes - is_response = 🙋.initiator !== nothing && client == 🙋.initiator.client - # @info "Responding" is_response (🙋.initiator !== nothing) (commentary === nothing) - - if !isempty(patches) || is_response - response = Dict( - :patches => patches_as_dicts, - :response => is_response ? commentary : nothing - ) - putclientupdates!(client, UpdateMessage(:notebook_diff, response, 🙋.notebook, nothing, 🙋.initiator)) +function send_notebook_changes!(🙋::ClientRequest; commentary::Any=nothing, skip_send::Bool=false) + outbox = Set{Tuple{ClientSession,UpdateMessage}}() + + lock(current_state_for_clients_lock) do + notebook_dict = notebook_to_js(🙋.notebook) + for (_, client) in 🙋.session.connected_clients + if client.connected_notebook !== nothing && client.connected_notebook.notebook_id == 🙋.notebook.notebook_id + current_dict = get(current_state_for_clients, client, :empty) + patches = Firebasey.diff(current_dict, notebook_dict) + patches_as_dicts = Firebasey._convert(Vector{Dict}, patches) + current_state_for_clients[client] = deep_enough_copy(notebook_dict) + + # Make sure we do send a confirmation to the client who made the request, even without changes + is_response = 🙋.initiator !== nothing && client == 🙋.initiator.client + + if !skip_send && (!isempty(patches) || is_response) + response = Dict( + :patches => patches_as_dicts, + :response => is_response ? commentary : nothing + ) + push!(outbox, (client, UpdateMessage(:notebook_diff, response, 🙋.notebook, nothing, 🙋.initiator))) + end end end end + + for (client, msg) in outbox + putclientupdates!(client, msg) + end try_event_call(🙋.session, FileEditEvent(🙋.notebook)) end @@ -228,16 +242,7 @@ const no_changes = Changed[] const effects_of_changed_state = Dict( "path" => function(; request::ClientRequest, patch::Firebasey.ReplacePatch) - newpath = tamepath(patch.value) - # SessionActions.move(request.session, request.notebook, newpath) - - if isfile(newpath) - error("File exists already - you need to delete the old file manually.") - else - move_notebook!(request.notebook, newpath; disable_writing_notebook_files=request.session.options.server.disable_writing_notebook_files) - putplutoupdates!(request.session, clientupdate_notebook_list(request.session.notebooks)) - WorkspaceManager.cd_workspace((request.session, request.notebook), newpath) - end + SessionActions.move(request.session, request.notebook, patch.value) return no_changes end, "process_status" => function(; request::ClientRequest, patch::Firebasey.ReplacePatch) @@ -245,6 +250,18 @@ const effects_of_changed_state = Dict( @info "Process status set by client" newstatus end, + # "execution_allowed" => function(; request::ClientRequest, patch::Firebasey.ReplacePatch) + # Firebasey.applypatch!(request.notebook, patch) + # newstatus = patch.value + + # @info "execution_allowed set by client" newstatus + # if newstatus + # @info "lets run some cells!" + # update_save_run!(request.session, request.notebook, notebook.cells; + # run_async=true, save=true + # ) + # end + # end, "in_temp_dir" => function(; _...) no_changes end, "cell_inputs" => Dict( Wildcard() => function(cell_id, rest...; request::ClientRequest, patch::Firebasey.JSONPatch) @@ -269,6 +286,12 @@ const effects_of_changed_state = Dict( Firebasey.applypatch!(request.notebook, patch) [BondChanged(name, patch isa Firebasey.AddPatch)] end, + ), + "metadata" => Dict( + Wildcard() => function(property; request::ClientRequest, patch::Firebasey.JSONPatch) + Firebasey.applypatch!(request.notebook, patch) + [FileChanged()] + end ) ) @@ -280,7 +303,6 @@ responses[:update_notebook] = function response_update_notebook(🙋::ClientRequ patches = (Base.convert(Firebasey.JSONPatch, update) for update in 🙋.body["updates"]) if length(patches) == 0 - # @info "Empty patches" send_notebook_changes!(🙋) return nothing end @@ -300,18 +322,33 @@ responses[:update_notebook] = function response_update_notebook(🙋::ClientRequ (mutator, matches, rest) = trigger_resolver(effects_of_changed_state, patch.path) current_changes = if isempty(rest) && applicable(mutator, matches...) - mutator(matches...; request=🙋, patch=patch) + mutator(matches...; request=🙋, patch) else - mutator(matches..., rest...; request=🙋, patch=patch) + mutator(matches..., rest...; request=🙋, patch) end - push!(changes, current_changes...) + union!(changes, current_changes) + end + + # We put a flag to check whether any patch changes the skip_as_script metadata. This is to eventually trigger a notebook updated if no reactive_run is part of this update + skip_as_script_changed = any(patches) do patch + path = patch.path + metadata_idx = findfirst(isequal("metadata"), path) + if metadata_idx === nothing + false + else + isequal(path[metadata_idx+1], "skip_as_script") + end end # If CodeChanged ∈ changes, then the client will also send a request like run_multiple_cells, which will trigger a file save _before_ running the cells. # In the future, we should get rid of that request, and save the file here. For now, we don't save the file here, to prevent unnecessary file IO. # (You can put a log in save_notebook to track how often the file is saved) if FileChanged() ∈ changes && CodeChanged() ∉ changes + if skip_as_script_changed + # If skip_as_script has changed but no cell run is happening we want to update the notebook dependency here before saving the file + update_skipped_cells_dependency!(notebook) + end save_notebook(🙋.session, notebook) end @@ -324,10 +361,11 @@ responses[:update_notebook] = function response_update_notebook(🙋::ClientRequ bound_sym_names=bound_sym_names, is_first_values=is_first_values, run_async=true, + initiator=🙋.initiator, ) end - send_notebook_changes!(🙋; commentary=Dict(:update_went_well => :👍)) + send_notebook_changes!(🙋; commentary=Dict(:update_went_well => :👍)) catch ex @error "Update notebook failed" 🙋.body["updates"] exception=(ex, stacktrace(catch_backtrace())) response = Dict( @@ -344,24 +382,16 @@ function trigger_resolver(anything, path, values=[]) end function trigger_resolver(resolvers::Dict, path, values=[]) if isempty(path) - throw(BoundsError("resolver path ends at Dict with keys $(keys(resolver))")) + throw(BoundsError("resolver path ends at Dict with keys $(keys(resolvers))")) end - segment = first(path) - rest = path[firstindex(path)+1:end] - for (key, resolver) in resolvers - if key isa Wildcard - continue - end - if key == segment - return trigger_resolver(resolver, rest, values) - end - end - - if haskey(resolvers, Wildcard()) - return trigger_resolver(resolvers[Wildcard()], rest, (values..., segment)) + segment, rest... = path + if haskey(resolvers, segment) + trigger_resolver(resolvers[segment], rest, values) + elseif haskey(resolvers, Wildcard()) + trigger_resolver(resolvers[Wildcard()], rest, (values..., segment)) else - throw(BoundsError("failed to match path $(path), possible keys $(keys(resolver))")) + throw(BoundsError("failed to match path $(path), possible keys $(keys(resolvers))")) end end @@ -372,6 +402,10 @@ end # MISC RESPONSES ### +responses[:current_time] = function response_current_time(🙋::ClientRequest) + putclientupdates!(🙋.session, 🙋.initiator, UpdateMessage(:current_time, Dict(:time => time()), nothing, nothing, 🙋.initiator)) +end + responses[:connect] = function response_connect(🙋::ClientRequest) putclientupdates!(🙋.session, 🙋.initiator, UpdateMessage(:👋, Dict( :notebook_exists => (🙋.notebook !== nothing), @@ -402,11 +436,28 @@ responses[:run_multiple_cells] = function response_run_multiple_cells(🙋::Clie if will_run_code(🙋.notebook) foreach(c -> c.queued = true, cells) - send_notebook_changes!(🙋) + # run send_notebook_changes! without actually sending it, to update current_state_for_clients for our client with c.queued = true. + # later, during update_save_run!, the cell will actually run, eventually setting c.queued = false again, which will be sent to the client through a patch update. + # We *need* to send *something* to the client, because of https://github.com/fonsp/Pluto.jl/pull/1892, but we also don't want to send unnecessary updates. We can skip sending this update, because update_save_run! will trigger a send_notebook_changes! very very soon. + send_notebook_changes!(🙋; skip_send=true) + end + + function on_auto_solve_multiple_defs(disabled_cells_dict) + response = Dict{Symbol,Any}( + :disabled_cells => Dict{UUID,Any}(cell_id(k) => v for (k,v) in disabled_cells_dict), + ) + putclientupdates!(🙋.session, 🙋.initiator, UpdateMessage(:run_feedback, response, 🙋.notebook, nothing, 🙋.initiator)) end - # save=true fixes the issue where "Submit all changes" or `Ctrl+S` has no effect. - update_save_run!(🙋.session, 🙋.notebook, cells; run_async=true, save=true) + wfp = 🙋.notebook.process_status == ProcessStatus.waiting_for_permission + + update_save_run!(🙋.session, 🙋.notebook, cells; + run_async=true, save=true, + auto_solve_multiple_defs=true, on_auto_solve_multiple_defs, + # special case: just render md cells in "Safe preview" mode + prerender_text=wfp, + clear_not_prerenderable_cells=wfp, + ) end responses[:get_all_notebooks] = function response_get_all_notebooks(🙋::ClientRequest) @@ -417,7 +468,7 @@ responses[:interrupt_all] = function response_interrupt_all(🙋::ClientRequest) require_notebook(🙋) session_notebook = (🙋.session, 🙋.notebook) - workspace = WorkspaceManager.get_workspace(session_notebook) + workspace = WorkspaceManager.get_workspace(session_notebook; allow_creation=false) already_interrupting = 🙋.notebook.wants_to_interrupt anything_running = !isready(workspace.dowork_token) @@ -441,8 +492,10 @@ responses[:restart_process] = function response_restart_process(🙋::ClientRequ if 🙋.notebook.process_status != ProcessStatus.waiting_to_restart 🙋.notebook.process_status = ProcessStatus.waiting_to_restart + 🙋.session.options.evaluation.run_notebook_on_load && _report_business_cells_planned!(🙋.notebook) send_notebook_changes!(🙋 |> without_initiator) + # TODO skip necessary? SessionActions.shutdown(🙋.session, 🙋.notebook; keep_in_session=true, async=true) 🙋.notebook.process_status = ProcessStatus.starting @@ -455,6 +508,8 @@ end responses[:reshow_cell] = function response_reshow_cell(🙋::ClientRequest) require_notebook(🙋) + @assert will_run_code(🙋.notebook) + cell = let cell_id = UUID(🙋.body["cell_id"]) 🙋.notebook.cells_dict[cell_id] diff --git a/src/webserver/Firebasey.jl b/src/webserver/Firebasey.jl index 22f99f2257..99a18e731c 100644 --- a/src/webserver/Firebasey.jl +++ b/src/webserver/Firebasey.jl @@ -1,27 +1,57 @@ ### A Pluto.jl notebook ### -# v0.16.1 +# v0.19.12 using Markdown using InteractiveUtils +# ╔═╡ e748600a-2de1-11eb-24be-d5f0ecab8fa4 +# ╠═╡ show_logs = false +# ╠═╡ skip_as_script = true +#=╠═╡ +# Only define this in Pluto - assume we are `using Test` otherwise +begin + import Pkg + Pkg.activate(mktempdir()) + Pkg.add(Pkg.PackageSpec(name="PlutoTest")) + using PlutoTest +end + ╠═╡ =# + +# ╔═╡ 3e07f976-6cd0-4841-9762-d40337bb0645 +# ╠═╡ skip_as_script = true +#=╠═╡ +using Markdown: @md_str + ╠═╡ =# + # ╔═╡ d948dc6e-2de1-11eb-19e7-cb3bb66353b6 +# ╠═╡ skip_as_script = true +#=╠═╡ md"# Diffing" + ╠═╡ =# # ╔═╡ 1a6e1853-6db1-4074-bce0-5f274351cece +# ╠═╡ skip_as_script = true +#=╠═╡ md""" We define a _diffing system_ for Julia `Dict`s, which is analogous to the diffing system of immer.js. This notebook is part of Pluto's source code (included in `src/webserver/Dynamic.jl`). """ + ╠═╡ =# # ╔═╡ 49fc1f97-3b8f-4297-94e5-2e24c001d35c +# ╠═╡ skip_as_script = true +#=╠═╡ md""" ## Example Computing a diff: """ + ╠═╡ =# # ╔═╡ d8e73b90-24c5-4e50-830b-b1dbe6224c8e +# ╠═╡ skip_as_script = true +#=╠═╡ dict_1 = Dict{String,Any}( "a" => 1, "b" => Dict( @@ -30,8 +60,11 @@ dict_1 = Dict{String,Any}( ), "e" => "hello!" ); + ╠═╡ =# # ╔═╡ 19646596-b35b-44fa-bfcf-891f9ffb748c +# ╠═╡ skip_as_script = true +#=╠═╡ dict_2 = Dict{String,Any}( "a" => 1, "b" => Dict( @@ -40,22 +73,29 @@ dict_2 = Dict{String,Any}( "🏝" => "👍", ), ); + ╠═╡ =# # ╔═╡ 9d2c07d9-16a9-4b9f-a375-2adb6e5b907a +# ╠═╡ skip_as_script = true +#=╠═╡ md""" Applying a set of patches: """ + ╠═╡ =# # ╔═╡ 336bfd4f-8a8e-4a2d-be08-ee48d6a9f747 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" ## JSONPatch objects """ + ╠═╡ =# # ╔═╡ db116c0a-2de1-11eb-2a56-872af797c547 abstract type JSONPatch end # ╔═╡ bd0d46bb-3e58-4522-bae0-83eb799196c4 -PatchPath = Vector +const PatchPath = Vector # ╔═╡ db2d8a3e-2de1-11eb-02b8-9ffbfaeff61c struct AddPatch <: JSONPatch @@ -93,7 +133,10 @@ const Patches = Vector{JSONPatch} const NoChanges = Patches() # ╔═╡ aad7ab32-eecf-4aad-883d-1c802cad6c0c +# ╠═╡ skip_as_script = true +#=╠═╡ md"### ==" + ╠═╡ =# # ╔═╡ 732fd744-acdb-4507-b1de-6866ec5563dd Base.hash(a::AddPatch) = hash([AddPatch, a.value, a.path]) @@ -135,8 +178,44 @@ function Base.:(==)(a::MovePatch, b::MovePatch) a.path == b.path && a.from == b.from end +# ╔═╡ 5ddfd616-db20-451b-bc1e-2ad52e0e2777 +#=╠═╡ +@test Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) == + Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) + ╠═╡ =# + +# ╔═╡ 24e93923-eab9-4a7b-9bc7-8d8a1209a78f +#=╠═╡ +@test ReplacePatch(["asd"], Dict("a" => 2)) == + ReplacePatch(["asd"], Dict("a" => 2)) + ╠═╡ =# + +# ╔═╡ 09ddf4d9-5ccb-4530-bfab-d11b864e872a +#=╠═╡ +@test Base.hash(RemovePatch(["asd"])) == Base.hash(RemovePatch(["asd"])) + ╠═╡ =# + +# ╔═╡ d9e764db-94fc-44f7-8c2e-3d63f4809617 +#=╠═╡ +@test RemovePatch(["asd"]) == RemovePatch(["asd"]) + ╠═╡ =# + +# ╔═╡ 99df99ad-aad5-4275-97d4-d1ceeb2f8d15 +#=╠═╡ +@test Base.hash(RemovePatch(["aasd"])) != Base.hash(RemovePatch(["asd"])) + ╠═╡ =# + +# ╔═╡ 2d665639-7274-495a-ae9d-f358a8219bb7 +#=╠═╡ +@test Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) != + Base.hash(AddPatch(["asd"], Dict("a" => 2))) + ╠═╡ =# + # ╔═╡ f658a72d-871d-49b3-9b73-7efedafbd7a6 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### convert(::Type{Dict}, ::JSONPatch)" + ╠═╡ =# # ╔═╡ 230bafe2-aaa7-48f0-9fd1-b53956281684 function Base.convert(::Type{Dict}, patch::AddPatch) @@ -148,11 +227,6 @@ function Base.convert(::Type{Dict}, patch::RemovePatch) Dict{String,Any}("op" => "remove", "path" => patch.path) end -# ╔═╡ fafcb8b8-cde9-4f99-9bab-8128025953a4 -function Base.convert(::Type{<:Dict}, patch::ReplacePatch) - Dict{String,Any}("op" => "replace", "path" => patch.path, "value" => patch.value) -end - # ╔═╡ 921a130e-b028-4f91-b077-3bd79dcb6c6d function Base.convert(::Type{JSONPatch}, patch_dict::Dict) op = patch_dict["op"] @@ -168,25 +242,40 @@ function Base.convert(::Type{JSONPatch}, patch_dict::Dict) end # ╔═╡ 07eeb122-6706-4544-a007-1c8d6581eec8 +# ╠═╡ skip_as_script = true +#=╠═╡ Base.convert(Dict, AddPatch([:x, :y], 10)) + ╠═╡ =# # ╔═╡ c59b30b9-f702-41f1-bb2e-1736c8cd5ede +# ╠═╡ skip_as_script = true +#=╠═╡ Base.convert(Dict, RemovePatch([:x, :y])) - -# ╔═╡ 7feeee3a-3aec-47ce-b8d7-74a0d9b0b381 -Base.convert(Dict, ReplacePatch([:x, :y], 10)) + ╠═╡ =# # ╔═╡ 6d67f8a5-0e0c-4b6e-a267-96b34d580946 +# ╠═╡ skip_as_script = true +#=╠═╡ add_patch = AddPatch(["counter"], 10) + ╠═╡ =# # ╔═╡ 56b28842-4a67-44d7-95e7-55d457a44fb1 +# ╠═╡ skip_as_script = true +#=╠═╡ remove_patch = RemovePatch(["counter"]) + ╠═╡ =# # ╔═╡ f10e31c0-1d2c-4727-aba5-dd676a10041b +# ╠═╡ skip_as_script = true +#=╠═╡ replace_patch = ReplacePatch(["counter"], 10) + ╠═╡ =# # ╔═╡ 3a99e22d-42d6-4b2d-9381-022b41b0e852 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### wrappath" + ╠═╡ =# # ╔═╡ 831d84a6-1c71-4e68-8c7c-27d9093a82c4 function wrappath(path::PatchPath, patches::Vector{JSONPatch}) @@ -221,7 +310,10 @@ function wrappath(path, patch::MovePatch) end # ╔═╡ daf9ec12-2de1-11eb-3a8d-59d9c2753134 +# ╠═╡ skip_as_script = true +#=╠═╡ md"## Diff" + ╠═╡ =# # ╔═╡ 0b50f6b2-8e85-4565-9f04-f99c913b4592 const use_triple_equals_for_arrays = Ref(false) @@ -318,46 +410,75 @@ function diff(o1::Nothing, o2::Nothing) end # ╔═╡ 7ca087b8-73ac-49ea-9c5a-2971f0da491f +#=╠═╡ example_patches = diff(dict_1, dict_2) + ╠═╡ =# # ╔═╡ 59b46bfe-da74-43af-9c11-cb0bdb2c13a2 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" ### Dict example """ + ╠═╡ =# # ╔═╡ 200516da-8cfb-42fe-a6b9-cb4730168923 +# ╠═╡ skip_as_script = true +#=╠═╡ celldict1 = Dict(:x => 1, :y => 2, :z => 3) + ╠═╡ =# # ╔═╡ 76326e6c-b95a-4b2d-a78c-e283e5fadbe2 +# ╠═╡ skip_as_script = true +#=╠═╡ celldict2 = Dict(:x => 1, :y => 2, :z => 4) + ╠═╡ =# # ╔═╡ 664cd334-91c7-40dd-a2bf-0da720307cfc +# ╠═╡ skip_as_script = true +#=╠═╡ notebook1 = Dict( :x => 1, :y => 2, ) + ╠═╡ =# # ╔═╡ b7fa5625-6178-4da8-a889-cd4f014f43ba +# ╠═╡ skip_as_script = true +#=╠═╡ notebook2 = Dict( :y => 4, :z => 5 ) + ╠═╡ =# # ╔═╡ dbdd1df0-2de1-11eb-152f-8d1af1ad02fe +#=╠═╡ notebook1_to_notebook2 = diff(notebook1, notebook2) + ╠═╡ =# # ╔═╡ 3924953f-787a-4912-b6ee-9c9d3030f0f0 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" ### Large Dict example 1 """ + ╠═╡ =# # ╔═╡ 80689881-1b7e-49b2-af97-9e3ab639d006 +# ╠═╡ skip_as_script = true +#=╠═╡ big_array = rand(UInt8, 1_000_000) + ╠═╡ =# # ╔═╡ fd22b6af-5fd2-428a-8291-53e223ea692c +# ╠═╡ skip_as_script = true +#=╠═╡ big_string = repeat('a', 1_000_000); + ╠═╡ =# # ╔═╡ bcd5059b-b0d2-49d8-a756-92349aa56aca +#=╠═╡ large_dict_1 = Dict{String,Any}( "cell_$(i)" => Dict{String,Any}( "x" => 1, @@ -366,8 +487,10 @@ large_dict_1 = Dict{String,Any}( ) for i in 1:10 ); + ╠═╡ =# # ╔═╡ e7fd6bab-c114-4f3e-b9ad-1af2d1147770 +#=╠═╡ begin large_dict_2 = Dict{String,Any}( "cell_$(i)" => Dict{String,Any}( @@ -382,21 +505,32 @@ begin large_dict_2["hello"] = Dict("a" => 1, "b" => 2) large_dict_2 end; + ╠═╡ =# # ╔═╡ 43c36ab7-e9ac-450a-8abe-435412f2be1d +#=╠═╡ diff(large_dict_1, large_dict_2) + ╠═╡ =# # ╔═╡ 1cf22fe6-4b58-4220-87a1-d7a18410b4e8 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" With `===` comparison for arrays: """ + ╠═╡ =# # ╔═╡ ffb01ab4-e2e3-4fa4-8c0b-093d2899a536 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" ### Large Dict example 2 """ + ╠═╡ =# # ╔═╡ 8188de75-ae6e-48aa-9495-111fd27ffd26 +# ╠═╡ skip_as_script = true +#=╠═╡ many_items_1 = Dict{String,Any}( "cell_$(i)" => Dict{String,Any}( "x" => 1, @@ -405,8 +539,15 @@ many_items_1 = Dict{String,Any}( ) for i in 1:100 ) + ╠═╡ =# + +# ╔═╡ fdc427f0-dfe8-4114-beca-48fc15434534 +#=╠═╡ +@test isempty(diff(many_items_1, many_items_1)) + ╠═╡ =# # ╔═╡ d807195e-ba27-4015-92a7-c9294d458d47 +#=╠═╡ begin many_items_2 = deepcopy(many_items_1) many_items_2["cell_5"]["y"][2] = 20 @@ -414,30 +555,67 @@ begin many_items_2["hello"] = Dict("a" => 1, "b" => 2) many_items_2 end + ╠═╡ =# # ╔═╡ 2e91a1a2-469c-4123-a0d7-3dcc49715738 +#=╠═╡ diff(many_items_1, many_items_2) + ╠═╡ =# # ╔═╡ b8061c1b-dd03-4cd1-b275-90359ae2bb39 fairly_equal(a,b) = Set(a) == Set(b) +# ╔═╡ 2983f6d4-c1ca-4b66-a2d3-f858b0df2b4c +#=╠═╡ +@test fairly_equal(diff(large_dict_1, large_dict_2), [ + ReplacePatch(["cell_5","y"], [2,20]), + RemovePatch(["cell_2"]), + AddPatch(["hello"], Dict("b" => 2, "a" => 1)), +]) + ╠═╡ =# + +# ╔═╡ 61b81430-d26e-493c-96da-b6818e58c882 +#=╠═╡ +@test fairly_equal(diff(many_items_1, many_items_2), [ + ReplacePatch(["cell_5","y"], [2,20]), + RemovePatch(["cell_2"]), + AddPatch(["hello"], Dict("b" => 2, "a" => 1)), +]) + ╠═╡ =# + # ╔═╡ aeab3363-08ba-47c2-bd33-04a004ed72c4 +#=╠═╡ diff(many_items_1, many_items_1) + ╠═╡ =# + +# ╔═╡ 62de3e79-4b4e-41df-8020-769c3c255c3e +#=╠═╡ +@test isempty(diff(many_items_1, many_items_1)) + ╠═╡ =# # ╔═╡ c7de406d-ccfe-41cf-8388-6bd2d7c42d64 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### Struct example" + ╠═╡ =# # ╔═╡ b9cc11ae-394b-44b9-bfbe-541d7720ead0 +# ╠═╡ skip_as_script = true +#=╠═╡ struct Cell id code folded end + ╠═╡ =# # ╔═╡ c3c675be-9178-4176-afe0-30501786b72c +#=╠═╡ deep_diff(old::Cell, new::Cell) = diff(Deep(old), Deep(new)) + ╠═╡ =# # ╔═╡ 02585c72-1d92-4526-98c2-1ca07aad87a3 +#=╠═╡ function direct_diff(old::Cell, new::Cell) changes = [] if old.id ≠ new.id @@ -451,15 +629,25 @@ function direct_diff(old::Cell, new::Cell) end changes end + ╠═╡ =# # ╔═╡ 2d084dd1-240d-4443-a8a2-82ae6e0b8900 +# ╠═╡ skip_as_script = true +#=╠═╡ cell1 = Cell(1, 2, 3) + ╠═╡ =# # ╔═╡ 3e05200f-071a-4ebe-b685-ff980f07cde7 +# ╠═╡ skip_as_script = true +#=╠═╡ cell2 = Cell(1, 2, 4) + ╠═╡ =# # ╔═╡ dd312598-2de1-11eb-144c-f92ed6484f5d +# ╠═╡ skip_as_script = true +#=╠═╡ md"## Update" + ╠═╡ =# # ╔═╡ d2af2a4b-8982-4e43-9fd7-0ecfdfb70511 const strict_applypatch = Ref(false) @@ -480,8 +668,7 @@ function getpath(value, path) return value end - current = path[firstindex(path)] - rest = path[firstindex(path) + 1:end] + current, rest... = path if value isa AbstractDict key = force_convert_key(value, current) getpath(getindex(value, key), rest) @@ -499,7 +686,32 @@ function applypatch!(value, patches::Array{JSONPatch}) end # ╔═╡ 3e285076-1d97-4728-87cf-f71b22569e57 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### applypatch! AddPatch" + ╠═╡ =# + +# ╔═╡ d7ea6052-9d9f-48e3-92fb-250afd69e417 +begin + _convert(::Type{Base.UUID}, s::String) = Base.UUID(s) + _convert(::Type{T}, a::AbstractArray) where {T<:Array} = _convert.(eltype(T), a) + _convert(x, y) = convert(x, y) + + function _convert(::Type{<:Dict}, patch::ReplacePatch) + Dict{String,Any}("op" => "replace", "path" => patch.path, "value" => patch.value) + end + + function _setproperty!(x, f::Symbol, v) + type = fieldtype(typeof(x), f) + return setfield!(x, f, _convert(type, v)) + end +end + +# ╔═╡ 7feeee3a-3aec-47ce-b8d7-74a0d9b0b381 +# ╠═╡ skip_as_script = true +#=╠═╡ +_convert(Dict, ReplacePatch([:x, :y], 10)) + ╠═╡ =# # ╔═╡ dd87ca7e-2de1-11eb-2ec3-d5721c32f192 function applypatch!(value, patch::AddPatch) @@ -507,7 +719,7 @@ function applypatch!(value, patch::AddPatch) throw("Impossible") else last = patch.path[end] - rest = patch.path[firstindex(patch.path):end - 1] + rest = patch.path[begin:end - 1] subvalue = getpath(value, rest) if subvalue isa AbstractDict key = force_convert_key(subvalue, last) @@ -520,17 +732,23 @@ function applypatch!(value, patch::AddPatch) if strict_applypatch[] @assert getproperty(subvalue, key) === nothing end - setproperty!(subvalue, key, patch.value) + _setproperty!(subvalue, key, patch.value) end end return value end # ╔═╡ a11e4082-4ff4-4c1b-9c74-c8fa7dcceaa6 +# ╠═╡ skip_as_script = true +#=╠═╡ md"*Should throw in strict mode:*" + ╠═╡ =# # ╔═╡ be6b6fc4-e12a-4cef-81d8-d5115fda50b7 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### applypatch! ReplacePatch" + ╠═╡ =# # ╔═╡ 6509d62e-77b6-499c-8dab-4a608e44720a function applypatch!(value, patch::ReplacePatch) @@ -538,7 +756,7 @@ function applypatch!(value, patch::ReplacePatch) throw("Impossible") else last = patch.path[end] - rest = patch.path[firstindex(patch.path):end - 1] + rest = patch.path[begin:end - 1] subvalue = getpath(value, rest) if subvalue isa AbstractDict key = force_convert_key(subvalue, last) @@ -551,17 +769,23 @@ function applypatch!(value, patch::ReplacePatch) if strict_applypatch[] @assert getproperty(subvalue, key) !== nothing end - setproperty!(subvalue, key, patch.value) + _setproperty!(subvalue, key, patch.value) end end return value end # ╔═╡ f1dde1bd-3fa4-48b7-91ed-b2f98680fcc1 +# ╠═╡ skip_as_script = true +#=╠═╡ md"*Should throw in strict mode:*" + ╠═╡ =# # ╔═╡ f3ef354b-b480-4b48-8358-46dbf37e1d95 +# ╠═╡ skip_as_script = true +#=╠═╡ md"### applypatch! RemovePatch" + ╠═╡ =# # ╔═╡ ddaf5b66-2de1-11eb-3348-b905b94a984b function applypatch!(value, patch::RemovePatch) @@ -569,7 +793,7 @@ function applypatch!(value, patch::RemovePatch) throw("Impossible") else last = patch.path[end] - rest = patch.path[firstindex(patch.path):end - 1] + rest = patch.path[begin:end - 1] subvalue = getpath(value, rest) if subvalue isa AbstractDict key = force_convert_key(subvalue, last) @@ -582,161 +806,89 @@ function applypatch!(value, patch::RemovePatch) if strict_applypatch[] @assert getproperty(subvalue, key) !== nothing end - setproperty!(subvalue, key, nothing) + _setproperty!(subvalue, key, nothing) end end return value end # ╔═╡ e65d483a-4c13-49ba-bff1-1d54de78f534 +#=╠═╡ let dict_1_copy = deepcopy(dict_1) applypatch!(dict_1_copy, example_patches) end - -# ╔═╡ df41caa7-f0fc-4b0d-ab3d-ebdab4804040 -md"*Should throw in strict mode:*" - -# ╔═╡ e55d1cea-2de1-11eb-0d0e-c95009eedc34 -md"## Testing" - -# ╔═╡ b05fcb88-3781-45d0-9f24-e88c339a72e5 -macro test2(expr) - quote nothing end -end - -# ╔═╡ e8d0c98a-2de1-11eb-37b9-e1df3f5cfa25 -md"## `@skip_as_script`" - -# ╔═╡ e907d862-2de1-11eb-11a9-4b3ac37cb0f3 -function is_inside_pluto(m::Module) - if isdefined(m, :PlutoForceDisplay) - return m.PlutoForceDisplay - else - isdefined(m, :PlutoRunner) && parentmodule(m) == Main - end -end - -# ╔═╡ e924a0be-2de1-11eb-2170-71d56e117af2 -""" - @skip_as_script expression - -Marks a expression as Pluto-only, which means that it won't be executed when running outside Pluto. Do not use this for your own projects. -""" -macro skip_as_script(ex) - if is_inside_pluto(__module__) - esc(ex) - else - nothing - end -end - -# ╔═╡ c2c2b057-a88f-4cc6-ada4-fc55ac29931e -"The opposite of `@skip_as_script`" -macro only_as_script(ex) is_inside_pluto(__module__) ? nothing : esc(ex) end - -# ╔═╡ e748600a-2de1-11eb-24be-d5f0ecab8fa4 -# Only define this in Pluto - assume we are `using Test` otherwise -begin - @skip_as_script begin - import Pkg - Pkg.activate(mktempdir()) - Pkg.add(Pkg.PackageSpec(name="PlutoTest")) - using PlutoTest - end - # Do nothing inside pluto (so we don't need to have Test as dependency) - # test/Firebasey is `using Test` before including this file - @only_as_script begin - if !isdefined(@__MODULE__, Symbol("@test")) - macro test(e...) nothing; end - macro test_throws(e...) nothing; end - macro test_broken(e...) nothing; end - macro testset(e...) nothing; end - end - end -end - -# ╔═╡ 5ddfd616-db20-451b-bc1e-2ad52e0e2777 -@test Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) == - Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) - -# ╔═╡ 24e93923-eab9-4a7b-9bc7-8d8a1209a78f -@test ReplacePatch(["asd"], Dict("a" => 2)) == - ReplacePatch(["asd"], Dict("a" => 2)) - -# ╔═╡ 09ddf4d9-5ccb-4530-bfab-d11b864e872a -@test Base.hash(RemovePatch(["asd"])) == Base.hash(RemovePatch(["asd"])) - -# ╔═╡ d9e764db-94fc-44f7-8c2e-3d63f4809617 -@test RemovePatch(["asd"]) == RemovePatch(["asd"]) - -# ╔═╡ 99df99ad-aad5-4275-97d4-d1ceeb2f8d15 -@test Base.hash(RemovePatch(["aasd"])) != Base.hash(RemovePatch(["asd"])) - -# ╔═╡ 2d665639-7274-495a-ae9d-f358a8219bb7 -@test Base.hash(ReplacePatch(["asd"], Dict("a" => 2))) != - Base.hash(AddPatch(["asd"], Dict("a" => 2))) + ╠═╡ =# # ╔═╡ 595fdfd4-3960-4fbd-956c-509c4cf03473 +#=╠═╡ @test applypatch!(deepcopy(notebook1), notebook1_to_notebook2) == notebook2 - -# ╔═╡ 2983f6d4-c1ca-4b66-a2d3-f858b0df2b4c -@test fairly_equal(diff(large_dict_1, large_dict_2), [ - ReplacePatch(["cell_5","y"], [2,20]), - RemovePatch(["cell_2"]), - AddPatch(["hello"], Dict("b" => 2, "a" => 1)), -]) - -# ╔═╡ fdc427f0-dfe8-4114-beca-48fc15434534 -@test isempty(diff(many_items_1, many_items_1)) - -# ╔═╡ 61b81430-d26e-493c-96da-b6818e58c882 -@test fairly_equal(diff(many_items_1, many_items_2), [ - ReplacePatch(["cell_5","y"], [2,20]), - RemovePatch(["cell_2"]), - AddPatch(["hello"], Dict("b" => 2, "a" => 1)), -]) - -# ╔═╡ 62de3e79-4b4e-41df-8020-769c3c255c3e -@test isempty(diff(many_items_1, many_items_1)) + ╠═╡ =# # ╔═╡ c3e4738f-4568-4910-a211-6a46a9d447ee +#=╠═╡ @test applypatch!(Dict(:y => "x"), AddPatch([:x], "-")) == Dict(:y => "x", :x => "-") + ╠═╡ =# # ╔═╡ 0f094932-10e5-40f9-a3fc-db27a85b4999 +#=╠═╡ @test applypatch!(Dict(:x => "x"), AddPatch([:x], "-")) == Dict(:x => "-") + ╠═╡ =# # ╔═╡ a560fdca-ee12-469c-bda5-62d7203235b8 +#=╠═╡ @test applypatch!(Dict(:x => "x"), ReplacePatch([:x], "-")) == Dict(:x => "-") + ╠═╡ =# # ╔═╡ 01e3417e-334e-4a8d-b086-4bddc42737b3 +#=╠═╡ @test applypatch!(Dict(:y => "x"), ReplacePatch([:x], "-")) == Dict(:x => "-", :y => "x") + ╠═╡ =# # ╔═╡ 96a80a23-7c56-4c41-b489-15bc1c4e3700 +#=╠═╡ @test applypatch!(Dict(:x => "x"), RemovePatch([:x])) == Dict() + ╠═╡ =# + +# ╔═╡ df41caa7-f0fc-4b0d-ab3d-ebdab4804040 +# ╠═╡ skip_as_script = true +#=╠═╡ +md"*Should throw in strict mode:*" + ╠═╡ =# # ╔═╡ fac65755-2a2a-4a3c-b5a8-fc4f6d256754 +#=╠═╡ @test applypatch!(Dict(:y => "x"), RemovePatch([:x])) == Dict(:y => "x") + ╠═╡ =# -# ╔═╡ e7e8d076-2de1-11eb-0214-8160bb81370a -@skip_as_script @test notebook1 == deepcopy(notebook1) - -# ╔═╡ e9d2eba8-2de1-11eb-16bf-bd2a16537a97 -@skip_as_script x = 2 - -# ╔═╡ ea45104e-2de1-11eb-3248-5dd833d350e4 -@skip_as_script @test 1 + 1 == x +# ╔═╡ e55d1cea-2de1-11eb-0d0e-c95009eedc34 +# ╠═╡ skip_as_script = true +#=╠═╡ +md"## Testing" + ╠═╡ =# -# ╔═╡ ea6650bc-2de1-11eb-3016-4542c5c333a5 -@skip_as_script @test 1 + 1 + 1 == x +# ╔═╡ b05fcb88-3781-45d0-9f24-e88c339a72e5 +# ╠═╡ skip_as_script = true +#=╠═╡ +macro test2(expr) + quote nothing end +end + ╠═╡ =# -# ╔═╡ ea934d9c-2de1-11eb-3f1d-3b60465decde -@skip_as_script @test_throws String throw("Oh my god") == x +# ╔═╡ e7e8d076-2de1-11eb-0214-8160bb81370a +#=╠═╡ +@test notebook1 == deepcopy(notebook1) + ╠═╡ =# # ╔═╡ ee70e282-36d5-4772-8585-f50b9a67ca54 +# ╠═╡ skip_as_script = true +#=╠═╡ md"## Track" + ╠═╡ =# # ╔═╡ a3e8fe70-cbf5-4758-a0f2-d329d138728c +# ╠═╡ skip_as_script = true +#=╠═╡ function prettytime(time_ns::Number) suffices = ["ns", "μs", "ms", "s"] @@ -759,8 +911,11 @@ function prettytime(time_ns::Number) end return "$(roundedtime) $(suffix)" end + ╠═╡ =# # ╔═╡ 0e1c6442-9040-49d9-b754-173583db7ba2 +# ╠═╡ skip_as_script = true +#=╠═╡ begin Base.@kwdef struct Tracked expr @@ -841,8 +996,11 @@ begin end Tracked end + ╠═╡ =# # ╔═╡ 7618aef7-1884-4e32-992d-0fd988e1ab20 +# ╠═╡ skip_as_script = true +#=╠═╡ macro track(expr) times_ran_expr = :(1) expr_to_show = expr @@ -876,27 +1034,41 @@ macro track(expr) ) end end + ╠═╡ =# # ╔═╡ 7b8ab89b-bf56-4ddf-b220-b4881f4a2050 +#=╠═╡ @track Base.convert(JSONPatch, convert(Dict, add_patch)) == add_patch + ╠═╡ =# # ╔═╡ 48ccd28a-060d-4214-9a39-f4c4e506d1aa +#=╠═╡ @track Base.convert(JSONPatch, convert(Dict, remove_patch)) == remove_patch + ╠═╡ =# # ╔═╡ 34d86e02-dd34-4691-bb78-3023568a5d16 -@track Base.convert(JSONPatch, convert(Dict, replace_patch)) == replace_patch +#=╠═╡ +@track Base.convert(JSONPatch, _convert(Dict, replace_patch)) == replace_patch + ╠═╡ =# # ╔═╡ 95ff676d-73c8-44cb-ac35-af94418737e9 -@skip_as_script @track for _ in 1:100 diff(celldict1, celldict2) end +#=╠═╡ +@track for _ in 1:100 diff(celldict1, celldict2) end + ╠═╡ =# # ╔═╡ 8c069015-d922-4c60-9340-8d65c80b1a06 -@skip_as_script @track for _ in 1:1000 diff(large_dict_1, large_dict_1) end +#=╠═╡ +@track for _ in 1:1000 diff(large_dict_1, large_dict_1) end + ╠═╡ =# # ╔═╡ bc9a0822-1088-4ee7-8c79-98e06fd50f11 -@skip_as_script @track for _ in 1:1000 diff(large_dict_1, large_dict_2) end +#=╠═╡ +@track for _ in 1:1000 diff(large_dict_1, large_dict_2) end + ╠═╡ =# # ╔═╡ ddf1090c-5239-41df-ae4d-70aeb3a75f2b -@skip_as_script let +#=╠═╡ +let old = use_triple_equals_for_arrays[] use_triple_equals_for_arrays[] = true @@ -905,9 +1077,11 @@ end use_triple_equals_for_arrays[] = old result end + ╠═╡ =# # ╔═╡ 88009db3-f40e-4fd0-942a-c7f4a7eecb5a -@skip_as_script let +#=╠═╡ +let old = use_triple_equals_for_arrays[] use_triple_equals_for_arrays[] = true @@ -916,21 +1090,32 @@ end use_triple_equals_for_arrays[] = old result end + ╠═╡ =# # ╔═╡ c287009f-e864-45d2-a4d0-a525c988a6e0 -@skip_as_script @track for _ in 1:1000 diff(many_items_1, many_items_1) end +#=╠═╡ +@track for _ in 1:1000 diff(many_items_1, many_items_1) end + ╠═╡ =# # ╔═╡ 67a1ae27-f7df-4f84-8809-1cc6a9bcd1ce -@skip_as_script @track for _ in 1:1000 diff(many_items_1, many_items_2) end +#=╠═╡ +@track for _ in 1:1000 diff(many_items_1, many_items_2) end + ╠═╡ =# # ╔═╡ fa959806-3264-4dd5-9f94-ba369697689b -@skip_as_script @track for _ in 1:1000 direct_diff(cell2, cell1) end +#=╠═╡ +@track for _ in 1:1000 direct_diff(cell2, cell1) end + ╠═╡ =# # ╔═╡ a9088341-647c-4fe1-ab85-d7da049513ae -@skip_as_script @track for _ in 1:1000 diff(Deep(cell1), Deep(cell2)) end +#=╠═╡ +@track for _ in 1:1000 diff(Deep(cell1), Deep(cell2)) end + ╠═╡ =# # ╔═╡ 1a26eed8-670c-43bf-9726-2db84b1afdab -@skip_as_script @track sleep(0.1) +#=╠═╡ +@track sleep(0.1) + ╠═╡ =# # ╔═╡ Cell order: # ╟─d948dc6e-2de1-11eb-19e7-cb3bb66353b6 @@ -973,7 +1158,6 @@ end # ╟─07eeb122-6706-4544-a007-1c8d6581eec8 # ╠═b48e2c08-a94a-4247-877d-949d92dde626 # ╟─c59b30b9-f702-41f1-bb2e-1736c8cd5ede -# ╠═fafcb8b8-cde9-4f99-9bab-8128025953a4 # ╟─7feeee3a-3aec-47ce-b8d7-74a0d9b0b381 # ╠═921a130e-b028-4f91-b077-3bd79dcb6c6d # ╟─6d67f8a5-0e0c-4b6e-a267-96b34d580946 @@ -1014,7 +1198,7 @@ end # ╠═fd22b6af-5fd2-428a-8291-53e223ea692c # ╠═bcd5059b-b0d2-49d8-a756-92349aa56aca # ╠═e7fd6bab-c114-4f3e-b9ad-1af2d1147770 -# ╠═43c36ab7-e9ac-450a-8abe-435412f2be1d +# ╟─43c36ab7-e9ac-450a-8abe-435412f2be1d # ╟─2983f6d4-c1ca-4b66-a2d3-f858b0df2b4c # ╟─fdc427f0-dfe8-4114-beca-48fc15434534 # ╟─8c069015-d922-4c60-9340-8d65c80b1a06 @@ -1046,6 +1230,7 @@ end # ╠═48a45941-2489-4666-b4e5-88d3f82e5145 # ╠═752b2da3-ff24-4758-8843-186368069888 # ╟─3e285076-1d97-4728-87cf-f71b22569e57 +# ╠═d7ea6052-9d9f-48e3-92fb-250afd69e417 # ╠═dd87ca7e-2de1-11eb-2ec3-d5721c32f192 # ╟─c3e4738f-4568-4910-a211-6a46a9d447ee # ╟─a11e4082-4ff4-4c1b-9c74-c8fa7dcceaa6 @@ -1061,17 +1246,10 @@ end # ╟─df41caa7-f0fc-4b0d-ab3d-ebdab4804040 # ╟─fac65755-2a2a-4a3c-b5a8-fc4f6d256754 # ╟─e55d1cea-2de1-11eb-0d0e-c95009eedc34 +# ╠═3e07f976-6cd0-4841-9762-d40337bb0645 # ╠═e748600a-2de1-11eb-24be-d5f0ecab8fa4 # ╠═b05fcb88-3781-45d0-9f24-e88c339a72e5 # ╠═e7e8d076-2de1-11eb-0214-8160bb81370a -# ╟─e8d0c98a-2de1-11eb-37b9-e1df3f5cfa25 -# ╟─e907d862-2de1-11eb-11a9-4b3ac37cb0f3 -# ╟─e924a0be-2de1-11eb-2170-71d56e117af2 -# ╟─c2c2b057-a88f-4cc6-ada4-fc55ac29931e -# ╠═e9d2eba8-2de1-11eb-16bf-bd2a16537a97 -# ╠═ea45104e-2de1-11eb-3248-5dd833d350e4 -# ╠═ea6650bc-2de1-11eb-3016-4542c5c333a5 -# ╠═ea934d9c-2de1-11eb-3f1d-3b60465decde # ╟─ee70e282-36d5-4772-8585-f50b9a67ca54 # ╟─1a26eed8-670c-43bf-9726-2db84b1afdab # ╟─0e1c6442-9040-49d9-b754-173583db7ba2 diff --git a/src/webserver/FirebaseyUtils.jl b/src/webserver/FirebaseyUtils.jl new file mode 100644 index 0000000000..fe9448060a --- /dev/null +++ b/src/webserver/FirebaseyUtils.jl @@ -0,0 +1,430 @@ +### A Pluto.jl notebook ### +# v0.19.9 + +using Markdown +using InteractiveUtils + +# ╔═╡ 092c4b11-8b75-446f-b3ad-01fa858daebb +# ╠═╡ show_logs = false +# ╠═╡ skip_as_script = true +#=╠═╡ +# Only define this in Pluto using skip_as_script = true +begin + import Pkg + Pkg.activate(mktempdir()) + Pkg.add(Pkg.PackageSpec(name="PlutoTest")) + using PlutoTest +end + ╠═╡ =# + +# ╔═╡ 058a3333-0567-43b7-ac5f-1f6688325a08 +begin + """ + Mark an instance of a custom struct as immutable. The resulting object is also an `AbstractDict`, where the keys are the struct fields (converted to strings). + """ + struct ImmutableMarker{T} <: AbstractDict{String,Any} + source::T + end + + + function Base.getindex(ldict::ImmutableMarker, key::String) + Base.getfield(ldict.source, Symbol(key)) + end + # disabled because it's immutable! + # Base.setindex!(ldict::ImmutableMarker, args...) = Base.setindex!(ldict.source, args...) + # Base.delete!(ldict::ImmutableMarker, args...) = Base.delete!(ldict.source, args...) + Base.keys(ldict::ImmutableMarker{T}) where T = String.(fieldnames(T)) + # Base.values(ldict::ImmutableMarker) = Base.values(ldict.source) + Base.length(ldict::ImmutableMarker) = nfields(ldict.source) + Base.iterate(ldict::ImmutableMarker) = Base.iterate(ldict, 1) + function Base.iterate(ldict::ImmutableMarker{T}, i) where T + a = ldict.source + + if i <= nfields(a) + name = fieldname(T, i) + (String(name) => getfield(a, name), i + 1) + end + end + +end + +# ╔═╡ 55975e53-f70f-4b70-96d2-b144f74e7cde +# ╠═╡ skip_as_script = true +#=╠═╡ +struct A + x + y + z +end + ╠═╡ =# + +# ╔═╡ d7e0de85-5cb2-4036-a2e3-ca416ea83737 +#=╠═╡ +id1 = ImmutableMarker(A(1,"asdf",3)) + ╠═╡ =# + +# ╔═╡ 08350326-526e-4c34-ab27-df9fbf69243e +#=╠═╡ +id2 = ImmutableMarker(A(1,"asdf",4)) + ╠═╡ =# + +# ╔═╡ aa6192e8-410f-4924-8250-4775e21b1590 +#=╠═╡ +id1d, id2d = Dict(id1), Dict(id2) + ╠═╡ =# + +# ╔═╡ 273c7c85-8178-44a7-99f0-581754aeb8c8 +begin + """ + Mark a vector as being append-only: let Firebasey know that it can diff this array simply by comparing lengths, without looking at its contents. + + It was made specifically for logs: Logs are always appended, OR the whole log stream is reset. AppendonlyMarker is like SubArray (a view into another array) except we agree to only ever append to the source array. This way, firebase can just look at the index and diff based on that. + """ + struct AppendonlyMarker{T} <: AbstractVector{T} + mutable_source::Vector{T} + length_at_time_of_creation::Int + end + AppendonlyMarker(arr) = AppendonlyMarker(arr, length(arr)) + + # Poor mans vector-proxy + # I think this is enough for Pluto to show, and for msgpack to pack + function Base.size(arr::AppendonlyMarker) + return (arr.length_at_time_of_creation,) + end + Base.getindex(arr::AppendonlyMarker, index::Int) = arr.mutable_source[index] + Base.iterate(arr::AppendonlyMarker, args...) = Base.iterate(arr.mutable_source, args...) +end + +# ╔═╡ ef7032d1-a666-48a6-a56e-df175f5ed832 +# ╠═╡ skip_as_script = true +#=╠═╡ +md""" +## ImmutableMarker +""" + ╠═╡ =# + +# ╔═╡ 183cef1f-bfe9-42cd-8239-49e9ed00a7b6 +# ╠═╡ skip_as_script = true +#=╠═╡ +md""" +## AppendonlyMarker(s) + +Example of how to solve performance problems with Firebasey: +We make a new type with a specific diff function. +It might be very specific per problem, but that's fine for performance problems (I think). +It also keeps the performance solutions as separate modules/packages to whatever it is you're actually modeling. +""" + ╠═╡ =# + +# ╔═╡ 35d3bcd7-af51-466a-b4c4-cc055e74d01d +# ╠═╡ skip_as_script = true +#=╠═╡ +appendonly_1, appendonly_2 = let + array_1 = [1,2,3,4] + appendonly_1 = AppendonlyMarker(array_1) + push!(array_1, 5) + appendonly_2 = AppendonlyMarker(array_1) + + appendonly_1, appendonly_2 +end; + ╠═╡ =# + +# ╔═╡ 1017f6cc-58ac-4c7b-a6d0-a03f5e387f1b +# ╠═╡ skip_as_script = true +#=╠═╡ +appendonly_1_large, appendonly_2_large = let + large_array_1 = [ + Dict{String,Any}( + "x" => 1, + "y" => [1,2,3,4], + "z" => "hi", + ) + for i in 1:10000 + ]; + appendonly_1 = AppendonlyMarker(large_array_1) + push!(large_array_1, Dict("x" => 5)) + appendonly_2 = AppendonlyMarker(large_array_1) + + appendonly_1, appendonly_2 +end; + ╠═╡ =# + +# ╔═╡ 06492e8d-4500-4efe-80ee-55bf1ee2348c +#=╠═╡ +@test length([AppendonlyMarker([1,2,3])...]) == 3 + ╠═╡ =# + +# ╔═╡ 2284ae12-5b8c-4542-81fa-c4d34f2483e7 +# @test length([AppendonlyMarker([1,2,3], 1)...]) == 1 + +# ╔═╡ dc5cd268-9cfb-49bf-87fb-5b7db4fa6e3c +# ╠═╡ skip_as_script = true +#=╠═╡ +md"## Import Firebasey when running inside notebook" + ╠═╡ =# + +# ╔═╡ 0c2f23d8-8e98-47b7-9c4f-5daa70a6c7fb +# OH how I wish I would put in the time to refactor with fromFile or SOEMTGHINLAS LDKJ JULIA WHY ARE YOU LIKE THIS GROW UP +if !@isdefined(Firebasey) + Firebasey = let + wrapper_module = Module() + Core.eval(wrapper_module, :(module Firebasey + include("Firebasey.jl") + end + )) + wrapper_module.Firebasey + end +end + +# ╔═╡ 2903d17e-c6fd-4cea-8585-4db26a00b0e7 +function Firebasey.diff(a::AppendonlyMarker, b::AppendonlyMarker) + if a.mutable_source !== b.mutable_source + [Firebasey.ReplacePatch([], b)] + else + if a.length_at_time_of_creation > b.length_at_time_of_creation + throw(ErrorException("Not really supposed to diff AppendonlyMarker with the original being longer than the next version (you know, 'append only' and al)")) + end + + map(a.length_at_time_of_creation+1:b.length_at_time_of_creation) do index + Firebasey.AddPatch([index], b.mutable_source[index]) + end + end +end + +# ╔═╡ 129dee79-61c0-4524-9bef-388837f035bb +function Firebasey.diff(a::ImmutableMarker, b::ImmutableMarker) + if a.source !== b.source + Firebasey.diff(Dict(a), Dict(b)) + # Firebasey.JSONPatch[Firebasey.ReplacePatch([], b)] + else + Firebasey.JSONPatch[] + end +end + +# ╔═╡ 138d2cc2-59ba-4f76-bf66-ecdb98cf4fd5 +#=╠═╡ +Firebasey.diff(id1, id2) + ╠═╡ =# + +# ╔═╡ 8537488d-2ff9-42b7-8bfc-72d43fca713f +#=╠═╡ +@test Firebasey.diff(appendonly_1, appendonly_2) == [Firebasey.AddPatch([5], 5)] + ╠═╡ =# + +# ╔═╡ 721e3c90-15ae-43f2-9234-57b38e3e6b69 +# ╠═╡ skip_as_script = true +#=╠═╡ +md""" +## Track +""" + ╠═╡ =# + +# ╔═╡ e830792c-c809-4fde-ae55-8ae01b4c04b9 +# ╠═╡ skip_as_script = true +#=╠═╡ +function prettytime(time_ns::Number) + suffices = ["ns", "μs", "ms", "s"] + + current_amount = time_ns + suffix = "" + for current_suffix in suffices + if current_amount >= 1000.0 + current_amount = current_amount / 1000.0 + else + suffix = current_suffix + break + end + end + + # const roundedtime = time_ns.toFixed(time_ns >= 100.0 ? 0 : 1) + roundedtime = if current_amount >= 100.0 + round(current_amount; digits=0) + else + round(current_amount; digits=1) + end + return "$(roundedtime) $(suffix)" +end + ╠═╡ =# + +# ╔═╡ 16b03608-0f5f-421a-bab4-89365528b0b4 +# ╠═╡ skip_as_script = true +#=╠═╡ +begin + Base.@kwdef struct Tracked + expr + value + time + bytes + times_ran = 1 + which = nothing + code_info = nothing + end + function Base.show(io::IO, mime::MIME"text/html", value::Tracked) + times_ran = if value.times_ran === 1 + "" + else + """ ($(value.times_ran)×)""" + end + # method = sprint(show, MIME("text/plain"), value.which) + code_info = if value.code_info ≠ nothing + codelength = length(value.code_info.first.code) + "$(codelength) frames in @code_typed" + else + "" + end + color = if value.time > 1 + "red" + elseif value.time > 0.001 + "orange" + elseif value.time > 0.0001 + "blue" + else + "green" + end + + + show(io, mime, HTML(""" +
+
+
+
+ $(value.expr) +
+ $(prettytime(value.time * 1e9 / value.times_ran)) + $(times_ran) +
+
$(code_info)
+ +
+ +
+ """)) + end + Tracked +end + ╠═╡ =# + +# ╔═╡ 875fd249-37cc-49da-8a7d-381fe0e21063 +#=╠═╡ +macro track(expr) + times_ran_expr = :(1) + expr_to_show = expr + if expr.head == :for + @assert expr.args[1].head == :(=) + times_ran_expr = expr.args[1].args[2] + expr_to_show = expr.args[2].args[2] + end + + Tracked # reference so that baby Pluto understands + + quote + local times_ran = length($(esc(times_ran_expr))) + local value, time, bytes = @timed $(esc(expr)) + + local method = nothing + local code_info = nothing + try + # Uhhh + method = @which $(expr_to_show) + code_info = @code_typed $(expr_to_show) + catch nothing end + Tracked( + expr=$(QuoteNode(expr_to_show)), + value=value, + time=time, + bytes=bytes, + times_ran=times_ran, + which=method, + code_info=code_info + ) + end +end + ╠═╡ =# + +# ╔═╡ a5f43f47-6189-413f-95a0-d98f927bb7ce +#=╠═╡ +@track for _ in 1:1000 Firebasey.diff(id1, id1) end + ╠═╡ =# + +# ╔═╡ ab5089cc-fec8-43b9-9aa4-d6fa96e231e0 +#=╠═╡ +@track for _ in 1:1000 Firebasey.diff(id1d, id1d) end + ╠═╡ =# + +# ╔═╡ a84dcdc3-e9ed-4bf5-9bec-c9cbfc267c17 +#=╠═╡ +@track for _ in 1:1000 Firebasey.diff(id1, id2) end + ╠═╡ =# + +# ╔═╡ f696bb85-0bbd-43c9-99ea-533816bc8e0d +#=╠═╡ +@track for _ in 1:1000 Firebasey.diff(id1d, id2d) end + ╠═╡ =# + +# ╔═╡ 37fe8c10-09f0-4f72-8cfd-9ce044c78c13 +#=╠═╡ +@track for _ in 1:1000 Firebasey.diff(appendonly_1_large, appendonly_2_large) end + ╠═╡ =# + +# ╔═╡ 9862ee48-48a0-4178-8ec4-306792827e17 +#=╠═╡ +@track sleep(0.1) + ╠═╡ =# + +# ╔═╡ Cell order: +# ╟─ef7032d1-a666-48a6-a56e-df175f5ed832 +# ╠═058a3333-0567-43b7-ac5f-1f6688325a08 +# ╠═129dee79-61c0-4524-9bef-388837f035bb +# ╠═55975e53-f70f-4b70-96d2-b144f74e7cde +# ╠═d7e0de85-5cb2-4036-a2e3-ca416ea83737 +# ╠═08350326-526e-4c34-ab27-df9fbf69243e +# ╠═138d2cc2-59ba-4f76-bf66-ecdb98cf4fd5 +# ╠═aa6192e8-410f-4924-8250-4775e21b1590 +# ╟─a5f43f47-6189-413f-95a0-d98f927bb7ce +# ╟─ab5089cc-fec8-43b9-9aa4-d6fa96e231e0 +# ╟─a84dcdc3-e9ed-4bf5-9bec-c9cbfc267c17 +# ╟─f696bb85-0bbd-43c9-99ea-533816bc8e0d +# ╟─183cef1f-bfe9-42cd-8239-49e9ed00a7b6 +# ╠═273c7c85-8178-44a7-99f0-581754aeb8c8 +# ╠═2903d17e-c6fd-4cea-8585-4db26a00b0e7 +# ╠═35d3bcd7-af51-466a-b4c4-cc055e74d01d +# ╠═1017f6cc-58ac-4c7b-a6d0-a03f5e387f1b +# ╟─06492e8d-4500-4efe-80ee-55bf1ee2348c +# ╠═2284ae12-5b8c-4542-81fa-c4d34f2483e7 +# ╟─8537488d-2ff9-42b7-8bfc-72d43fca713f +# ╟─37fe8c10-09f0-4f72-8cfd-9ce044c78c13 +# ╟─dc5cd268-9cfb-49bf-87fb-5b7db4fa6e3c +# ╠═0c2f23d8-8e98-47b7-9c4f-5daa70a6c7fb +# ╠═092c4b11-8b75-446f-b3ad-01fa858daebb +# ╟─721e3c90-15ae-43f2-9234-57b38e3e6b69 +# ╟─9862ee48-48a0-4178-8ec4-306792827e17 +# ╟─16b03608-0f5f-421a-bab4-89365528b0b4 +# ╟─875fd249-37cc-49da-8a7d-381fe0e21063 +# ╟─e830792c-c809-4fde-ae55-8ae01b4c04b9 diff --git a/src/webserver/MsgPack.jl b/src/webserver/MsgPack.jl index 1bbbad5cfb..f0b5f135ad 100644 --- a/src/webserver/MsgPack.jl +++ b/src/webserver/MsgPack.jl @@ -31,12 +31,16 @@ MsgPack.msgpack_type(::Type{Configuration.CompilerOptions}) = MsgPack.StructType MsgPack.msgpack_type(::Type{Configuration.ServerOptions}) = MsgPack.StructType() MsgPack.msgpack_type(::Type{Configuration.SecurityOptions}) = MsgPack.StructType() +# Don't try to send callback functions which can't be serialized (see ServerOptions.event_listener) +MsgPack.msgpack_type(::Type{Function}) = MsgPack.NilType() +MsgPack.to_msgpack(::MsgPack.NilType, ::Function) = nothing + # We want typed integer arrays to arrive as JS typed integer arrays: const JSTypedIntSupport = [Int8, UInt8, Int16, UInt16, Int32, UInt32, Float32, Float64] -JSTypedInt = Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Float32,Float64} +const JSTypedInt = Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Float32,Float64} MsgPack.msgpack_type(::Type{Vector{T}}) where T <: JSTypedInt = MsgPack.ExtensionType() -MsgPack.to_msgpack(::MsgPack.ExtensionType, x::Vector{T}) where T <: JSTypedInt = let +function MsgPack.to_msgpack(::MsgPack.ExtensionType, x::Vector{T}) where T <: JSTypedInt type = findfirst(isequal(T), JSTypedIntSupport) + 0x10 MsgPack.Extension(type, reinterpret(UInt8, x)) end @@ -81,4 +85,5 @@ end function unpack(args...) MsgPack.unpack(args...) |> decode_extension_and_addbits -end \ No newline at end of file +end +precompile(unpack, (Vector{UInt8},)) \ No newline at end of file diff --git a/src/webserver/PutUpdates.jl b/src/webserver/PutUpdates.jl index dcac8e9dd5..4256cf520e 100644 --- a/src/webserver/PutUpdates.jl +++ b/src/webserver/PutUpdates.jl @@ -1,4 +1,20 @@ +function serialize_message_to_stream(io::IO, message::UpdateMessage) + to_send = Dict(:type => message.type, :message => message.message) + if message.notebook !== nothing + to_send[:notebook_id] = message.notebook.notebook_id + end + if message.cell !== nothing + to_send[:cell_id] = message.cell.cell_id + end + if message.initiator !== nothing + to_send[:initiator_id] = message.initiator.client_id + to_send[:request_id] = message.initiator.request_id + end + + pack(io, to_send) +end + function serialize_message_to_stream(io::IO, message::UpdateMessage, recipient::ClientSession) to_send = Dict{Symbol,Any}( :type => message.type, @@ -19,6 +35,12 @@ function serialize_message_to_stream(io::IO, message::UpdateMessage, recipient:: pack(io, to_send) end +function serialize_message(message::UpdateMessage) + io = IOBuffer() + serialize_message_to_stream(io, message) + take!(io) +end + function serialize_message(message::UpdateMessage, recipient::ClientSession) sprint(serialize_message_to_stream, message, recipient) end @@ -69,18 +91,34 @@ end # https://github.com/JuliaWeb/HTTP.jl/issues/382 const flushtoken = Token() +function send_message(stream::HTTP.WebSocket, msg) + HTTP.send(stream, serialize_message(msg)) +end +function send_message(stream::IO, msg) + write(stream, serialize_message(msg)) +end + +function is_stream_open(stream::HTTP.WebSocket) + !HTTP.WebSockets.isclosed(stream) +end +function is_stream_open(io::IO) + isopen(io) +end + function flushclient(client::ClientSession) take!(flushtoken) while isready(client.pendingupdates) next_to_send = take!(client.pendingupdates) - + try if client.stream !== nothing - if isopen(client.stream) - if client.stream isa HTTP.WebSockets.WebSocket - client.stream.frame_type = HTTP.WebSockets.WS_BINARY + if is_stream_open(client.stream) + let + lag = client.simulated_lag + (lag > 0) && sleep(lag * (0.5 + rand())) # sleep(0) would yield to the process manager which we dont want end - write(client.stream, serialize_message(next_to_send, client)) + + send_message(client.stream, next_to_send) else put!(flushtoken) return false diff --git a/src/webserver/REPLTools.jl b/src/webserver/REPLTools.jl index b4b5fd9b35..7da202f6ca 100644 --- a/src/webserver/REPLTools.jl +++ b/src/webserver/REPLTools.jl @@ -1,5 +1,5 @@ import FuzzyCompletions: complete_path, completion_text, score -import Distributed +import Malt import .PkgCompat: package_completions using Markdown import REPL @@ -17,8 +17,12 @@ responses[:completepath] = function response_completepath(🙋::ClientRequest) pos = lastindex(path) results, loc, found = complete_path(path, pos) + # too many candiates otherwise. -0.1 instead of 0 to enable autocompletions for paths: `/` or `/asdf/` isenough(x) = x ≥ -0.1 - filter!(isenough ∘ score, results) # too many candiates otherwise. -0.1 instead of 0 to enable autocompletions for paths: `/` or `/asdf/` + ishidden(path_completion) = let p = path_completion.path + startswith(basename(isdirpath(p) ? dirname(p) : p), ".") + end + filter!(p -> !ishidden(p) && (isenough ∘ score)(p), results) start_utf8 = let # REPLCompletions takes into account that spaces need to be prefixed with `\` in the shell, so it subtracts the number of spaces in the filename from `start`: @@ -69,20 +73,23 @@ responses[:complete] = function response_complete(🙋::ClientRequest) query = 🙋.body["query"] pos = lastindex(query) # the query is cut at the cursor position by the front-end, so the cursor position is just the last legal index - workspace = WorkspaceManager.get_workspace((🙋.session, 🙋.notebook)) - results, loc, found = if package_name_to_complete(query) !== nothing p = package_name_to_complete(query) cs = package_completions(p) |> sort [(c,"package",true) for c in cs], (nextind(query, pos-length(p)):pos), true else - if will_run_code(🙋.notebook) && isready(workspace.dowork_token) + workspace = WorkspaceManager.get_workspace((🙋.session, 🙋.notebook); allow_creation=false) + + if will_run_code(🙋.notebook) && workspace isa WorkspaceManager.Workspace && isready(workspace.dowork_token) # we don't use eval_format_fetch_in_workspace because we don't want the output to be string-formatted. # This works in this particular case, because the return object, a `Completion`, exists in this scope too. - Distributed.remotecall_eval(Main, workspace.pid, :(PlutoRunner.completion_fetcher( - $query, $pos, - getfield(Main, $(QuoteNode(workspace.module_name))), - ))) + Malt.remote_eval_fetch(workspace.worker, quote + PlutoRunner.completion_fetcher( + $query, + $pos, + getfield(Main, $(QuoteNode(workspace.module_name))), + ) + end) else # We can at least autocomplete general julia things: PlutoRunner.completion_fetcher(query, pos, Main) @@ -109,22 +116,31 @@ responses[:docs] = function response_docs(🙋::ClientRequest) # Expand string macro calls to their macro form: # `html"` should yield `@html_str` and # `Markdown.md"` should yield `@Markdown.md_str`. (Ideally `Markdown.@md_str` but the former is easier) - if endswith(query, "\"") && query != "\"" - query = "@$(query[begin:end-1])_str" + if endswith(query, '"') && query != "\"" + query = string("@", SubString(query, firstindex(query), prevind(query, lastindex(query))), "_str") end - doc_html, status = if REPL.lookup_doc(Symbol(query)) isa Markdown.MD + workspace = WorkspaceManager.get_workspace((🙋.session, 🙋.notebook); allow_creation=false) + + query_as_symbol = Symbol(query) + base_binding = Docs.Binding(Base, query_as_symbol) + doc_md = Docs.doc(base_binding) + + doc_html, status = if doc_md isa Markdown.MD && + haskey(doc_md.meta, :results) && !isempty(doc_md.meta[:results]) + # available in Base, no need to ask worker - doc_md = REPL.lookup_doc(Symbol(query)) + PlutoRunner.improve_docs!(doc_md, query_as_symbol, base_binding) + (repr(MIME("text/html"), doc_md), :👍) else - workspace = WorkspaceManager.get_workspace((🙋.session, 🙋.notebook)) - - if will_run_code(🙋.notebook) && isready(workspace.dowork_token) - Distributed.remotecall_eval(Main, workspace.pid, :(PlutoRunner.doc_fetcher( - $query, - getfield(Main, $(QuoteNode(workspace.module_name))), - ))) + if will_run_code(🙋.notebook) && workspace isa WorkspaceManager.Workspace && isready(workspace.dowork_token) + Malt.remote_eval_fetch(workspace.worker, quote + PlutoRunner.doc_fetcher( + $query, + getfield(Main, $(QuoteNode(workspace.module_name))), + ) + end) else (nothing, :⌛) end diff --git a/src/webserver/Router.jl b/src/webserver/Router.jl new file mode 100644 index 0000000000..cfbfed3d28 --- /dev/null +++ b/src/webserver/Router.jl @@ -0,0 +1,251 @@ + +function http_router_for(session::ServerSession) + router = HTTP.Router(default_404) + security = session.options.security + + function create_serve_onefile(path) + return request::HTTP.Request -> asset_response(normpath(path)) + end + + HTTP.register!(router, "GET", "/", create_serve_onefile(project_relative_path(frontend_directory(), "index.html"))) + HTTP.register!(router, "GET", "/edit", create_serve_onefile(project_relative_path(frontend_directory(), "editor.html"))) + + HTTP.register!(router, "GET", "/ping", r -> HTTP.Response(200, "OK!")) + HTTP.register!(router, "GET", "/possible_binder_token_please", r -> session.binder_token === nothing ? HTTP.Response(200,"") : HTTP.Response(200, session.binder_token)) + + function try_launch_notebook_response( + action::Function, path_or_url::AbstractString; + as_redirect=true, + title="", advice="", home_url="./", + action_kwargs... + ) + try + nb = action(session, path_or_url; action_kwargs...) + notebook_response(nb; home_url, as_redirect) + catch e + if e isa SessionActions.NotebookIsRunningException + notebook_response(e.notebook; home_url, as_redirect) + else + error_response(500, title, advice, sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + end + + function serve_newfile(request::HTTP.Request) + notebook_response(SessionActions.new(session); as_redirect=(request.method == "GET")) + end + HTTP.register!(router, "GET", "/new", serve_newfile) + HTTP.register!(router, "POST", "/new", serve_newfile) + + # This is not in Dynamic.jl because of bookmarks, how HTML works, + # real loading bars and the rest; Same for CustomLaunchEvent + function serve_openfile(request::HTTP.Request) + try + uri = HTTP.URI(request.target) + query = HTTP.queryparams(uri) + as_sample = haskey(query, "as_sample") + execution_allowed = haskey(query, "execution_allowed") + if haskey(query, "path") + path = tamepath(maybe_convert_path_to_wsl(query["path"])) + if isfile(path) + return try_launch_notebook_response( + SessionActions.open, path; + execution_allowed, + as_redirect=(request.method == "GET"), + as_sample, + risky_file_source=nothing, + title="Failed to load notebook", + advice="The file $(htmlesc(path)) could not be loaded. Please report this error!", + ) + else + return error_response(404, "Can't find a file here", "Please check whether $(htmlesc(path)) exists.") + end + elseif haskey(query, "url") + url = query["url"] + return try_launch_notebook_response( + SessionActions.open_url, url; + execution_allowed, + as_redirect=(request.method == "GET"), + as_sample, + risky_file_source=url, + title="Failed to load notebook", + advice="The notebook from $(htmlesc(url)) could not be loaded. Please report this error!" + ) + else + # You can ask Pluto to handle CustomLaunch events + # and do some magic with how you open files. + # You are responsible to keep this up to date. + # See Events.jl for types and explanation + # + maybe_notebook_response = try_event_call(session, CustomLaunchEvent(query, request, try_launch_notebook_response)) + isnothing(maybe_notebook_response) && return error("Empty request") + return maybe_notebook_response + end + catch e + return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + + HTTP.register!(router, "GET", "/open", serve_openfile) + HTTP.register!(router, "POST", "/open", serve_openfile) + + + # normally shutdown is done through Dynamic.jl, with the exception of shutdowns made from the desktop app + function serve_shutdown(request::HTTP.Request) + notebook = notebook_from_uri(request) + SessionActions.shutdown(session, notebook) + return HTTP.Response(200) + end + + HTTP.register!(router, "GET", "/shutdown", serve_shutdown) + HTTP.register!(router, "POST", "/shutdown", serve_shutdown) + + + # used in desktop app + # looks like `/move?id=&newpath=`` + function serve_move(request::HTTP.Request) + uri = HTTP.URI(request.target) + query = HTTP.queryparams(uri) + + notebook = notebook_from_uri(request) + newpath = query["newpath"] + + try + SessionActions.move(session, notebook, newpath) + HTTP.Response(200, notebook.path) + catch e + error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + + HTTP.register!(router, "GET", "/move", serve_move) + HTTP.register!(router, "POST", "/move", serve_move) + + + function serve_notebooklist(request::HTTP.Request) + return HTTP.Response(200, pack(Dict(k => v.path for (k, v) in session.notebooks))) + end + + HTTP.register!(router, "GET", "/notebooklist", serve_notebooklist) + + + function serve_sample(request::HTTP.Request) + uri = HTTP.URI(request.target) + sample_filename = split(HTTP.unescapeuri(uri.path), "sample/")[2] + sample_path = project_relative_path("sample", sample_filename) + + try_launch_notebook_response( + SessionActions.open, sample_path; + as_redirect=(request.method == "GET"), + home_url="../", + as_sample=true, + title="Failed to load sample", + advice="Please report this error!" + ) + end + HTTP.register!(router, "GET", "/sample/*", serve_sample) + HTTP.register!(router, "POST","/sample/*", serve_sample) + + notebook_from_uri(request) = let + uri = HTTP.URI(request.target) + query = HTTP.queryparams(uri) + id = UUID(query["id"]) + session.notebooks[id] + end + function serve_notebookfile(request::HTTP.Request) + try + notebook = notebook_from_uri(request) + response = HTTP.Response(200, sprint(save_notebook, notebook)) + HTTP.setheader(response, "Content-Type" => "text/julia; charset=utf-8") + HTTP.setheader(response, "Content-Disposition" => "inline; filename=\"$(basename(notebook.path))\"") + response + catch e + return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + HTTP.register!(router, "GET", "/notebookfile", serve_notebookfile) + + function serve_statefile(request::HTTP.Request) + try + notebook = notebook_from_uri(request) + response = HTTP.Response(200, Pluto.pack(Pluto.notebook_to_js(notebook))) + HTTP.setheader(response, "Content-Type" => "application/octet-stream") + HTTP.setheader(response, "Content-Disposition" => "attachment; filename=\"$(without_pluto_file_extension(basename(notebook.path))).plutostate\"") + response + catch e + return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + HTTP.register!(router, "GET", "/statefile", serve_statefile) + + function serve_notebookexport(request::HTTP.Request) + try + notebook = notebook_from_uri(request) + response = HTTP.Response(200, generate_html(notebook)) + HTTP.setheader(response, "Content-Type" => "text/html; charset=utf-8") + HTTP.setheader(response, "Content-Disposition" => "attachment; filename=\"$(without_pluto_file_extension(basename(notebook.path))).html\"") + response + catch e + return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) + end + end + HTTP.register!(router, "GET", "/notebookexport", serve_notebookexport) + + function serve_notebookupload(request::HTTP.Request) + uri = HTTP.URI(request.target) + query = HTTP.queryparams(uri) + + save_path = SessionActions.save_upload(request.body; filename_base=get(query, "name", nothing)) + + try_launch_notebook_response( + SessionActions.open, + save_path; + as_redirect=false, + as_sample=false, + execution_allowed=haskey(query, "execution_allowed"), + clear_frontmatter=haskey(query, "clear_frontmatter"), + title="Failed to load notebook", + advice="The contents could not be read as a Pluto notebook file. When copying contents from somewhere else, make sure that you copy the entire notebook file. You can also report this error!" + ) + end + HTTP.register!(router, "POST", "/notebookupload", serve_notebookupload) + + function serve_asset(request::HTTP.Request) + uri = HTTP.URI(request.target) + filepath = project_relative_path(frontend_directory(), relpath(HTTP.unescapeuri(uri.path), "/")) + asset_response(filepath; cacheable=should_cache(filepath)) + end + HTTP.register!(router, "GET", "/**", serve_asset) + + HTTP.register!(router, "GET", "/favicon.ico", create_serve_onefile(project_relative_path(frontend_directory(allow_bundled=false), "img", "favicon.ico"))) + + return scoped_router(session.options.server.base_url, router) +end + + + +""" + scoped_router(base_url::String, base_router::HTTP.Router)::HTTP.Router + +Returns a new `HTTP.Router` which delegates all requests to `base_router` but with requests trimmed +so that they seem like they arrived at `/**` instead of `/\$base_url/**`. +""" +function scoped_router(base_url, base_router) + base_url == "/" && return base_router + + @assert startswith(base_url, '/') "base_url \"$base_url\" should start with a '/'" + @assert endswith(base_url, '/') "base_url \"$base_url\" should end with a '/'" + @assert !occursin('*', base_url) "'*' not allowed in base_url \"$base_url\" " + + function handler(request) + request.target = request.target[length(base_url):end] + return base_router(request) + end + + router = HTTP.Router(base_router._404, base_router._405) + HTTP.register!(router, base_url * "**", handler) + HTTP.register!(router, base_url, handler) + + return router +end + diff --git a/src/webserver/Session.jl b/src/webserver/Session.jl index 3de8bb0268..36b912ae82 100644 --- a/src/webserver/Session.jl +++ b/src/webserver/Session.jl @@ -10,10 +10,11 @@ mutable struct ClientSession stream::Any connected_notebook::Union{Notebook,Nothing} pendingupdates::Channel + simulated_lag::Float64 end -ClientSession(id::Symbol, stream) = let - ClientSession(id, stream, nothing, Channel(1024)) +ClientSession(id::Symbol, stream, simulated_lag=0.0) = let + ClientSession(id, stream, nothing, Channel(1024), simulated_lag) end "A combination of _client ID_ and a _request ID_. The front-end generates a unqique ID for every request that it sends. The back-end (the stuff you are currently reading) can respond to a specific request. In that case, the response does not go through the normal message handlers in the front-end, but it flies directly to the place where the message was sent. (It resolves the promise returned by `send(...)`.)" @@ -47,7 +48,6 @@ Base.@kwdef mutable struct ServerSession secret::String = String(rand(('a':'z') ∪ ('A':'Z') ∪ ('0':'9'), 8)) binder_token::Union{String,Nothing} = nothing options::Configuration.Options = Configuration.Options() - event_listener::Function = function(a::PlutoEvent) #= @info "$(typeof(a))" =# end end function save_notebook(session::ServerSession, notebook::Notebook) @@ -82,7 +82,8 @@ function clientupdate_notebook_list(notebooks; initiator::Union{Initiator,Nothin :notebook_id => notebook.notebook_id, :path => notebook.path, :in_temp_dir => startswith(notebook.path, new_notebooks_directory()), - :shortpath => basename(notebook.path) + :shortpath => basename(notebook.path), + :process_status => notebook.process_status, ) for notebook in values(notebooks) ] ), nothing, nothing, initiator) diff --git a/src/webserver/SessionActions.jl b/src/webserver/SessionActions.jl index eb02ba29f1..a8ef828d12 100644 --- a/src/webserver/SessionActions.jl +++ b/src/webserver/SessionActions.jl @@ -1,8 +1,9 @@ module SessionActions -import ..Pluto: ServerSession, Notebook, Cell, emptynotebook, tamepath, new_notebooks_directory, without_pluto_file_extension, numbered_until_new, readwrite, update_save_run!, update_from_file, wait_until_file_unchanged, putnotebookupdates!, putplutoupdates!, load_notebook, clientupdate_notebook_list, WorkspaceManager, try_event_call, NewNotebookEvent, OpenNotebookEvent, ShutdownNotebookEvent, @asynclog +import ..Pluto: Pluto, Status, ServerSession, Notebook, Cell, emptynotebook, tamepath, new_notebooks_directory, without_pluto_file_extension, numbered_until_new, cutename, readwrite, update_save_run!, update_nbpkg_cache!, update_from_file, wait_until_file_unchanged, putnotebookupdates!, putplutoupdates!, load_notebook, clientupdate_notebook_list, WorkspaceManager, try_event_call, NewNotebookEvent, OpenNotebookEvent, ShutdownNotebookEvent, @asynclog, ProcessStatus, maybe_convert_path_to_wsl, move_notebook!, throttled using FileWatching import ..Pluto.DownloadCool: download_cool +import HTTP import UUIDs: UUID, uuid1 @@ -19,12 +20,37 @@ function Base.showerror(io::IO, e::UserError) end function open_url(session::ServerSession, url::AbstractString; kwargs...) - path = download_cool(url, emptynotebook().path) - open(session, path; kwargs...) + name_from_url = startswith(url, r"https?://") ? strip(HTTP.unescapeuri(splitext(basename(HTTP.URI(url).path))[1])) : "" + new_name = isempty(name_from_url) ? cutename() : name_from_url + + random_notebook = emptynotebook() + random_notebook.path = numbered_until_new( + joinpath( + new_notebooks_directory(), + new_name + ); suffix=".jl") + + path = download_cool(url, random_notebook.path) + result = try_event_call(session, NewNotebookEvent()) + notebook = if result isa UUID + open(session, path; notebook_id=result, kwargs...) + else + open(session, path; kwargs...) + end + return notebook end "Open the notebook at `path` into `session::ServerSession` and run it. Returns the `Notebook`." -function open(session::ServerSession, path::AbstractString; run_async=true, compiler_options=nothing, as_sample=false, notebook_id::UUID=uuid1()) +function open(session::ServerSession, path::AbstractString; + execution_allowed::Bool=true, + run_async::Bool=true, + compiler_options=nothing, + as_sample::Bool=false, + risky_file_source::Union{Nothing,String}=nothing, + clear_frontmatter::Bool=false, + notebook_id::UUID=uuid1() +) + path = maybe_convert_path_to_wsl(path) if as_sample new_filename = "sample " * without_pluto_file_extension(basename(path)) new_path = numbered_until_new(joinpath(new_notebooks_directory(), new_filename); suffix=".jl") @@ -33,34 +59,51 @@ function open(session::ServerSession, path::AbstractString; run_async=true, comp path = new_path end - for nb in values(session.notebooks) - if isfile(nb.path) && realpath(nb.path) == realpath(tamepath(path)) - throw(NotebookIsRunningException(nb)) + for notebook in values(session.notebooks) + if isfile(notebook.path) && realpath(notebook.path) == realpath(tamepath(path)) + throw(NotebookIsRunningException(notebook)) end end - nb = load_notebook(tamepath(path); disable_writing_notebook_files=session.options.server.disable_writing_notebook_files) - nb.notebook_id = notebook_id + notebook = load_notebook(tamepath(path); disable_writing_notebook_files=session.options.server.disable_writing_notebook_files) + execution_allowed = execution_allowed && !haskey(notebook.metadata, "risky_file_source") + + notebook.notebook_id = notebook_id + if !isnothing(risky_file_source) + notebook.metadata["risky_file_source"] = risky_file_source + end + notebook.process_status = execution_allowed ? ProcessStatus.starting : ProcessStatus.waiting_for_permission # overwrites the notebook environment if specified if compiler_options !== nothing - nb.compiler_options = compiler_options + notebook.compiler_options = compiler_options end - - session.notebooks[nb.notebook_id] = nb - for c in nb.cells - c.queued = session.options.evaluation.run_notebook_on_load + if clear_frontmatter + Pluto.set_frontmatter!(notebook, nothing) end - update_save_run!(session, nb, nb.cells; run_async=run_async, prerender_text=true) + session.notebooks[notebook.notebook_id] = notebook - add(session, nb; run_async=run_async) - try_event_call(session, OpenNotebookEvent(nb)) - nb + if execution_allowed && session.options.evaluation.run_notebook_on_load + Pluto._report_business_cells_planned!(notebook) + end + + if !execution_allowed + Status.delete_business!(notebook.status_tree, :run) + Status.delete_business!(notebook.status_tree, :workspace) + Status.delete_business!(notebook.status_tree, :pkg) + end + + update_nbpkg_cache!(notebook) + + update_save_run!(session, notebook, notebook.cells; run_async, prerender_text=true) + add(session, notebook; run_async) + try_event_call(session, OpenNotebookEvent(notebook)) + return notebook end -function add(session::ServerSession, nb::Notebook; run_async::Bool=true) - session.notebooks[nb.notebook_id] = nb +function add(session::ServerSession, notebook::Notebook; run_async::Bool=true) + session.notebooks[notebook.notebook_id] = notebook if run_async @asynclog putplutoupdates!(session, clientupdate_notebook_list(session.notebooks)) @@ -69,134 +112,136 @@ function add(session::ServerSession, nb::Notebook; run_async::Bool=true) end - running = Ref(false) - function update_from_file_throttled() - if !running[] - running[] = true - - @info "Updating from file..." - - - sleep(0.1) ## There seems to be a synchronization issue if your OS is VERYFAST - wait_until_file_unchanged(nb.path, .3) - - # call update_from_file. If it returns false, that means that the notebook file was corrupt, so we try again, a maximum of 10 times. - for i in 1:10 - if update_from_file(session, nb) - break + update_from_file_throttled = let + running = Ref(false) + function() + if !running[] + running[] = true + + @info "Updating from file..." + + sleep(0.1) ## There seems to be a synchronization issue if your OS is VERYFAST + wait_until_file_unchanged(notebook.path, .3) + + # call update_from_file. If it returns false, that means that the notebook file was corrupt, so we try again, a maximum of 10 times. + for _ in 1:10 + if update_from_file(session, notebook) + break + end end + + + @info "Updating from file done!" + + running[] = false end - - - @info "Updating from file done!" - - running[] = false end end - in_session() = get(session.notebooks, nb.notebook_id, nothing) === nb - session.options.server.auto_reload_from_file && @asynclog while in_session() - if !isfile(nb.path) - # notebook file deleted... let's ignore this, changing the notebook will cause it to save again. Fine for now - sleep(2) - else - watch_file(nb.path) - # the above call is blocking until the file changes - - local modified_time = mtime(nb.path) - local _tries = 0 - - # mtime might return zero if the file is temporarily removed - while modified_time == 0.0 && _tries < 10 - modified_time = mtime(nb.path) - _tries += 1 - sleep(.05) - end - - # current_time = time() - # @info "File changed" (current_time - nb.last_save_time) (modified_time - nb.last_save_time) (current_time - modified_time) - if !in_session() - break - end - - # if current_time - nb.last_save_time < 2.0 - # @info "Notebook was saved by me very recently, not reloading from file." - if modified_time == 0.0 - # @warn "Failed to hot reload: file no longer exists." - elseif modified_time - nb.last_save_time < session.options.server.auto_reload_from_file_cooldown - # @info "Modified time is very close to my last save time, not reloading from file." + in_session() = get(session.notebooks, notebook.notebook_id, nothing) === notebook + + session.options.server.auto_reload_from_file && @asynclog try + while in_session() + if !isfile(notebook.path) + # notebook file deleted... let's ignore this, changing the notebook will cause it to save again. Fine for now + sleep(2) else - update_from_file_throttled() + e = watch_file(notebook.path, 3) + if e.timedout + continue + end + + # the above call is blocking until the file changes + + local modified_time = mtime(notebook.path) + local _tries = 0 + + # mtime might return zero if the file is temporarily removed + while modified_time == 0.0 && _tries < 10 + modified_time = mtime(notebook.path) + _tries += 1 + sleep(.05) + end + + # current_time = time() + # @info "File changed" (current_time - notebook.last_save_time) (modified_time - notebook.last_save_time) (current_time - modified_time) + if !in_session() + break + end + + # if current_time - notebook.last_save_time < 2.0 + # @info "Notebook was saved by me very recently, not reloading from file." + if modified_time == 0.0 + # @warn "Failed to hot reload: file no longer exists." + elseif modified_time - notebook.last_save_time < session.options.server.auto_reload_from_file_cooldown + # @info "Modified time is very close to my last save time, not reloading from file." + else + update_from_file_throttled() + end end end + catch e + if !(e isa InterruptException) + rethrow(e) + end end - nb + notebook.status_tree.update_listener_ref[] = first(throttled(1.0 / 20) do + # TODO: this throttle should be trailing + Pluto.send_notebook_changes!(Pluto.ClientRequest(; session, notebook)) + end) + + return notebook end -function save_upload(content::Vector{UInt8}) - save_path = emptynotebook().path - Base.open(save_path, "w") do io - write(io, content) - end +""" +Generate a non-existing new notebook filename, and write `contents` to that file. Return the generated filename. +# Example +```julia +save_upload(some_notebook_data; filename_base="hello") == "~/.julia/pluto_notebooks/hello 5.jl" +``` +""" +function save_upload(contents::Union{String,Vector{UInt8}}; filename_base::Union{Nothing,AbstractString}=nothing) + save_path = numbered_until_new( + joinpath( + new_notebooks_directory(), + something(filename_base, cutename()) + ); suffix=".jl") + write(save_path, contents) save_path end "Create a new empty notebook inside `session::ServerSession`. Returns the `Notebook`." function new(session::ServerSession; run_async=true, notebook_id::UUID=uuid1()) - nb = if session.options.server.init_with_file_viewer - - @warn "DEPRECATED: init_with_file_viewer will be removed soon." - - file_viewer_code = """html\"\"\" - - - - \"\"\" - """ - Notebook([Cell(), Cell(code=file_viewer_code, code_folded=true)]) - + if session.options.server.init_with_file_viewer + @error "DEPRECATED: init_with_file_viewer has been removed." + end + + notebook = if session.options.compiler.sysimage === nothing + emptynotebook() else - if session.options.compiler.sysimage === nothing - emptynotebook() - else - Notebook([Cell("import Pkg"), Cell("# This cell disables Pluto's package manager and activates the global environment. Click on ? inside the bubble next to Pkg.activate to learn more.\n# (added automatically because a sysimage is used)\nPkg.activate()"), Cell()]) - end + Notebook([Cell("import Pkg"), Cell("# This cell disables Pluto's package manager and activates the global environment. Click on ? inside the bubble next to Pkg.activate to learn more.\n# (added automatically because a sysimage is used)\nPkg.activate()"), Cell()]) end - # Run NewNotebookEvent handler before assigning ID - isid = try_event_call(session, NewNotebookEvent(nb)) - nb.notebook_id = isnothing(isid) ? notebook_id : isid - update_save_run!(session, nb, nb.cells; run_async=run_async, prerender_text=true) - add(session, nb; run_async=run_async) + # Run NewNotebookEvent handler before assigning ID + isid = try_event_call(session, NewNotebookEvent()) + notebook.notebook_id = isnothing(isid) ? notebook_id : isid - try_event_call(session, OpenNotebookEvent(nb)) - nb + update_save_run!(session, notebook, notebook.cells; run_async, prerender_text=true) + add(session, notebook; run_async) + try_event_call(session, OpenNotebookEvent(notebook)) + return notebook end -"Shut down `notebook` inside `session`." -function shutdown(session::ServerSession, notebook::Notebook; keep_in_session=false, async=false) +"Shut down `notebook` inside `session`. If `keep_in_session` is `false` (default), you will not be allowed to run a notebook with the same notebook_id again." +function shutdown(session::ServerSession, notebook::Notebook; keep_in_session::Bool=false, async::Bool=false, verbose::Bool=true) notebook.nbpkg_restart_recommended_msg = nothing notebook.nbpkg_restart_required_msg = nothing + + if notebook.process_status ∈ (ProcessStatus.ready, ProcessStatus.starting) + notebook.process_status = ProcessStatus.no_process + end if !keep_in_session listeners = putnotebookupdates!(session, notebook) # TODO: shutdown message @@ -206,8 +251,20 @@ function shutdown(session::ServerSession, notebook::Notebook; keep_in_session=fa @async close(client.stream) end end - WorkspaceManager.unmake_workspace((session, notebook); async=async) + WorkspaceManager.unmake_workspace((session, notebook); async, verbose, allow_restart=keep_in_session) try_event_call(session, ShutdownNotebookEvent(notebook)) end +function move(session::ServerSession, notebook::Notebook, newpath::String) + newpath = tamepath(newpath) + + if isfile(newpath) + error("File exists already - you need to delete the old file manually.") + else + move_notebook!(notebook, newpath; disable_writing_notebook_files=session.options.server.disable_writing_notebook_files) + putplutoupdates!(session, clientupdate_notebook_list(session.notebooks)) + WorkspaceManager.cd_workspace((session, notebook), newpath) + end +end + end diff --git a/src/webserver/Static.jl b/src/webserver/Static.jl index f9f2057fa5..76a29f8081 100644 --- a/src/webserver/Static.jl +++ b/src/webserver/Static.jl @@ -2,322 +2,90 @@ import HTTP import Markdown: htmlesc import UUIDs: UUID import Pkg +import MIMEs -const found_is_pluto_dev = Ref{Union{Nothing,Bool}}(nothing) -function is_pluto_dev() - if found_is_pluto_dev[] !== nothing - return found_is_pluto_dev[] - end - found_is_pluto_dev[] = try - deps = Pkg.dependencies() - - p_index = findfirst(p -> p.name == "Pluto", deps) - p = deps[p_index] - - return p.is_tracking_path - catch - false - end -end function frontend_directory(; allow_bundled::Bool=true) - if allow_bundled && isdir(project_relative_path("frontend-dist")) && !is_pluto_dev() + if allow_bundled && isdir(project_relative_path("frontend-dist")) && (get(ENV, "JULIA_PLUTO_FORCE_BUNDLED", "nein") == "ja" || !is_pluto_dev()) "frontend-dist" else "frontend" end end -# Serve everything from `/frontend`, and create HTTP endpoints to open notebooks. +function should_cache(path::String) + dir, filename = splitdir(path) + endswith(dir, "frontend-dist") && occursin(r"\.[0-9a-f]{8}\.", filename) +end -"Attempts to find the MIME pair corresponding to the extension of a filename. Defaults to `text/plain`." -function mime_fromfilename(filename) - # This bad boy is from: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types - mimepairs = Dict(".aac" => "audio/aac", ".bin" => "application/octet-stream", ".bmp" => "image/bmp", ".css" => "text/css", ".csv" => "text/csv", ".eot" => "application/vnd.ms-fontobject", ".gz" => "application/gzip", ".gif" => "image/gif", ".htm" => "text/html", ".html" => "text/html", ".ico" => "image/vnd.microsoft.icon", ".jpeg" => "image/jpeg", ".jpg" => "image/jpeg", ".js" => "text/javascript", ".json" => "application/json", ".jsonld" => "application/ld+json", ".mjs" => "text/javascript", ".mp3" => "audio/mpeg", ".mp4" => "video/mp4", ".mpeg" => "video/mpeg", ".oga" => "audio/ogg", ".ogv" => "video/ogg", ".ogx" => "application/ogg", ".opus" => "audio/opus", ".otf" => "font/otf", ".png" => "image/png", ".pdf" => "application/pdf", ".rtf" => "application/rtf", ".sh" => "application/x-sh", ".svg" => "image/svg+xml", ".tar" => "application/x-tar", ".tif" => "image/tiff", ".tiff" => "image/tiff", ".ttf" => "font/ttf", ".txt" => "text/plain", ".wav" => "audio/wav", ".weba" => "audio/webm", ".webm" => "video/webm", ".webp" => "image/webp", ".woff" => "font/woff", ".woff2" => "font/woff2", ".xhtml" => "application/xhtml+xml", ".xml" => "application/xml", ".xul" => "application/vnd.mozilla.xul+xml", ".zip" => "application/zip", ".wasm" => "application/wasm") - file_extension = getkey(mimepairs, '.' * split(filename, '.')[end], ".txt") - MIME(mimepairs[file_extension]) +const day = let + second = 1 + hour = 60second + day = 24hour end -function asset_response(path) +function default_404(req = nothing) + HTTP.Response(404, "Not found!") +end + +function asset_response(path; cacheable::Bool=false) if !isfile(path) && !endswith(path, ".html") - return asset_response(path * ".html") - end - try - @assert isfile(path) - response = HTTP.Response(200, read(path, String)) - m = mime_fromfilename(path) - push!(response.headers, "Content-Type" => Base.istextmime(m) ? "$(m); charset=UTF-8" : string(m)) - push!(response.headers, "Access-Control-Allow-Origin" => "*") + return asset_response(path * ".html"; cacheable) + end + if isfile(path) + data = read(path) + response = HTTP.Response(200, data) + HTTP.setheader(response, "Content-Type" => MIMEs.contenttype_from_mime(MIMEs.mime_from_path(path, MIME"application/octet-stream"()))) + HTTP.setheader(response, "Content-Length" => string(length(data))) + HTTP.setheader(response, "Access-Control-Allow-Origin" => "*") + cacheable && HTTP.setheader(response, "Cache-Control" => "public, max-age=$(30day), immutable") response - catch e - HTTP.Response(404, "Not found!") + else + default_404() end end -function error_response(status_code::Integer, title, advice, body="") +function error_response( + status_code::Integer, title, advice, body="") template = read(project_relative_path(frontend_directory(), "error.jl.html"), String) body_title = body == "" ? "" : "Error message:" filled_in = replace(replace(replace(replace(replace(template, - "\$STYLE" => """"""), + "\$STYLE" => """"""), "\$TITLE" => title), "\$ADVICE" => advice), "\$BODYTITLE" => body_title), "\$BODY" => htmlesc(body)) response = HTTP.Response(status_code, filled_in) - push!(response.headers, "Content-Type" => string(mime_fromfilename(".html"))) + HTTP.setheader(response, "Content-Type" => MIMEs.contenttype_from_mime(MIME"text/html"())) response end function notebook_response(notebook; home_url="./", as_redirect=true) if as_redirect response = HTTP.Response(302, "") - push!(response.headers, "Location" => home_url * "edit?id=" * string(notebook.notebook_id)) + HTTP.setheader(response, "Location" => home_url * "edit?id=" * string(notebook.notebook_id)) return response else HTTP.Response(200, string(notebook.notebook_id)) end end -""" -Return whether the `request` was authenticated in one of two ways: -1. the session's `secret` was included in the URL as a search parameter, or -2. the session's `secret` was included in a cookie. -""" -function is_authenticated(session::ServerSession, request::HTTP.Request) - ( - secret_in_url = try - uri = HTTP.URI(request.target) - query = HTTP.queryparams(uri) - get(query, "secret", "") == session.secret - catch e - @warn "Failed to authenticate request using URL" exception = (e, catch_backtrace()) - false - end - ) || ( - secret_in_cookie = try - cookies = HTTP.cookies(request) - any(cookies) do cookie - cookie.name == "secret" && cookie.value == session.secret - end - catch e - @warn "Failed to authenticate request using cookies" exception = (e, catch_backtrace()) - false - end - ) - # that ) || ( kind of looks like Krabs from spongebob -end - -function http_router_for(session::ServerSession) - router = HTTP.Router() - security = session.options.security - - function add_set_secret_cookie!(response::HTTP.Response) - push!(response.headers, "Set-Cookie" => "secret=$(session.secret); SameSite=Strict; HttpOnly") - response - end - - """ - with_authentication(f::Function) - - Returns a function `HTTP.Request → HTTP.Response` which does three things: - 1. Check whether the request is authenticated (by calling `is_authenticated`), if not, return a 403 error. - 2. Call your `f(request)` to create the response message. - 3. Add a `Set-Cookie` header to the response with the session's `secret`. - """ - function with_authentication(f::Function; required::Bool)::Function - return function (request::HTTP.Request) - if !required || is_authenticated(session, request) - response = f(request) - add_set_secret_cookie!(response) - if !required - filter!(p -> p[1] != "Access-Control-Allow-Origin", response.headers) - push!(response.headers, "Access-Control-Allow-Origin" => "*") - end - response - else - error_response(403, "Not yet authenticated", "Open the link that was printed in the terminal where you launched Pluto. It includes a secret, which is needed to access this server.

If you are running the server yourself and want to change this configuration, have a look at the keyword arguments to Pluto.run.

Please report this error if you did not expect it!") - end - end - end - - function create_serve_onefile(path) - return request::HTTP.Request -> asset_response(normpath(path)) - end - - # / does not need security.require_secret_for_open_links - # because this is how we handle the case: - # require_secret_for_open_links == true - # require_secret_for_access == false - # Access to all 'risky' endpoints is still restricted to requests that have the secret cookie, but visiting `/` is allowed, and it will set the cookie. From then on the security situation is identical to - # secret_for_access == true - HTTP.@register(router, "GET", "/", with_authentication( - create_serve_onefile(project_relative_path(frontend_directory(), "index.html")); - required=security.require_secret_for_access - )) - HTTP.@register(router, "GET", "/edit", with_authentication( - create_serve_onefile(project_relative_path(frontend_directory(), "editor.html")); - required=security.require_secret_for_access || - security.require_secret_for_open_links, - )) - # the /edit page also uses with_authentication, but this is not how access to notebooks is secured: this is done by requiring the WS connection to be authenticated. - # we still use it for /edit to do the cookie stuff, and show a more helpful error, instead of the WS never connecting. - - HTTP.@register(router, "GET", "/ping", r -> HTTP.Response(200, "OK!")) - HTTP.@register(router, "GET", "/possible_binder_token_please", r -> session.binder_token === nothing ? HTTP.Response(200,"") : HTTP.Response(200, session.binder_token)) - - function try_launch_notebook_response(action::Function, path_or_url::AbstractString; title="", advice="", home_url="./", as_redirect=true, action_kwargs...) - try - nb = action(session, path_or_url; action_kwargs...) - notebook_response(nb; home_url=home_url, as_redirect=as_redirect) - catch e - if e isa SessionActions.NotebookIsRunningException - notebook_response(e.notebook; home_url=home_url, as_redirect=as_redirect) - else - error_response(500, title, advice, sprint(showerror, e, stacktrace(catch_backtrace()))) - end - end - end - - serve_newfile = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - notebook_response(SessionActions.new(session); as_redirect=(request.method == "GET")) - end - HTTP.@register(router, "GET", "/new", serve_newfile) - HTTP.@register(router, "POST", "/new", serve_newfile) - - # This is not in Dynamic.jl because of bookmarks, how HTML works, - # real loading bars and the rest; Same for CustomLaunchEvent - serve_openfile = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - try - uri = HTTP.URI(request.target) - query = HTTP.queryparams(uri) - as_sample = haskey(query, "as_sample") - if haskey(query, "path") - path = tamepath(query["path"]) - if isfile(path) - return try_launch_notebook_response(SessionActions.open, path, as_redirect=(request.method == "GET"), as_sample=as_sample, title="Failed to load notebook", advice="The file $(htmlesc(path)) could not be loaded. Please report this error!") - else - return error_response(404, "Can't find a file here", "Please check whether $(htmlesc(path)) exists.") - end - elseif haskey(query, "url") - url = query["url"] - return try_launch_notebook_response(SessionActions.open_url, url, as_redirect=(request.method == "GET"), as_sample=as_sample, title="Failed to load notebook", advice="The notebook from $(htmlesc(url)) could not be loaded. Please report this error!") - else - # You can ask Pluto to handle CustomLaunch events - # and do some magic with how you open files. - # You are responsible to keep this up to date. - # See Events.jl for types and explanation - # - maybe_notebook_response = try_event_call(session, CustomLaunchEvent(query, request, try_launch_notebook_response)) - isnothing(maybe_notebook_response) && return error("Empty request") - return maybe_notebook_response - end - catch e - return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) - end - end - - HTTP.@register(router, "GET", "/open", serve_openfile) - HTTP.@register(router, "POST", "/open", serve_openfile) - - serve_sample = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - uri = HTTP.URI(request.target) - sample_filename = split(HTTP.unescapeuri(uri.path), "sample/")[2] - sample_path = project_relative_path("sample", sample_filename) - - try_launch_notebook_response(SessionActions.open, sample_path; as_redirect=(request.method == "GET"), home_url="../", as_sample=true, title="Failed to load sample", advice="Please report this error!") - end - HTTP.@register(router, "GET", "/sample/*", serve_sample) - HTTP.@register(router, "POST", "/sample/*", serve_sample) - - notebook_from_uri(request) = let - uri = HTTP.URI(request.target) - query = HTTP.queryparams(uri) - id = UUID(query["id"]) - session.notebooks[id] - end - serve_notebookfile = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - try - notebook = notebook_from_uri(request) - response = HTTP.Response(200, sprint(save_notebook, notebook)) - push!(response.headers, "Content-Type" => "text/julia; charset=utf-8") - push!(response.headers, "Content-Disposition" => "inline; filename=\"$(basename(notebook.path))\"") - response - catch e - return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) - end +const found_is_pluto_dev = Ref{Union{Nothing,Bool}}(nothing) +function is_pluto_dev() + if found_is_pluto_dev[] !== nothing + return found_is_pluto_dev[] end - HTTP.@register(router, "GET", "/notebookfile", serve_notebookfile) + found_is_pluto_dev[] = try + deps = Pkg.dependencies() - serve_statefile = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - try - notebook = notebook_from_uri(request) - response = HTTP.Response(200, Pluto.pack(Pluto.notebook_to_js(notebook))) - push!(response.headers, "Content-Type" => "application/octet-stream") - push!(response.headers, "Content-Disposition" => "inline; filename=\"$(without_pluto_file_extension(basename(notebook.path))).plutostate\"") - response - catch e - return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) - end - end - HTTP.@register(router, "GET", "/statefile", serve_statefile) + p_index = findfirst(p -> p.name == "Pluto", deps) + p = deps[p_index] - serve_notebookexport = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - try - notebook = notebook_from_uri(request) - response = HTTP.Response(200, generate_html(notebook)) - push!(response.headers, "Content-Type" => "text/html; charset=utf-8") - push!(response.headers, "Content-Disposition" => "inline; filename=\"$(basename(notebook.path)).html\"") - response - catch e - return error_response(400, "Bad query", "Please report this error!", sprint(showerror, e, stacktrace(catch_backtrace()))) - end - end - HTTP.@register(router, "GET", "/notebookexport", serve_notebookexport) - - serve_notebookupload = with_authentication(; - required=security.require_secret_for_access || - security.require_secret_for_open_links - ) do request::HTTP.Request - save_path = SessionActions.save_upload(request.body) - try_launch_notebook_response( - SessionActions.open, - save_path, - as_redirect=false, - as_sample=false, - title="Failed to load notebook", - advice="Make sure that you copy the entire notebook file. Please report this error!" - ) - end - HTTP.@register(router, "POST", "/notebookupload", serve_notebookupload) - - function serve_asset(request::HTTP.Request) - uri = HTTP.URI(request.target) - - filepath = project_relative_path(frontend_directory(), relpath(HTTP.unescapeuri(uri.path), "/")) - asset_response(filepath) + p.is_tracking_path + catch + false end - HTTP.@register(router, "GET", "/*", serve_asset) - HTTP.@register(router, "GET", "/favicon.ico", create_serve_onefile(project_relative_path(frontend_directory(allow_bundled=false), "img", "favicon.ico"))) +end - return router -end \ No newline at end of file diff --git a/src/webserver/Status.jl b/src/webserver/Status.jl new file mode 100644 index 0000000000..8586659d90 --- /dev/null +++ b/src/webserver/Status.jl @@ -0,0 +1,120 @@ +module Status + +_default_update_listener() = nothing + +Base.@kwdef mutable struct Business + name::Symbol=:ignored + started_at::Union{Nothing,Float64}=nothing + finished_at::Union{Nothing,Float64}=nothing + subtasks::Dict{Symbol,Business}=Dict{Symbol,Business}() + update_listener_ref::Ref{Function}=Ref{Function}(_default_update_listener) + lock::Threads.SpinLock=Threads.SpinLock() +end + + + +tojs(b::Business) = Dict{String,Any}( + "name" => b.name, + "started_at" => b.started_at, + "finished_at" => b.finished_at, + "subtasks" => Dict{String,Any}( + String(s) => tojs(r) + for (s, r) in b.subtasks + ), +) + + +function report_business_started!(business::Business) + lock(business.lock) do + business.started_at = time() + business.finished_at = nothing + + empty!(business.subtasks) + end + + business.update_listener_ref[]() + return business +end + + + +function report_business_finished!(business::Business) + lock(business.lock) do + # if it never started, then lets "start" it now + business.started_at = something(business.started_at, time()) + # if it already finished, then leave the old finish time. + business.finished_at = something(business.finished_at, max(business.started_at, time())) + end + + # also finish all subtasks (this can't be inside the same lock) + for v in values(business.subtasks) + report_business_finished!(v) + end + + business.update_listener_ref[]() + + return business +end + + + +create_for_child(parent::Business, name::Symbol) = function() + Business(; name, update_listener_ref=parent.update_listener_ref, lock=parent.lock) +end + +get_child(parent::Business, name::Symbol) = lock(parent.lock) do + get!(create_for_child(parent, name), parent.subtasks, name) +end + +report_business_finished!(parent::Business, name::Symbol) = get_child(parent, name) |> report_business_finished! +report_business_started!(parent::Business, name::Symbol) = get_child(parent, name) |> report_business_started! +report_business_planned!(parent::Business, name::Symbol) = get_child(parent, name) + + +report_business!(f::Function, parent::Business, args...) = try + report_business_started!(parent, args...) + f() +finally + report_business_finished!(parent, args...) +end + +delete_business!(business::Business, name::Symbol) = lock(business.lock) do + delete!(business.subtasks, name) +end + + + +# GLOBAL + +# registry update +## once per process + +# waiting for other notebook packages + + + + + + + + + + +# PER NOTEBOOK + +# notebook process starting + +# installing packages +# updating packages + +# running cells + + + + + + +end + + + diff --git a/src/webserver/WebServer.jl b/src/webserver/WebServer.jl index 098b6a4c19..d8a5fef6d7 100644 --- a/src/webserver/WebServer.jl +++ b/src/webserver/WebServer.jl @@ -2,22 +2,7 @@ import MsgPack import UUIDs: UUID import HTTP import Sockets - -import Base: endswith -function endswith(vec::Vector{T}, suffix::Vector{T}) where T - local liv = lastindex(vec) - local lis = lastindex(suffix) - liv >= lis && (view(vec, (liv - lis + 1):liv) == suffix) -end - -include("./WebSocketFix.jl") - -# from https://github.com/JuliaLang/julia/pull/36425 -function detectwsl() - Sys.islinux() && - isfile("/proc/sys/kernel/osrelease") && - occursin(r"Microsoft|WSL"i, read("/proc/sys/kernel/osrelease", String)) -end +import .PkgCompat function open_in_default_browser(url::AbstractString)::Bool try @@ -28,7 +13,7 @@ function open_in_default_browser(url::AbstractString)::Bool Base.run(`powershell.exe Start "'$url'"`) true elseif Sys.islinux() - Base.run(`xdg-open $url`) + Base.run(`xdg-open $url`, devnull, devnull, devnull) true else false @@ -38,13 +23,13 @@ function open_in_default_browser(url::AbstractString)::Bool end end -isurl(s::String) = startswith(s, "http://") || startswith(s, "https://") - -swallow_exception(f, exception_type::Type{T}) where T = - try f() +function swallow_exception(f, exception_type::Type{T}) where {T} + try + f() catch e isa(e, T) || rethrow(e) end +end """ Pluto.run() @@ -61,6 +46,7 @@ For the full list, see the [`Pluto.Configuration`](@ref) module. Some **common p - `launch_browser`: Optional. Whether to launch the system default browser. Disable this on SSH and such. - `host`: Optional. The default `host` is `"127.0.0.1"`. For wild setups like Docker and heroku, you might need to change this to `"0.0.0.0"`. - `port`: Optional. The default `port` is `1234`. +- `auto_reload_from_file`: Reload when the `.jl` file is modified. The default is `false`. ## Technobabble @@ -73,43 +59,76 @@ function run(; kwargs...) end function run(options::Configuration.Options) - session = ServerSession(;options=options) + session = ServerSession(; options) run(session) end # Deprecation errors -function run(host::String, port::Union{Nothing,Integer}=nothing; kwargs...) +function run(host::String, port::Union{Nothing,Integer} = nothing; kwargs...) @error """run(host, port) is deprecated in favor of: - + run(;host="$host", port=$port) - + """ end function run(port::Integer; kwargs...) @error "Oopsie! This is the old command to launch Pluto. The new command is: - + Pluto.run() - + without the port as argument - it will choose one automatically. If you need to specify the port, use: Pluto.run(port=$port) " end -# open notebook(s) on startup - -open_notebook!(session:: ServerSession, notebook:: Nothing) = Nothing -open_notebook!(session:: ServerSession, notebook:: AbstractString) = SessionActions.open(session, notebook) +const is_first_run = Ref(true) -function open_notebook!(session:: ServerSession, notebook:: AbstractVector{<: AbstractString}) - for nb in notebook - SessionActions.open(session, nb) +"Return a port and serversocket to use while taking into account the `favourite_port`." +function port_serversocket(hostIP::Sockets.IPAddr, favourite_port, port_hint) + local port, serversocket + if favourite_port === nothing + port, serversocket = Sockets.listenany(hostIP, UInt16(port_hint)) + else + port = UInt16(favourite_port) + try + serversocket = Sockets.listen(hostIP, port) + catch e + error("Cannot listen on port $port. It may already be in use, or you may not have sufficient permissions. Use Pluto.run() to automatically select an available port.") + end end + return port, serversocket +end + +struct RunningPlutoServer + http_server + initial_registry_update_task::Task end +function Base.close(ssc::RunningPlutoServer) + close(ssc.http_server) + wait(ssc.http_server) + wait(ssc.initial_registry_update_task) +end + +function Base.wait(ssc::RunningPlutoServer) + try + # create blocking call and switch the scheduler back to the server task, so that interrupts land there + while isopen(ssc.http_server) + sleep(.1) + end + catch e + println() + println() + Base.close(ssc) + (e isa InterruptException) || rethrow(e) + end + + nothing +end """ run(session::ServerSession) @@ -117,39 +136,56 @@ end Specifiy the [`Pluto.ServerSession`](@ref) to run the web server on, which includes the configuration. Passing a session as argument allows you to start the web server with some notebooks already running. See [`SessionActions`](@ref) to learn more about manipulating a `ServerSession`. """ function run(session::ServerSession) - pluto_router = http_router_for(session) - Base.invokelatest(run, session, pluto_router) + Base.wait(run!(session)) end -function run(session::ServerSession, pluto_router) - +function run!(session::ServerSession) + if is_first_run[] + is_first_run[] = false + @info "Loading..." + end + if VERSION < v"1.6.2" - @info "Pluto is running on an old version of Julia ($(VERSION)) that is no longer supported. Visit https://julialang.org/downloads/ for more information about upgrading Julia." + @warn("\nPluto is running on an old version of Julia ($(VERSION)) that is no longer supported. Visit https://julialang.org/downloads/ for more information about upgrading Julia.") end - notebook_at_startup = session.options.server.notebook - open_notebook!(session, notebook_at_startup) + pluto_router = http_router_for(session) + store_session_middleware = create_session_context_middleware(session) + app = pluto_router |> auth_middleware |> store_session_middleware + + let n = session.options.server.notebook + SessionActions.open.((session,), + n === nothing ? [] : + n isa AbstractString ? [n] : + n; + run_async=true, + ) + end host = session.options.server.host - port = session.options.server.port - hostIP = parse(Sockets.IPAddr, host) - if port === nothing - port, serversocket = Sockets.listenany(hostIP, UInt16(1234)) - else - try - serversocket = Sockets.listen(hostIP, UInt16(port)) - catch e - @error "Port with number $port is already in use. Use Pluto.run() to automatically select an available port." - return + favourite_port = session.options.server.port + port_hint = session.options.server.port_hint + + local port, serversocket = port_serversocket(hostIP, favourite_port, port_hint) + + on_shutdown() = @sync begin + # Triggered by HTTP.jl + @info("\nClosing Pluto... Restart Julia for a fresh session. \n\nHave a nice day! 🎈\n\n") + # TODO: put do_work tokens back + @async swallow_exception(() -> close(serversocket), Base.IOError) + for client in values(session.connected_clients) + @async swallow_exception(() -> close(client.stream), Base.IOError) + end + empty!(session.connected_clients) + for nb in values(session.notebooks) + @asynclog SessionActions.shutdown(session, nb; keep_in_session=false, async=false, verbose=false) end end - shutdown_server = Ref{Function}(() -> ()) - - servertask = @async HTTP.serve(hostIP, UInt16(port), stream=true, server=serversocket) do http::HTTP.Stream + server = HTTP.listen!(hostIP, port; stream=true, server=serversocket, on_shutdown, verbose=-1) do http::HTTP.Stream # messy messy code so that we can use the websocket on the same port as the HTTP server - if HTTP.WebSockets.is_upgrade(http.message) + if HTTP.WebSockets.isupgrade(http.message) secret_required = let s = session.options.security s.require_secret_for_access || s.require_secret_for_open_links @@ -158,39 +194,40 @@ function run(session::ServerSession, pluto_router) try HTTP.WebSockets.upgrade(http) do clientstream - if !isopen(clientstream) + if HTTP.WebSockets.isclosed(clientstream) return end try - while !eof(clientstream) - # This stream contains data received over the WebSocket. - # It is formatted and MsgPack-encoded by send(...) in PlutoConnection.js - local parentbody = nothing - try - message = collect(WebsocketFix.readmessage(clientstream)) - parentbody = unpack(message) - - let - lag = session.options.server.simulated_lag - (lag > 0) && sleep(lag * (0.5 + rand())) # sleep(0) would yield to the process manager which we dont want - end - - process_ws_message(session, parentbody, clientstream) - catch ex - if ex isa InterruptException - shutdown_server[]() - elseif ex isa HTTP.WebSockets.WebSocketError || ex isa EOFError - # that's fine! - else - bt = stacktrace(catch_backtrace()) - @warn "Reading WebSocket client stream failed for unknown reason:" parentbody exception = (ex, bt) + for message in clientstream + # This stream contains data received over the WebSocket. + # It is formatted and MsgPack-encoded by send(...) in PlutoConnection.js + local parentbody = nothing + local did_read = false + try + parentbody = unpack(message) + + let + lag = session.options.server.simulated_lag + (lag > 0) && sleep(lag * (0.5 + rand())) # sleep(0) would yield to the process manager which we dont want + end + + did_read = true + process_ws_message(session, parentbody, clientstream) + catch ex + if ex isa InterruptException || ex isa HTTP.WebSockets.WebSocketError || ex isa EOFError + # that's fine! + else + bt = catch_backtrace() + if did_read + @warn "Processing message failed for unknown reason:" parentbody exception = (ex, bt) + else + @warn "Reading WebSocket client stream failed for unknown reason:" parentbody exception = (ex, bt) + end + end end end - end catch ex - if ex isa InterruptException - shutdown_server[]() - elseif ex isa HTTP.WebSockets.WebSocketError || ex isa EOFError || (ex isa Base.IOError && occursin("connection reset", ex.msg)) + if ex isa InterruptException || ex isa HTTP.WebSockets.WebSocketError || ex isa EOFError || (ex isa Base.IOError && occursin("connection reset", ex.msg)) # that's fine! else bt = stacktrace(catch_backtrace()) @@ -200,7 +237,7 @@ function run(session::ServerSession, pluto_router) end catch ex if ex isa InterruptException - shutdown_server[]() + # that's fine! elseif ex isa Base.IOError # that's fine! elseif ex isa ArgumentError && occursin("stream is closed", ex.msg) @@ -222,26 +259,30 @@ function run(session::ServerSession, pluto_router) end end else + # then it's a regular HTTP request, not a WS upgrade + request::HTTP.Request = http.message request.body = read(http) - HTTP.closeread(http) + # HTTP.closeread(http) # If a "token" url parameter is passed in from binder, then we store it to add to every URL (so that you can share the URL to collaborate). params = HTTP.queryparams(HTTP.URI(request.target)) - if haskey(params, "token") && session.binder_token === nothing + if haskey(params, "token") && params["token"] ∉ ("null", "undefined", "") && session.binder_token === nothing session.binder_token = params["token"] end - request_body = IOBuffer(HTTP.payload(request)) - response_body = HTTP.handle(pluto_router, request) - + response_body = app(request) + request.response::HTTP.Response = response_body request.response.request = request try - HTTP.setheader(http, "Referrer-Policy" => "origin-when-cross-origin") + HTTP.setheader(http, "Content-Length" => string(length(request.response.body))) + # https://github.com/fonsp/Pluto.jl/pull/722 + HTTP.setheader(http, "Referrer-Policy" => "same-origin") + # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#:~:text=is%202%20minutes.-,14.38%20Server + HTTP.setheader(http, "Server" => "Pluto.jl/$(PLUTO_VERSION_STR[2:end]) Julia/$(JULIA_VERSION_STR[2:end])") HTTP.startwrite(http) write(http, request.response.body) - HTTP.closewrite(http) catch e if isa(e, Base.IOError) || isa(e, ArgumentError) # @warn "Attempted to write to a closed stream at $(request.target)" @@ -252,56 +293,48 @@ function run(session::ServerSession, pluto_router) end end - address = pretty_address(session, hostIP, port) + server_running() = + try + HTTP.get("http://$(hostIP):$(port)$(session.options.server.base_url)ping"; status_exception = false, retry = false, connect_timeout = 10, readtimeout = 10).status == 200 + catch + false + end + # Wait for the server to start up before opening the browser. We have a 5 second grace period for allowing the connection, and then 10 seconds for the server to write data. + WorkspaceManager.poll(server_running, 5.0, 1.0) - println() + address = pretty_address(session, hostIP, port) if session.options.server.launch_browser && open_in_default_browser(address) - println("Opening $address in your default browser... ~ have fun!") + @info("\nOpening $address in your default browser... ~ have fun!") else - println("Go to $address in your browser to start writing ~ have fun!") + @info("\nGo to $address in your browser to start writing ~ have fun!") end - println() - println("Press Ctrl+C in this terminal to stop Pluto") - println() + @info("\nPress Ctrl+C in this terminal to stop Pluto\n\n") - if PLUTO_VERSION >= v"0.18.0" && frontend_directory() == "frontend" - @info "It looks like you are developing the Pluto package, using the unbundled frontend..." - end + # Trigger ServerStartEvent with server details + try_event_call(session, ServerStartEvent(address, port)) - shutdown_server[] = () -> @sync begin - println("\n\nClosing Pluto... Restart Julia for a fresh session. \n\nHave a nice day! 🎈") - @async swallow_exception(() -> close(serversocket), Base.IOError) - # TODO: HTTP has a kill signal? - # TODO: put do_work tokens back - for client in values(session.connected_clients) - @async swallow_exception(() -> close(client.stream), Base.IOError) - end - empty!(session.connected_clients) - for (notebook_id, ws) in WorkspaceManager.workspaces - @async WorkspaceManager.unmake_workspace(fetch(ws)) - end + if PLUTO_VERSION >= v"0.17.6" && frontend_directory() == "frontend" + @info("It looks like you are developing the Pluto package, using the unbundled frontend...") end - try - # create blocking call and switch the scheduler back to the server task, so that interrupts land there - wait(servertask) - catch e - if e isa InterruptException - shutdown_server[]() - elseif e isa TaskFailedException - # nice! - else - rethrow(e) - end + # Start this in the background, so that the first notebook launch (which will trigger registry update) will be faster + initial_registry_update_task = @asynclog withtoken(pkg_token) do + will_update = !PkgCompat.check_registry_age() + PkgCompat.update_registries(; force = false) + will_update && println(" Updating registry done ✓") end -end -get_favorite_notebook(notebook:: Nothing) = nothing -get_favorite_notebook(notebook:: String) = notebook -get_favorite_notebook(notebook:: AbstractVector) = first(notebook) + return RunningPlutoServer(server, initial_registry_update_task) +end +precompile(run, (ServerSession, HTTP.Handlers.Router{Symbol("##001")})) function pretty_address(session::ServerSession, hostIP, port) - root = if session.options.server.root_url === nothing + root = if session.options.server.root_url !== nothing + @assert endswith(session.options.server.root_url, "/") + replace(session.options.server.root_url, "{PORT}" => string(Int(port))) + elseif haskey(ENV, "JH_APP_URL") + "$(ENV["JH_APP_URL"])proxy/$(Int(port))/" + else host_str = string(hostIP) host_pretty = if isa(hostIP, Sockets.IPv6) if host_str == "::1" @@ -315,10 +348,8 @@ function pretty_address(session::ServerSession, hostIP, port) host_str end port_pretty = Int(port) - "http://$(host_pretty):$(port_pretty)/" - else - @assert endswith(session.options.server.root_url, "/") - session.options.server.root_url + base_url = session.options.server.base_url + "http://$(host_pretty):$(port_pretty)$(base_url)" end url_params = Dict{String,String}() @@ -326,23 +357,27 @@ function pretty_address(session::ServerSession, hostIP, port) if session.options.security.require_secret_for_access url_params["secret"] = session.secret end - fav_notebook = get_favorite_notebook(session.options.server.notebook) + fav_notebook = let n = session.options.server.notebook + n isa AbstractVector ? (isempty(n) ? nothing : first(n)) : n + end new_root = if fav_notebook !== nothing - key = isurl(fav_notebook) ? "url" : "path" - url_params[key] = string(fav_notebook) + # since this notebook already started running, this will get redicted to that session + url_params["path"] = string(fav_notebook) root * "open" else root end - merge(HTTP.URIs.URI(new_root), query=url_params) |> string + string(HTTP.URI(HTTP.URI(new_root); query = url_params)) end "All messages sent over the WebSocket get decoded+deserialized and end up here." -function process_ws_message(session::ServerSession, parentbody::Dict, clientstream::IO) +function process_ws_message(session::ServerSession, parentbody::Dict, clientstream) client_id = Symbol(parentbody["client_id"]) - client = get!(session.connected_clients, client_id, ClientSession(client_id, clientstream)) + client = get!(session.connected_clients, client_id ) do + ClientSession(client_id, clientstream, session.options.server.simulated_lag) + end client.stream = clientstream # it might change when the same client reconnects - + messagetype = Symbol(parentbody["type"]) request_id = Symbol(parentbody["request_id"]) @@ -359,7 +394,7 @@ function process_ws_message(session::ServerSession, parentbody::Dict, clientstre client.connected_notebook = notebook end end - + notebook else nothing diff --git a/src/webserver/WebSocketFix.jl b/src/webserver/WebSocketFix.jl deleted file mode 100644 index 517724bcaa..0000000000 --- a/src/webserver/WebSocketFix.jl +++ /dev/null @@ -1,80 +0,0 @@ -"Things that will hopefully go into HTTP.jl someday." -module WebsocketFix - -import HTTP.WebSockets - -function readframe(ws::WebSockets.WebSocket) - header = WebSockets.readheader(ws.io) - @debug 1 "WebSocket ➡️ $header" - - if header.length > 0 - if length(ws.rxpayload) < header.length - resize!(ws.rxpayload, header.length) - end - unsafe_read(ws.io, pointer(ws.rxpayload), header.length) - @debug 2 " ➡️ \"$(String(ws.rxpayload[1:header.length]))\"" - end - l = Int(header.length) - if header.hasmask - WebSockets.mask!(ws.rxpayload, ws.rxpayload, l, reinterpret(UInt8, [header.mask])) - end - - return header, view(ws.rxpayload, 1:l) -end - -""" - readmessage(ws::WebSocket) - -HTTP.jl's default `readframe` (or `readavailable`) doesn't look at the FINAL field of frames. -This means that it will return a frame no matter what, even though most people expect to get a full message. -This method fixes that and gives you what you expect. -""" -function readmessage(ws::WebSockets.WebSocket) - # this code is based on HTTP.jl source code: https://github.com/JuliaWeb/HTTP.jl/blob/master/src/WebSockets.jl - - header, data = readframe(ws) - l = Int(header.length) - - if header.opcode == WebSockets.WS_CLOSE - ws.rxclosed = true - if l >= 2 - status = UInt16(ws.rxpayload[1]) << 8 | ws.rxpayload[2] - if status != 1000 - message = String(ws.rxpayload[3:l]) - status_descr = get(WebSockets.STATUS_CODE_DESCRIPTION, Int(status), "") - msg = "Status: $(status_descr), Internal Code: $(message)" - throw(WebSockets.WebSocketError(status, msg)) - end - end - return UInt8[] - elseif header.opcode == WebSockets.WS_PING - WebSockets.wswrite(ws, WebSockets.WS_FINAL | WebSockets.WS_PONG, ws.rxpayload[1:l]) - header2, data2 = readframe(ws) - return readmessage(ws) - elseif header.opcode == WebSockets.WS_CONTINUATION - error("WS continuation gone wrong") - else - if header.final == true - return view(ws.rxpayload, 1:l) - else - multi_message_data = UInt8[] - append!(multi_message_data, data) - while true - header2, data2 = readframe(ws) - if header2.opcode != WebSockets.WS_CONTINUATION - println("header2.opcode:", header2.opcode) - println("header2:", header2) - throw("Should be a continuation") - end - append!(multi_message_data, data2) - if header2.final - break - end - end - - multi_message_data - end - end -end - -end \ No newline at end of file diff --git a/src/webserver/data_url.jl b/src/webserver/data_url.jl index fca7186191..0d77f89bd4 100644 --- a/src/webserver/data_url.jl +++ b/src/webserver/data_url.jl @@ -1,18 +1,44 @@ ### A Pluto.jl notebook ### -# v0.17.1 +# v0.19.9 using Markdown using InteractiveUtils +# ╔═╡ b987a8a2-6ab0-4e88-af3c-d7f2778af657 +# ╠═╡ show_logs = false +# ╠═╡ skip_as_script = true +#=╠═╡ +begin + import Pkg + + # create a local environment for this notebook + # used to install and load PlutoTest + local_env = mktempdir() + Pkg.activate(local_env) + Pkg.add(name="PlutoTest", version="0.2") + pushfirst!(LOAD_PATH, local_env) + + # activate Pluto's environment, used to load HTTP.jl + Pkg.activate(Base.current_project(@__FILE__)) + using PlutoTest +end + ╠═╡ =# + # ╔═╡ cc180e7e-46c3-11ec-3fff-05e1b5c77986 +# ╠═╡ skip_as_script = true +#=╠═╡ md""" # Download Data URLs """ + ╠═╡ =# # ╔═╡ 2385dd3b-15f8-4790-907f-e0576a56c4c0 +# ╠═╡ skip_as_script = true +#=╠═╡ random_data = rand(UInt8, 30) + ╠═╡ =# # ╔═╡ d8ed6d44-33cd-4c9d-828b-d237d43769f5 # try @@ -21,40 +47,11 @@ random_data = rand(UInt8, 30) # e # end |> typeof -# ╔═╡ e1610184-5d16-499b-883e-7ef92f402ebb -function is_inside_pluto(m::Module) - if isdefined(m, :PlutoForceDisplay) - return m.PlutoForceDisplay - else - isdefined(m, :PlutoRunner) && parentmodule(m) == Main - end -end - -# ╔═╡ b987a8a2-6ab0-4e88-af3c-d7f2778af657 +# ╔═╡ b3f685a3-b52d-4190-9196-6977a7e76aa1 begin - if is_inside_pluto(@__MODULE__) - import Pkg - - # create a local environment for this notebook - # used to install and load PlutoTest - local_env = mktempdir() - Pkg.activate(local_env) - Pkg.add(name="PlutoTest", version="0.2") - pushfirst!(LOAD_PATH, local_env) - - # activate Pluto's environment, used to load HTTP.jl - Pkg.activate(Base.current_project(@__FILE__)) - using PlutoTest - else - if !isdefined(@__MODULE__, Symbol("@test")) - macro test(e...) nothing; end - macro test_throws(e...) nothing; end - macro test_broken(e...) nothing; end - macro testset(e...) nothing; end - end - end import HTTP.URIs import Base64 + import Downloads end # ╔═╡ a85c0c0b-47d0-4377-bc22-3c87239a67b3 @@ -90,56 +87,82 @@ function download_cool(url::AbstractString, path::AbstractString=tempname()) write(path, data) path else - download(url, path) + Downloads.download(url, path) end end # ╔═╡ 6e1dd79c-a7bf-44d6-bfa6-ced75b45170a download_cool_string(args...) = read(download_cool(args...), String) -# ╔═╡ 3630b4bc-ff63-426d-b95d-ae4e4f9ccd88 -download_cool_data(args...) = read(download_cool(args...)) - # ╔═╡ 6339496d-11be-40d0-b4e5-9247e5199367 +#=╠═╡ @test download_cool_string("data:,Hello%2C%20World%21") == "Hello, World!" + ╠═╡ =# # ╔═╡ bf7b4241-9cb0-4d90-9ded-b527bf220803 +#=╠═╡ @test download_cool_string("data:text/plain,Hello%2C%20World%21") == "Hello, World!" + ╠═╡ =# # ╔═╡ d6e01532-a8e4-4173-a270-eae37c8002c7 +#=╠═╡ @test download_cool_string("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==") == "Hello, World!" + ╠═╡ =# # ╔═╡ b0ba1add-f452-4a44-ab23-becbc610e2b9 +#=╠═╡ @test download_cool_string("data:;base64,SGVsbG8sIFdvcmxkIQ==") == "Hello, World!" + ╠═╡ =# # ╔═╡ e630e261-1c2d-4117-9c44-dd49199fa3de +#=╠═╡ @test download_cool_string("data:,hello") == "hello" + ╠═╡ =# # ╔═╡ 4bb75573-09bd-4ce7-b76f-34c0249d7b88 +#=╠═╡ @test download_cool_string("data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E") == "

Hello, World!

" + ╠═╡ =# # ╔═╡ 301eee81-7715-4d39-89aa-37bffde3557f +#=╠═╡ @test download_cool_string("data:text/html,") == "" - -# ╔═╡ ae296e09-08dd-4ee8-87ac-eb2bf24b28b9 -random_data_url = "data:asf;base64,$( - Base64.base64encode(random_data) -)" - -# ╔═╡ 2eabfa58-2d8f-4479-9c00-a58b934638d9 -@test download_cool_data(random_data_url) == random_data + ╠═╡ =# # ╔═╡ 525b2cb6-b7b9-436e-898e-a951e6a1f2f1 +#=╠═╡ @test occursin("reactive", download_cool_string("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.17.1/README.md")) + ╠═╡ =# + +# ╔═╡ 3630b4bc-ff63-426d-b95d-ae4e4f9ccd88 +download_cool_data(args...) = read(download_cool(args...)) # ╔═╡ 40b48818-e191-4509-85ad-b9ff745cd0cb +#=╠═╡ @test_throws Exception download_cool("data:xoxo;base10,asdfasdfasdf") + ╠═╡ =# # ╔═╡ 1f175fcd-8b94-4f13-a912-02a21c95f8ca +#=╠═╡ @test_throws Exception download_cool("data:text/plain;base10,asdfasdfasdf") + ╠═╡ =# # ╔═╡ a4f671e6-0e23-4753-9301-048b2ef505e3 +#=╠═╡ @test_throws Exception download_cool("data:asdfasdfasdf") + ╠═╡ =# + +# ╔═╡ ae296e09-08dd-4ee8-87ac-eb2bf24b28b9 +#=╠═╡ +random_data_url = "data:asf;base64,$( + Base64.base64encode(random_data) +)" + ╠═╡ =# + +# ╔═╡ 2eabfa58-2d8f-4479-9c00-a58b934638d9 +#=╠═╡ +@test download_cool_data(random_data_url) == random_data + ╠═╡ =# # ╔═╡ Cell order: # ╟─cc180e7e-46c3-11ec-3fff-05e1b5c77986 @@ -161,5 +184,5 @@ random_data_url = "data:asf;base64,$( # ╠═1f175fcd-8b94-4f13-a912-02a21c95f8ca # ╠═a4f671e6-0e23-4753-9301-048b2ef505e3 # ╠═d8ed6d44-33cd-4c9d-828b-d237d43769f5 -# ╟─e1610184-5d16-499b-883e-7ef92f402ebb +# ╠═b3f685a3-b52d-4190-9196-6977a7e76aa1 # ╠═b987a8a2-6ab0-4e88-af3c-d7f2778af657 diff --git a/test/Analysis.jl b/test/Analysis.jl index 38436f468c..f9182ac30c 100644 --- a/test/Analysis.jl +++ b/test/Analysis.jl @@ -1,78 +1,139 @@ using Test -import Pluto: Notebook, ServerSession, ClientSession, Cell, updated_topology, static_resolve_topology, is_just_text +import Pluto: Notebook, Cell, updated_topology, static_resolve_topology, is_just_text, NotebookTopology @testset "Analysis" begin - notebook = Notebook([ - Cell(""), - Cell("md\"a\""), - Cell("html\"a\""), - Cell("md\"a \$b\$\""), - Cell("md\"a ``b``\""), - Cell(""" - let - x = md"a" - md"r \$x" - end - """), - Cell("html\"a 7 \$b\""), + @testset "is_just_text" begin + notebook = Notebook([ + Cell(""), + Cell("md\"a\""), + Cell("html\"a\""), + Cell("md\"a \$b\$\""), + Cell("md\"a ``b``\""), + Cell(""" + let + x = md"a" + md"r \$x" + end + """), + Cell("html\"a 7 \$b\""), - Cell("md\"a 8 \$b\""), - Cell("@a md\"asdf 9\""), - Cell("x()"), - Cell("x() = y()"), - Cell("12 + 12"), - Cell("import Dates"), - Cell("import Dates"), - Cell("while false end"), - Cell("for i in [16]; end"), - Cell("[i for i in [17]]"), - Cell("module x18 end"), - Cell(""" - module x19 - exit() - end - """), - Cell("""quote end"""), - Cell("""quote x = 21 end"""), - Cell("""quote \$(x = 22) end"""), - Cell("""asdf"23" """), - Cell("""@asdf("24") """), - Cell("""@x"""), - Cell("""@y z 26"""), - Cell("""f(g"27")"""), - ]) + Cell("md\"a 8 \$b\""), + Cell("@a md\"asdf 9\""), + Cell("x()"), + Cell("x() = y()"), + Cell("12 + 12"), + Cell("import Dates"), + Cell("import Dates"), + Cell("while false end"), + Cell("for i in [16]; end"), + Cell("[i for i in [17]]"), + Cell("module x18 end"), + Cell(""" + module x19 + exit() + end + """), + Cell("""quote end"""), + Cell("""quote x = 21 end"""), + Cell("""quote \$(x = 22) end"""), + Cell("""asdf"23" """), + Cell("""@asdf("24") """), + Cell("""@x"""), + Cell("""@y z 26"""), + Cell("""f(g"27")"""), + ]) + + old = notebook.topology + new = notebook.topology = updated_topology(old, notebook, notebook.cells) - old = notebook.topology - new = notebook.topology = updated_topology(old, notebook, notebook.cells) |> static_resolve_topology + @testset "Only-text detection" begin + @test is_just_text(new, notebook.cells[1]) + @test is_just_text(new, notebook.cells[2]) + @test is_just_text(new, notebook.cells[3]) + @test is_just_text(new, notebook.cells[4]) + @test is_just_text(new, notebook.cells[5]) + @test is_just_text(new, notebook.cells[6]) + @test is_just_text(new, notebook.cells[7]) - @testset "Only-text detection" begin - @test is_just_text(new, notebook.cells[1]) - @test is_just_text(new, notebook.cells[2]) - @test is_just_text(new, notebook.cells[3]) - @test is_just_text(new, notebook.cells[4]) - @test is_just_text(new, notebook.cells[5]) - @test is_just_text(new, notebook.cells[6]) - @test is_just_text(new, notebook.cells[7]) + @test !is_just_text(new, notebook.cells[8]) + @test !is_just_text(new, notebook.cells[9]) + @test !is_just_text(new, notebook.cells[10]) + @test !is_just_text(new, notebook.cells[11]) + @test !is_just_text(new, notebook.cells[12]) + @test !is_just_text(new, notebook.cells[13]) + @test !is_just_text(new, notebook.cells[14]) + @test !is_just_text(new, notebook.cells[15]) + @test !is_just_text(new, notebook.cells[16]) + @test !is_just_text(new, notebook.cells[17]) + @test !is_just_text(new, notebook.cells[18]) + @test !is_just_text(new, notebook.cells[19]) + @test !is_just_text(new, notebook.cells[20]) + @test !is_just_text(new, notebook.cells[21]) + @test !is_just_text(new, notebook.cells[22]) + @test !is_just_text(new, notebook.cells[23]) + @test !is_just_text(new, notebook.cells[24]) + @test !is_just_text(new, notebook.cells[25]) + @test !is_just_text(new, notebook.cells[26]) + @test !is_just_text(new, notebook.cells[27]) + end + end - @test !is_just_text(new, notebook.cells[8]) - @test !is_just_text(new, notebook.cells[9]) - @test !is_just_text(new, notebook.cells[10]) - @test !is_just_text(new, notebook.cells[11]) - @test !is_just_text(new, notebook.cells[12]) - @test !is_just_text(new, notebook.cells[13]) - @test !is_just_text(new, notebook.cells[14]) - @test !is_just_text(new, notebook.cells[15]) - @test !is_just_text(new, notebook.cells[16]) - @test !is_just_text(new, notebook.cells[17]) - @test !is_just_text(new, notebook.cells[18]) - @test !is_just_text(new, notebook.cells[19]) - @test !is_just_text(new, notebook.cells[20]) - @test !is_just_text(new, notebook.cells[21]) - @test !is_just_text(new, notebook.cells[22]) - @test !is_just_text(new, notebook.cells[23]) - @test !is_just_text(new, notebook.cells[24]) - @test !is_just_text(new, notebook.cells[25]) - @test !is_just_text(new, notebook.cells[26]) - @test !is_just_text(new, notebook.cells[27]) + @testset "updated_topology identity" begin + notebook = Notebook([ + Cell("x = 1") + Cell("function f(x) + x + 1 + end") + Cell("a = x - 123") + Cell("") + Cell("") + Cell("") + ]) + + empty_top = notebook.topology + topo = updated_topology(empty_top, notebook, notebook.cells) + # updated_topology should preserve the identity of the topology if nothing changed. This means that we can cache the result of other functions in our code! + @test topo === updated_topology(topo, notebook, notebook.cells) + @test topo === updated_topology(topo, notebook, Cell[]) + @test topo === static_resolve_topology(topo) + + # for n in fieldnames(NotebookTopology) + # @test getfield(topo, n) === getfield(top2a, n) + # end + + setcode!(notebook.cells[1], "x = 999") + topo_2 = updated_topology(topo, notebook, notebook.cells[1:1]) + @test topo_2 !== topo + + + setcode!(notebook.cells[4], "@asdf 1 + 2") + topo_3 = updated_topology(topo_2, notebook, notebook.cells[4:4]) + @test topo_3 !== topo_2 + @test topo_3 !== topo + + @test topo_3.unresolved_cells |> only === notebook.cells[4] + + @test topo_3 === updated_topology(topo_3, notebook, notebook.cells[1:3]) + @test topo_3 === updated_topology(topo_3, notebook, Cell[]) + # rerunning the cell with the macro does not change the topology because it was already unresolved + @test topo_3 === updated_topology(topo_3, notebook, notebook.cells[1:4]) + + # let's pretend that we resolved the macro in the 4th cell + topo_3_resolved = NotebookTopology(; + nodes=topo_3.nodes, + codes=topo_3.codes, + unresolved_cells=setdiff(topo_3.unresolved_cells, notebook.cells[4:4]), + cell_order=topo_3.cell_order, + disabled_cells=topo_3.disabled_cells, + ) + + @test topo_3_resolved === updated_topology(topo_3_resolved, notebook, notebook.cells[1:3]) + @test topo_3_resolved === updated_topology(topo_3_resolved, notebook, Cell[]) + # rerunning the cell with the macro makes it unresolved again + @test topo_3_resolved !== updated_topology(topo_3_resolved, notebook, notebook.cells[1:4]) + + notebook.cells[4] ∈ updated_topology(topo_3_resolved, notebook, notebook.cells[1:4]).unresolved_cells + + # @test topo_3 === static_resolve_topology(topo_3) end end diff --git a/test/Bonds.jl b/test/Bonds.jl index cb698a5bf3..bf1b028e09 100644 --- a/test/Bonds.jl +++ b/test/Bonds.jl @@ -1,23 +1,50 @@ using Test import Pluto -import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Notebook, Cell -import Distributed +import Pluto: update_run!, update_save_run!, WorkspaceManager, ClientSession, ServerSession, Notebook, Cell +import Malt @testset "Bonds" begin 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient + + @testset "Don't write to file" begin + notebook = Notebook([ + Cell(""" + @bind x html"" + """), + Cell("x"), + ]) + update_save_run!(🍭, notebook, notebook.cells) + + old_mtime = mtime(notebook.path) + setcode!(notebook.cells[2], "x #asdf") + update_save_run!(🍭, notebook, notebook.cells[2]) + @test old_mtime != mtime(notebook.path) + + + old_mtime = mtime(notebook.path) + function set_bond_value(name, value, is_first_value=false) + notebook.bonds[name] = Dict("value" => value) + Pluto.set_bond_values_reactive(; session=🍭, notebook, bound_sym_names=[name], + is_first_values=[is_first_value], + run_async=false, + ) + end + + set_bond_value(:x, 1, true) + @test old_mtime == mtime(notebook.path) + set_bond_value(:x, 2, false) + @test old_mtime == mtime(notebook.path) + end @testset "AbstractPlutoDingetjes.jl" begin - 🍭.options.evaluation.workspace_use_distributed = true + 🍭.options.evaluation.workspace_use_distributed = true # because we use AbstractPlutoDingetjes notebook = Notebook([ # 1 Cell(""" begin - import AbstractPlutoDingetjes - const APD = AbstractPlutoDingetjes + import AbstractPlutoDingetjes as APD import AbstractPlutoDingetjes.Bonds end """), @@ -177,16 +204,16 @@ import Distributed Cell("@bind pv4 PossibleValuesTest((x+1 for x in 1:10))"), # 34 Cell("@bind pv5 PossibleValuesTest(1:10)"), + + # 35 - https://github.com/fonsp/Pluto.jl/issues/2465 + Cell(""), + Cell("@bind ts2465 TransformSlider()"), + Cell("ts2465"), ]) - fakeclient.connected_notebook = notebook - - + function set_bond_value(name, value, is_first_value=false) notebook.bonds[name] = Dict("value" => value) - Pluto.set_bond_values_reactive(; - session=🍭, - notebook=notebook, - bound_sym_names=[name], + Pluto.set_bond_values_reactive(; session=🍭, notebook, bound_sym_names=[name], is_first_values=[is_first_value], run_async=false, ) @@ -201,8 +228,7 @@ import Distributed @test notebook.cells[10].output.body == "missing" set_bond_value(:x_simple, 1, true) @test notebook.cells[10].output.body == "1" - - + update_run!(🍭, notebook, notebook.cells) @test noerror(notebook.cells[1]) @@ -247,7 +273,7 @@ import Distributed @test noerror(notebook.cells[32]) @test noerror(notebook.cells[33]) @test noerror(notebook.cells[34]) - @test length(notebook.cells) == 34 + @test length(notebook.cells) == 37 @test Pluto.possible_bond_values(🍭, notebook, :x_new) == [1,2,3] @@ -302,17 +328,38 @@ import Distributed @test notebook.cells[25].output.body == "1" set_bond_value(:x_counter, 7, false) @test notebook.cells[25].output.body == "2" - - + + # https://github.com/fonsp/Pluto.jl/issues/2465 + update_run!(🍭, notebook, notebook.cells[35:37]) + + @test noerror(notebook.cells[35]) + @test noerror(notebook.cells[36]) + @test noerror(notebook.cells[37]) + @test notebook.cells[37].output.body == "\"x\"" + @test isempty(notebook.cells[35].code) + + # this should not deregister the TransformSlider + setcode!(notebook.cells[35], notebook.cells[36].code) + setcode!(notebook.cells[36], "") + + update_run!(🍭, notebook, notebook.cells[35:36]) + @test noerror(notebook.cells[35]) + @test noerror(notebook.cells[36]) + @test notebook.cells[37].output.body == "\"x\"" + + set_bond_value(:ts2465, 2, false) + @test noerror(notebook.cells[35]) + @test noerror(notebook.cells[36]) + @test notebook.cells[37].output.body == "\"xx\"" + WorkspaceManager.unmake_workspace((🍭, notebook)) 🍭.options.evaluation.workspace_use_distributed = false # test that the notebook file is runnable: - test_proc = Distributed.addprocs(1)[1] - - Distributed.remotecall_eval(Main, test_proc, quote + test_proc = Malt.Worker() + Malt.remote_eval_wait(test_proc, quote import Pkg try Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true @@ -320,10 +367,128 @@ import Distributed Pkg.activate(mktempdir()) Pkg.add("AbstractPlutoDingetjes") end) - @test Distributed.remotecall_eval(Main, test_proc, quote + @test Malt.remote_eval_fetch(test_proc, quote include($(notebook.path)) true end) - Distributed.rmprocs(test_proc) + Malt.stop(test_proc) + end + + @testset "Dependent Bound Variables" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = true + notebook = Notebook([ + Cell(raw"""@bind x HTML("")"""), + Cell(raw"""@bind y HTML("")"""), + Cell(raw"""x"""), #3 + Cell(raw"""y"""), #4 + Cell(raw""" + begin + struct TransformSlider + range::AbstractRange + end + + Base.show(io::IO, m::MIME"text/html", os::TransformSlider) = write(io, "") + + Bonds.initial_value(os::TransformSlider) = Bonds.transform_value(os, minimum(os.range)) + Bonds.possible_values(os::TransformSlider) = os.range + Bonds.transform_value(os::TransformSlider, from_js) = from_js * 2 + end + """), + Cell(raw"""begin + hello1 = 123 + @bind a TransformSlider(1:10) + end"""), + Cell(raw"""begin + hello2 = 234 + @bind b TransformSlider(1:a) + end"""), + Cell(raw"""a"""), #8 + Cell(raw"""b"""), #9 + Cell(raw"""hello1"""), #10 + Cell(raw"""hello2"""), #11 + Cell(raw"""using AbstractPlutoDingetjes"""), + ]) + update_run!(🍭, notebook, notebook.cells) + + # Test the get_bond_names function + @test Pluto.get_bond_names(🍭, notebook) == Set([:a, :b, :x, :y]) + + function set_bond_values!(notebook:: Notebook, bonds:: Dict; is_first_value=false) + for (name, value) in bonds + notebook.bonds[name] = Dict("value" => value) + end + Pluto.set_bond_values_reactive(; session=🍭, notebook, bound_sym_names=collect(keys(bonds)), run_async=false, is_first_values=fill(is_first_value, length(bonds))) + end + + @test notebook.cells[3].output.body == "missing" + @test notebook.cells[4].output.body == "missing" # no initial value defined for simple html slider (in contrast to TransformSlider) + @test notebook.cells[8].output.body == "2" + @test notebook.cells[9].output.body == "2" + @test notebook.cells[10].output.body == "123" + @test notebook.cells[11].output.body == "234" + + set_bond_values!(notebook, Dict(:x => 1, :a => 1); is_first_value=true) + @test notebook.cells[3].output.body == "1" + @test notebook.cells[4].output.body == "missing" # no initial value defined for simple html slider (in contrast to TransformSlider) + @test notebook.cells[8].output.body == "2" # TransformSlider scales values *2 + @test notebook.cells[9].output.body == "2" + @test notebook.cells[10].output.body == "123" + @test notebook.cells[11].output.body == "234" + + set_bond_values!(notebook, Dict(:y => 1, :b => 1); is_first_value=true) + @test notebook.cells[3].output.body == "1" + @test notebook.cells[4].output.body == "1" + @test notebook.cells[8].output.body == "2" + @test notebook.cells[9].output.body == "2" + @test notebook.cells[10].output.body == "123" + @test notebook.cells[11].output.body == "234" + + set_bond_values!(notebook, Dict(:x => 5)) + @test notebook.cells[3].output.body == "5" + @test notebook.cells[4].output.body == "missing" # the slider object is re-defined, therefore its value is the default one + + set_bond_values!(notebook, Dict(:y => 3)) + @test notebook.cells[3].output.body == "5" + @test notebook.cells[4].output.body == "3" + + set_bond_values!(notebook, Dict(:x => 10, :y => 5)) + @test notebook.cells[3].output.body == "10" + @test notebook.cells[4].output.body == "5" # this would fail without PR #2014 - previously `y` was reset to the default value `missing` + + set_bond_values!(notebook, Dict(:b => 2)) + @test notebook.cells[8].output.body == "2" + @test notebook.cells[9].output.body == "4" + @test notebook.cells[10].output.body == "123" + @test notebook.cells[11].output.body == "234" + + set_bond_values!(notebook, Dict(:a => 8, :b => 12)) + @test notebook.cells[8].output.body == "16" + @test notebook.cells[9].output.body == "24" # this would fail without PR #2014 + @test notebook.cells[10].output.body == "123" + @test notebook.cells[11].output.body == "234" + + set_bond_values!(notebook, Dict(:a => 1, :b => 1)) + setcode!(notebook.cells[10], "a + hello1") + setcode!(notebook.cells[11], "b + hello2") + update_run!(🍭, notebook, notebook.cells[10:11]) + + @test notebook.cells[10].output.body == "125" + @test notebook.cells[11].output.body == "236" + + set_bond_values!(notebook, Dict(:a => 2, :b => 2)) + @test notebook.cells[10].output.body == "127" + @test notebook.cells[11].output.body == "238" + set_bond_values!(notebook, Dict(:b => 3)) + @test notebook.cells[10].output.body == "127" + @test notebook.cells[11].output.body == "240" + set_bond_values!(notebook, Dict(:a => 1)) + @test notebook.cells[10].output.body == "125" + @test notebook.cells[11].output.body == "236" # changing a will reset b + + + + WorkspaceManager.unmake_workspace((🍭, notebook)) + end end diff --git a/test/Configuration.jl b/test/Configuration.jl index 9cd5bd739b..37630b3847 100644 --- a/test/Configuration.jl +++ b/test/Configuration.jl @@ -5,6 +5,7 @@ using Pluto: ServerSession, ClientSession, SessionActions using Pluto.Configuration using Pluto.Configuration: notebook_path_suggestion, from_flat_kwargs, _convert_to_flags using Pluto.WorkspaceManager: poll +import URIs @testset "Configurations" begin @@ -13,63 +14,106 @@ cd(Pluto.project_relative_path("test")) do end @testset "from_flat_kwargs" begin - opt = from_flat_kwargs(;compile="min", launch_browser=false) + opt = from_flat_kwargs(; compile="min", launch_browser=false) @test opt.compiler.compile == "min" @test opt.server.launch_browser == false - et = @static if isdefined(Pluto.Configuration.Configurations, :InvalidKeyError) - Pluto.Configuration.Configurations.InvalidKeyError - else - ArgumentError + @test_throws MethodError from_flat_kwargs(; asdfasdf="test") + + structs_kwargs = let + structs = [ + Pluto.Configuration.ServerOptions, + Pluto.Configuration.SecurityOptions, + Pluto.Configuration.EvaluationOptions, + Pluto.Configuration.CompilerOptions + ] + sets = [collect(fieldnames(s)) for s in structs] + vcat(sets...)::Vector{Symbol} end - @test_throws et from_flat_kwargs(;asdfasdf="test") + from_flat_kwargs_kwargs = let + method = only(methods(Pluto.Configuration.from_flat_kwargs)) + syms = method.slot_syms + names = split(syms, "\0")[2:end-1] + Symbol.(names)::Vector{Symbol} + end + + # Verify that all struct fields can be set via `from_flat_kwargs`. + # Also verifies ordering to improve code readability. + @test structs_kwargs == from_flat_kwargs_kwargs end @testset "flag conversion" begin - if VERSION > v"1.5.0-" - @test _convert_to_flags(Configuration.CompilerOptions(threads="123")) == - ["--startup-file=no", "--history-file=no", "--threads=123"] - - @test _convert_to_flags(Configuration.CompilerOptions(threads=123)) == - ["--startup-file=no", "--history-file=no", "--threads=123"] - - @test _convert_to_flags(Configuration.CompilerOptions()) ⊇ - ["--startup-file=no", "--history-file=no"] - else - @test _convert_to_flags(Configuration.CompilerOptions()) == - ["--startup-file=no", "--history-file=no"] - end + @test _convert_to_flags(Configuration.CompilerOptions(threads="123")) == + ["--startup-file=no", "--history-file=no", "--threads=123"] + + @test _convert_to_flags(Configuration.CompilerOptions(threads=123)) == + ["--startup-file=no", "--history-file=no", "--threads=123"] + + @test _convert_to_flags(Configuration.CompilerOptions()) ⊇ + ["--startup-file=no", "--history-file=no"] + @test _convert_to_flags(Configuration.CompilerOptions(compile="min")) ⊇ ["--compile=min", "--startup-file=no", "--history-file=no"] end @testset "Authentication" begin + basic_nb_path = Pluto.project_relative_path("sample", "Basic.jl") + port = 1238 - options = Pluto.Configuration.from_flat_kwargs(; port=port, launch_browser=false, workspace_use_distributed=false) - 🍭 = Pluto.ServerSession(; options=options) - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient + options = Pluto.Configuration.from_flat_kwargs(; port, launch_browser=false, workspace_use_distributed=false) + 🍭 = Pluto.ServerSession(; options) host = 🍭.options.server.host secret = 🍭.secret println("Launching test server...") - server_task = @async Pluto.run(🍭) - sleep(2) + server = Pluto.run!(🍭) local_url(suffix) = "http://$host:$port/$suffix" withsecret(url) = occursin('?', url) ? "$url&secret=$secret" : "$url?secret=$secret" - @test HTTP.get(local_url("favicon.ico")).status == 200 - function requeststatus(url, method) - r = HTTP.request(method, url; status_exception=false, redirect=false) - r.status + function request(url, method; kwargs...) + HTTP.request(method, url, nothing, method == "POST" ? read(basic_nb_path) : UInt8[]; status_exception=false, redirect=false, cookies=false, kwargs...) + end + + function shares_secret(response) + any(occursin(secret, y) for (x,y) in response.headers) + end + + public_routes = [ + ("favicon.ico", "GET"), + ("possible_binder_token_please", "GET"), + ("index.css", "GET"), + ("index.js", "GET"), + ("img/favicon-32x32.png", "GET"), + ] + + broken_routes = [ + ("../tsconfig.json", "GET"), + ("/img/", "GET"), + ("open.png?url=$(URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))", "GET"), + ] + + for (suffix, method) in public_routes + url = local_url(suffix) + r = request(url, method) + @test r.status == 200 + @test !shares_secret(r) end + + for (suffix, method) in broken_routes + url = local_url(suffix) + r = request(url, method) + @test r.status ∈ 400:499 + @test !shares_secret(r) + end + - nb = SessionActions.open(🍭, Pluto.project_relative_path("sample", "Basic.jl"); as_sample=true) + nb = SessionActions.open(🍭, basic_nb_path; as_sample=true) simple_routes = [ ("", "GET"), ("edit?id=$(nb.notebook_id)", "GET"), + ("editor.html", "GET"), ("notebookfile?id=$(nb.notebook_id)", "GET"), ("notebookexport?id=$(nb.notebook_id)", "GET"), ("statefile?id=$(nb.notebook_id)", "GET"), @@ -80,78 +124,127 @@ end Pluto.readwrite(x, p) p end - @assert isfile(Pluto.project_relative_path("sample", "Basic.jl")) + @assert isfile(basic_nb_path) effect_routes = [ ("new", "GET"), ("new", "POST"), - ("open?url=$(HTTP.URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))", "GET"), - ("open?url=$(HTTP.URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))", "POST"), - ("open?path=$(HTTP.URIs.escapeuri(Pluto.project_relative_path("sample", "Basic.jl") |> tempcopy))", "GET"), - ("open?path=$(HTTP.URIs.escapeuri(Pluto.project_relative_path("sample", "Basic.jl") |> tempcopy))", "POST"), + ("open?url=$(URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))", "GET"), + ("open?url=$(URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))&execution_allowed=asdf", "GET"), + ("open?url=$(URIs.escapeuri("https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl"))", "POST"), + ("open?path=$(URIs.escapeuri(basic_nb_path |> tempcopy))", "GET"), + ("open?path=$(URIs.escapeuri(basic_nb_path |> tempcopy))", "POST"), ("sample/Basic.jl", "GET"), ("sample/Basic.jl", "POST"), ("notebookupload", "POST"), + ("notebookupload?execution_allowed=asdf", "POST"), ] - for (suffix, method) in simple_routes ∪ effect_routes + @testset "simple & effect w/o auth $suffix $method" for (suffix, method) in simple_routes ∪ effect_routes url = local_url(suffix) - @test requeststatus(url, method) == 403 + r = request(url, method) + @test r.status == 403 + @test !shares_secret(r) end # no notebooks were opened @test length(🍭.notebooks) == 1 - - for (suffix, method) in simple_routes - url = local_url(suffix) |> withsecret - @test requeststatus(url, method) ∈ 200:299 - end - - for (suffix, method) in setdiff(effect_routes, [("notebookupload", "POST")]) - url = local_url(suffix) |> withsecret - @test requeststatus(url, method) ∈ 200:399 # 3xx are redirects - end - - @async schedule(server_task, InterruptException(); error=true) -end - -@testset "Open Notebooks at Startup" begin - port = 1338 - host = "localhost" - local_url(suffix) = "http://$host:$port/$suffix" - - urls = [ - "https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.12.16/sample/Basic.jl", - "https://gist.githubusercontent.com/fonsp/4e164a262a60fc4bdd638e124e629d64/raw/8ffe93c680e539056068456a62dea7bf6b8eb622/basic_pkg_notebook.jl", - ] - nbnames = download.(urls) - server_running() = HTTP.get(local_url("favicon.ico")).status == 200 && HTTP.get(local_url("edit")).status == 200 - - # without notebook at startup - server_task = @async Pluto.run(port=port, launch_browser=false, workspace_use_distributed=false, require_secret_for_access=false, require_secret_for_open_links=false) - @test poll(5) do - server_running() + @testset "require secret only for open links" begin + @test !shares_secret(request(local_url(""), "GET")) + jar = HTTP.Cookies.CookieJar() + + # Let's test the config + # require_secret_for_access = false + # require_secret_for_open_links = true + 🍭.options.security.require_secret_for_access = false + + # Effectful paths should not work without a secret. + @testset "simple & effect w/o auth 1 $suffix $method" for (suffix, method) in effect_routes + url = local_url(suffix) + r = request(url, method; cookies=true, jar) + @test r.status == 403 + @test !shares_secret(r) + end + + # With this config, the / path should work and share the secret, even when requested without a secret. + r = request(local_url(""), "GET"; cookies=true, jar) + @test r.status == 200 + @test shares_secret(r) + + # Now, the other effectful paths should work bc of the secret. + @testset "simple w/o auth 2 $suffix $method" for (suffix, method) in simple_routes + url = local_url(suffix) + r = request(url, method; cookies=true, jar) + @test r.status ∈ 200:299 # 2xx is OK + @test shares_secret(r) + end + + 🍭.options.security.require_secret_for_access = true end - @async schedule(server_task, InterruptException(); error=true) + + jar = HTTP.Cookies.CookieJar() + + @test shares_secret(request(local_url("") |> withsecret, "GET"; cookies=true, jar)) + - # with a single notebook at startup - server_task = @async Pluto.run(notebook=first(nbnames), port=port, launch_browser=false, workspace_use_distributed=false, require_secret_for_access=false, require_secret_for_open_links=false) - @test poll(5) do - server_running() + @testset "simple w/ auth $suffix $method" for (suffix, method) in simple_routes + # should work because of cookie + url = local_url(suffix) + r = request(url, method; cookies=true, jar) + @test r.status ∈ 200:299 # 2xx is OK + @test shares_secret(r) # see reasoning in of https://github.com/fonsp/Pluto.jl/commit/20515dd46678a49ca90e042fcfa3eab1e5c8e162 + + # Without cookies, but with secret in URL + r = request(url |> withsecret, method) + @test r.status ∈ 200:299 # 2xx is OK + @test shares_secret(r) end - @async schedule(server_task, InterruptException(); error=true) - # with multiple notebooks at startup - server_task = @async Pluto.run(notebook=nbnames, port=port, launch_browser=false, workspace_use_distributed=false, require_secret_for_access=false, require_secret_for_open_links=false) - @test poll(5) do - server_running() + @testset "effect w/ auth $suffix $method" for (suffix, method) in effect_routes + old_ids = collect(keys(🍭.notebooks)) + + url = local_url(suffix) |> withsecret + r = request(url, method) + @test r.status ∈ 200:399 # 3xx are redirects + @test shares_secret(r) # see reasoning in of https://github.com/fonsp/Pluto.jl/commit/20515dd46678a49ca90e042fcfa3eab1e5c8e162 + + new_ids = collect(keys(🍭.notebooks)) + nb = 🍭.notebooks[only(setdiff(new_ids, old_ids))] + + if any(x -> occursin(x, suffix), ["new", "execution_allowed", "sample/Basic.jl"]) + @test Pluto.will_run_code(nb) + @test Pluto.will_run_pkg(nb) + else + @test !Pluto.will_run_code(nb) + @test !Pluto.will_run_pkg(nb) + @test nb.process_status === Pluto.ProcessStatus.waiting_for_permission + end end - @async schedule(server_task, InterruptException(); error=true) + close(server) end -# TODO are the processes closed properly? -# TODO we reuse the same port without awaiting the shutdown of the previous server +@testset "disable mimetype via workspace_custom_startup_expr" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = true + 🍭.options.evaluation.workspace_custom_startup_expr = """ + 1 + 1 + PlutoRunner.is_mime_enabled(m::MIME"application/vnd.pluto.tree+object") = false + """ + + nb = Pluto.Notebook([ + Pluto.Cell("x = [1, 2]") + Pluto.Cell("struct Foo; x; end") + Pluto.Cell("Foo(x)") + ]) + + Pluto.update_run!(🍭, nb, nb.cells) + @test nb.cells[1].output.body == repr(MIME"text/plain"(), [1,2]) + @test nb.cells[1].output.mime isa MIME"text/plain" + @test nb.cells[3].output.mime isa MIME"text/plain" + + Pluto.WorkspaceManager.unmake_workspace((🍭, nb)) +end -end # testset +end diff --git a/test/DependencyCache.jl b/test/DependencyCache.jl index 96d69bbd6d..77b2c0b660 100644 --- a/test/DependencyCache.jl +++ b/test/DependencyCache.jl @@ -7,9 +7,6 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient - notebook = Notebook([ Cell("x = 1"), # prerequisite of test cell Cell("f(x) = x + y"), # depends on test cell @@ -23,7 +20,6 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook Cell("g(6) + g(6,6)"), Cell("using Dates"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) state = Pluto.notebook_to_js(notebook) diff --git a/test/Dynamic.jl b/test/Dynamic.jl index 7a1e199c1b..1d8675c740 100644 --- a/test/Dynamic.jl +++ b/test/Dynamic.jl @@ -35,8 +35,6 @@ end client = ClientSession(:buffery, buffer) 🍭 = ServerSession() - # 🍭.connected_clients[client.id] = client - notebook = Notebook([ Cell( @@ -152,8 +150,23 @@ end @testset "Docs" begin @test occursin("square root", Pluto.PlutoRunner.doc_fetcher("sqrt", Main)[1]) @test occursin("square root", Pluto.PlutoRunner.doc_fetcher("Base.sqrt", Main)[1]) + @test occursin("Functions are defined", Pluto.PlutoRunner.doc_fetcher("function", Main)[1]) + @test occursin("Within a module", Pluto.PlutoRunner.doc_fetcher("module", Main)[1]) @test occursin("No documentation found", Pluto.PlutoRunner.doc_fetcher("Base.findmeta", Main)[1]) - + let + doc_output = Pluto.PlutoRunner.doc_fetcher("sor", Main)[1] + @test occursin("Similar results:", doc_output) + @test occursin("sort", doc_output) + end + + @test occursin("\\div", Pluto.PlutoRunner.doc_fetcher("÷", Main)[1]) + @test occursin("\\gamma", Pluto.PlutoRunner.doc_fetcher("γ", Main)[1]) + let # the expression is not valid, so this doc fetch fails + doc_output, result = Pluto.PlutoRunner.doc_fetcher("🍕\"", Main) + @test isnothing(doc_output) + @test result == :👎 + end + # Issue #1128 # Ref https://docs.julialang.org/en/v1/manual/documentation/#Dynamic-documentation m = Module() @@ -169,7 +182,7 @@ end global y end )) - + @test occursin("Normal docstring", Pluto.PlutoRunner.doc_fetcher("MyType", m.DocTest)[1]) @test occursin("Normal docstring", Pluto.PlutoRunner.doc_fetcher("DocTest.MyType", m)[1]) @test occursin("Documentation for MyType with value", Pluto.PlutoRunner.doc_fetcher("x", m.DocTest)[1]) @@ -179,40 +192,70 @@ end end @testset "PlutoRunner API" begin - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() - 🍭.options.evaluation.workspace_use_distributed = true - 🍭.connected_clients[fakeclient.id] = fakeclient + # 🍭.options.evaluation.workspace_use_distributed = true + + cid = uuid1() notebook = Notebook([ Cell("PlutoRunner.notebook_id[] |> Text"), - Cell(""" - let - # not actually public API but we test it anyways - a = PlutoRunner._publish(Dict( + # These cells tests `core_published_to_js`, which is the function used by the official API (`AbtractPlutoDingetjes.Display.published_to_js`). + Cell(cid, """ + begin + + a = Dict( "hello" => "world", "xx" => UInt8[6,7,8], - )) - b = PlutoRunner._publish("cool") - Text((a, b)) + ) + b = "cool" + + struct ZZZ + x + y + end + + function Base.show(io::IO, ::MIME"text/html", z::ZZZ) + write(io, "") + end + + ZZZ(a, b) end """), - Cell("3"), + Cell(""" + begin + struct ABC + x + end + ZZZ( + 123, + Dict("a" => 234, "b" => ABC(4)), + ) + end + """), + # This is the deprecated API: Cell("PlutoRunner.publish_to_js(Ref(4))"), - Cell("PlutoRunner.publish_to_js((ref=4,))"), + Cell("PlutoRunner.publish_to_js((ref=5,))"), Cell("x = Dict(:a => 6)"), Cell("PlutoRunner.publish_to_js(x)"), ]) - fakeclient.connected_notebook = notebook update_save_run!(🍭, notebook, notebook.cells) @test notebook.cells[1].output.body == notebook.notebook_id |> string - @test !notebook.cells[2].errored - a, b = Meta.parse(notebook.cells[2].output.body) |> eval + @test notebook.cells[2] |> noerror + @test notebook.cells[2].output.mime isa MIME"text/html" + + ab1, ab2 = keys(notebook.cells[2].published_objects) + @test occursin(ab1, notebook.cells[2].output.body) + @test occursin(ab2, notebook.cells[2].output.body) + + ab() = sort(collect(keys(notebook.cells[2].published_objects)); by=(s -> findfirst(s, notebook.cells[2].output.body) |> first)) + a, b = ab() + p = notebook.cells[2].published_objects - @test sort(collect(keys(p))) == sort([a,b]) - @test isempty(notebook.cells[3].published_objects) @test p[a] == Dict( "hello" => "world", @@ -224,18 +267,29 @@ end old_pb = p[b] update_save_run!(🍭, notebook, notebook.cells) p = notebook.cells[2].published_objects - a, b = Meta.parse(notebook.cells[2].output.body) |> eval + a, b = ab() @test p[a] == old_pa @test p[b] == old_pb @test !isempty(notebook.cells[2].published_objects) - setcode(notebook.cells[2], "2") + # display should have failed + @test only(values(notebook.cells[3].published_objects)) == 123 + msg = notebook.cells[3].output.body[:msg] + @test occursin("Failed to show value", msg) + @test occursin("ABC is not compatible", msg) + + + + setcode!(notebook.cells[2], "2") update_save_run!(🍭, notebook, notebook.cells) @test isempty(notebook.cells[2].published_objects) - + @test isempty(notebook.cells[2].published_objects) + + + @test notebook.cells[4].errored - @test !notebook.cells[5].errored + @test notebook.cells[5] |> noerror @test !isempty(notebook.cells[5].published_objects) diff --git a/test/Events.jl b/test/Events.jl index 5727d387f0..1dbfdaee03 100644 --- a/test/Events.jl +++ b/test/Events.jl @@ -9,23 +9,20 @@ import UUIDs: UUID events = [] function test_listener(a::PlutoEvent) - @info "this run!" + # @info "this run!" push!(events, typeof(a)) end - 🍭 = ServerSession(; event_listener = test_listener) + 🍭 = ServerSession() + 🍭.options.server.on_event = test_listener 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient notebook = Notebook([ Cell("[1,1,[1]]"), Cell("Dict(:a => [:b, :c])"), ]) - fakeclient.connected_notebook = notebook - update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) @test_broken events[1:3] == ["NewNotebookEvent", "OpenNotebookEvent" , "FileSaveEvent"] # Pluto.CustomLaunchEvent: Gets fired diff --git a/test/ExpressionExplorer.jl b/test/ExpressionExplorer.jl index be36821c41..7835ba19a7 100644 --- a/test/ExpressionExplorer.jl +++ b/test/ExpressionExplorer.jl @@ -1,627 +1,246 @@ -using Test - -#= -`@test_broken` means that the test doesn't pass right now, but we want it to pass. Feel free to try to fix it and open a PR! -Some of these @test_broken lines are commented out to prevent printing to the terminal, but we still want them fixed. - -# When working on ExpressionExplorer: - -- Go to runtests.jl and move `include("ExpressionExplorer.jl")` to the second line, so that they run instantly (after loading the helper functions). Be careful not to commit this change. -- If you are fixing a `@test_broken`: - - uncomment that line if needed - - change `@test_broken` to `@test` - - remove `verbose=false` at the end of the line -- If you are fixing something else: - - you can add lots of tests! They run super fast, don't worry about duplicates too much - --fons =# - -@testset "Explore Expressions" begin - @testset "Basics" begin - @test testee(:(a), [:a], [], [], []) - @test testee(:(1 + 1), [], [], [:+], []) - @test testee(:(sqrt(1)), [], [], [:sqrt], []) - @test testee(:(x = 3), [], [:x], [], []) - @test testee(:(x = x), [:x], [:x], [], []) - @test testee(:(x = 1 + y), [:y], [:x], [:+], []) - @test testee(:(x = +(a...)), [:a], [:x], [:+], []) - @test testee(:(1:3), [], [], [:(:)], []) - end - @testset "Bad code" begin - # @test_nowarn testee(:(begin end = 2), [:+], [], [:+], [], verbose=false) - @test testee(:(123 = x), [:x], [], [], []) - @test_nowarn testee(:((a = b, c, d = 123,)), [:b], [], [], [], verbose=false) - @test_nowarn testee(:((a = b, c[r] = 2, d = 123,)), [:b], [], [], [], verbose=false) - - @test_nowarn testee(:(function f(function g() end) end), [], [], [:+], [], verbose=false) - @test_nowarn testee(:(function f() Base.sqrt(x::String) = 2; end), [], [], [:+], [], verbose=false) - @test_nowarn testee(:(function f() global g(x) = x; end), [], [], [], [], verbose=false) - end - @testset "Lists and structs" begin - @test testee(:(1:3), [], [], [:(:)], []) - @test testee(:(a[1:3,4]), [:a], [], [:(:)], []) - @test testee(:(a[b]), [:a, :b], [], [], []) - @test testee(:([a[1:3,4]; b[5]]), [:b, :a], [], [:(:)], []) - @test testee(:(a.someproperty), [:a], [], [], []) # `a` can also be a module - @test testee(:([a..., b]), [:a, :b], [], [], []) - @test testee(:(struct a; b; c; end), [], [:a], [], [ - :a => ([], [], [], []) - ]) - @test testee(:(let struct a; b; c; end end), [], [:a], [], [ - :a => ([], [], [], []) - ]) - - @test testee(:(module a; f(x) = x; z = r end), [], [:a], [], []) - end - @testset "Types" begin - @test testee(:(x::Foo = 3), [:Foo], [:x], [], []) - @test testee(:(x::Foo), [:x, :Foo], [], [], []) - @test testee(:(a::Foo, b::String = 1, "2"), [:Foo, :String], [:a, :b], [], []) - @test testee(:(Foo[]), [:Foo], [], [], []) - @test testee(:(x isa Foo), [:x, :Foo], [], [:isa], []) - - @test testee(:(A{B} = B), [], [:A], [], []) - @test testee(:(A{T} = Union{T,Int}), [:Int, :Union], [:A], [], []) - - @test testee(:(abstract type a end), [], [:a], [], [:a => ([], [], [], [])]) - @test testee(:(abstract type a <: b end), [], [:a], [], [:a => ([:b], [], [], [])]) - @test testee(:(abstract type a <: b{C} end), [], [:a], [], [:a => ([:b, :C], [], [], [])]) - @test testee(:(abstract type a{T} end), [], [:a], [], [:a => ([], [], [], [])]) - @test testee(:(abstract type a{T,S} end), [], [:a], [], [:a => ([], [], [], [])]) - @test testee(:(abstract type a{T} <: b end), [], [:a], [], [:a => ([:b], [], [], [])]) - @test testee(:(abstract type a{T} <: b{T} end), [], [:a], [], [:a => ([:b], [], [], [])]) - @test_nowarn testee(macroexpand(Main, :(@enum a b c)), [], [], [], []; verbose=false) - - e = :(struct a end) # needs to be on its own line to create LineNumberNode - @test testee(e, [], [:a], [], [:a => ([], [], [], [])]) - @test testee(:(struct a <: b; c; d::Foo; end), [], [:a], [], [:a => ([:b, :Foo], [], [], [])]) - @test testee(:(struct a{T,S}; c::T; d::Foo; end), [], [:a], [], [:a => ([:Foo], [], [], [])]) - @test testee(:(struct a{T} <: b; c; d::Foo; end), [], [:a], [], [:a => ([:b, :Foo], [], [], [])]) - @test testee(:(struct a{T} <: b{T}; c; d::Foo; end), [], [:a], [], [:a => ([:b, :Foo], [], [], [])]) - @test testee(:(struct a; c; a(x=y) = new(x, z); end), [], [:a], [], [:a => ([:y, :z], [], [:new], [])]) - @test testee(:(struct a{A,B<:C{A}}; i::A; j::B end), [], [:a], [], [:a => ([:C], [], [], [])]) - @test testee(:(struct a{A,B<:C{<:A}} <: D{A,B}; i::A; j::B end), [], [:a], [], [:a => ([:C, :D], [], [], [])]) - @test testee(:(struct a{A,DD<:B.C{D.E{A}}} <: K.A{A} i::A; j::DD; k::C end), [], [:a], [], [:a => ([:B, :C, :D, :K], [], [], [])]) - # @test_broken testee(:(struct a; c; a(x=y) = new(x,z); end), [], [:a], [], [:a => ([:y, :z], [], [], [])], verbose=false) - end - @testset "Assignment operator & modifiers" begin - # https://github.com/JuliaLang/julia/blob/f449765943ba414bd57c3d1a44a73e5a0bb27534/base/docs/basedocs.jl#L239-L244 - @test testee(:(a = a), [:a], [:a], [], []) - @test testee(:(a = a + 1), [:a], [:a], [:+], []) - @test testee(:(x = a = a + 1), [:a], [:a, :x], [:+], []) - @test testee(:(const a = b), [:b], [:a], [], []) - @test testee(:(f(x) = x), [], [], [], [:f => ([], [], [], [])]) - @test testee(:(a[b,c,:] = d), [:a, :b, :c, :d, :(:)], [], [], []) - @test testee(:(a.b = c), [:a, :c], [], [], []) - @test testee(:(f(a, b=c, d=e; f=g)), [:a, :c, :e, :g], [], [:f], []) - - @test testee(:(a += 1), [:a], [:a], [:+], []) - @test testee(:(a >>>= 1), [:a], [:a], [:>>>], []) - @test testee(:(a ⊻= 1), [:a], [:a], [:⊻], []) - @test testee(:(a[1] += 1), [:a], [], [:+], []) - @test testee(:(x = let a = 1; a += b end), [:b], [:x], [:+], []) - @test testee(:(_ = a + 1), [:a], [], [:+], []) - @test testee(:(a = _ + 1), [], [:a], [:+], []) - end - @testset "Tuples" begin - @test testee(:((a, b,)), [:a,:b], [], [], []) - @test testee(:((a = b, c = 2, d = 123,)), [:b], [], [], []) - @test testee(:((a = b,)), [:b], [], [], []) - @test testee(:(a, b = 1, 2), [], [:a, :b], [], []) - @test testee(:(a, _, c, __ = 1, 2, 3, _d), [:_d], [:a, :c], [], []) - @test testee(:(const a, b = 1, 2), [], [:a, :b], [], []) - @test testee(:((a, b) = 1, 2), [], [:a, :b], [], []) - @test testee(:(a = b, c), [:b, :c], [:a], [], []) - @test testee(:(a, b = c), [:c], [:a, :b], [], []) - @test testee(:(a = (b, c)), [:b, :c], [:a], [], []) - @test testee(:(a, (b, c) = [e,[f,g]]), [:e, :f, :g], [:a, :b, :c], [], []) - @test testee(:((x, y), a, (b, c) = z, e, (f, g)), [:z, :e, :f, :g], [:x, :y, :a, :b, :c], [], []) - @test testee(:((x[i], y.r), a, (b, c) = z, e, (f, g)), [:x, :i, :y, :z, :e, :f, :g], [:a, :b, :c], [], []) - @test testee(:((a[i], b.r) = (c.d, 2)), [:a, :b, :i, :c], [], [], []) - @test testee(:((; a, b) = x), [:x], [:a, :b], [], []) - end - @testset "Broadcasting" begin - @test testee(:(a .= b), [:b, :a], [], [], []) # modifies elements, doesn't set `a` - @test testee(:(a .+= b), [:b, :a], [], [:+], []) - @test testee(:(a[i] .+= b), [:b, :a, :i], [], [:+], []) - @test testee(:(a .+ b ./ sqrt.(c, d)), [:a, :b, :c, :d], [], [:+, :/, :sqrt], []) - - # in 1.5 :(.+) is a symbol, in 1.6 its Expr:(:(.), :+) - broadcasted_add = :(.+) isa Symbol ? :(.+) : :+ - @test testee(:(f = .+), [broadcasted_add], [:f], [], []) - @test testee(:(reduce(.+, foo)), [broadcasted_add, :foo], [], [:reduce], []) - end - @testset "`for` & `while`" begin - @test testee(:(for k in 1:n; k + s; end), [:n, :s], [], [:+, :(:)], []) - @test testee(:(for k in 1:2, r in 3:4; global z = k + r; end), [], [:z], [:+, :(:)], []) - @test testee(:(while k < 2; r = w; global z = k + r; end), [:k, :w], [:z], [:+, :(<)], []) - end - @testset "`try` & `catch`" begin - @test testee(:(try a = b + 1 catch; end), [:b], [], [:+], []) - @test testee(:(try a() catch e; e end), [], [], [:a], []) - @test testee(:(try a() catch; e end), [:e], [], [:a], []) - @test testee(:(try a + 1 catch a; a end), [:a], [], [:+], []) - @test testee(:(try 1 catch e; e finally a end), [:a], [], [], []) - @test testee(:(try 1 finally a end), [:a], [], [], []) - end - @testset "Comprehensions" begin - @test testee(:([sqrt(s) for s in 1:n]), [:n], [], [:sqrt, :(:)], []) - @test testee(:([sqrt(s + r) for s in 1:n, r in k]), [:n, :k], [], [:sqrt, :(:), :+], []) - @test testee(:([s + j + r + m for s in 1:3 for j in 4:5 for (r, l) in [(1, 2)]]), [:m], [], [:+, :(:)], []) - @test testee(:([a for a in b if a != 2]), [:b], [], [:(!=)], []) - @test testee(:([a for a in f() if g(a)]), [], [], [:f, :g], []) - @test testee(:([c(a) for a in f() if g(a)]), [], [], [:c, :f, :g], []) - @test testee(:([k for k in P, j in 1:k]), [:k, :P], [], [:(:)], []) - - @test testee(:([a for a in a]), [:a], [], [], []) - @test testee(:(for a in a; a; end), [:a], [], [], []) - @test testee(:(let a = a; a; end), [:a], [], [], []) - @test testee(:(let a = a end), [:a], [], [], []) - @test testee(:(let a = b end), [:b], [], [], []) - @test testee(:(a = a), [:a], [:a], [], []) - @test testee(:(a = [a for a in a]), [:a], [:a], [], []) - end - @testset "Multiple expressions" begin - @test testee(:(x = let r = 1; r + r end), [], [:x], [:+], []) - @test testee(:(begin let r = 1; r + r end; r = 2 end), [], [:r], [:+], []) - @test testee(:((k = 2; 123)), [], [:k], [], []) - @test testee(:((a = 1; b = a + 1)), [], [:a, :b], [:+], []) - @test testee(Meta.parse("a = 1; b = a + 1"), [], [:a, :b], [:+], []) - @test testee(:((a = b = 1)), [], [:a, :b], [], []) - @test testee(:(let k = 2; 123 end), [], [], [], []) - @test testee(:(let k() = 2 end), [], [], [], []) - end - @testset "Functions" begin - @test testee(:(function g() r = 2; r end), [], [], [], [ - :g => ([], [], [], []) - ]) - @test testee(:(function g end), [], [], [], [ - :g => ([], [], [], []) - ]) - @test testee(:(function f() g(x) = x; end), [], [], [], [ - :f => ([], [], [], []) # g is not a global def - ]) - @test testee(:(function f(z) g(x) = x; g(z) end), [], [], [], [ - :f => ([], [], [], []) - ]) - @test testee(:(function f(x, y=1; r, s=3 + 3) r + s + x * y * z end), [], [], [], [ - :f => ([:z], [], [:+, :*], []) - ]) - @test testee(:(function f(x) x * y * z end), [], [], [], [ - :f => ([:y, :z], [], [:*], []) - ]) - @test testee(:(function f(x) x = x / 3; x end), [], [], [], [ - :f => ([], [], [:/], []) - ]) - @test testee(:(function f(x) a end; function f(x, y) b end), [], [], [], [ - :f => ([:a, :b], [], [], []) - ]) - @test testee(:(function f(x, args...; kwargs...) return [x, y, args..., kwargs...] end), [], [], [], [ - :f => ([:y], [], [], []) - ]) - @test testee(:(function f(x; y=x) y + x end), [], [], [], [ - :f => ([], [], [:+], []) - ]) - @test testee(:(function (A::MyType)(x; y=x) y + x end), [], [], [], [ - :MyType => ([], [], [:+], []) - ]) - @test testee(:(f(x, y=a + 1) = x * y * z), [], [], [], [ - :f => ([:z, :a], [], [:*, :+], []) - ]) - @test testee(:(begin f() = 1; f end), [], [], [], [ - :f => ([], [], [], []) - ]) - @test testee(:(begin f() = 1; f() end), [], [], [], [ - :f => ([], [], [], []) - ]) - @test testee(:(begin - f(x) = (global a = √b) - f(x, y) = (global c = -d) - end), [], [], [], [ - :f => ([:b, :d], [:a, :c], [:√, :-], []) - ]) - @test testee(:(Base.show() = 0), [:Base], [], [], [ - [:Base, :show] => ([], [], [], []) - ]) - @test testee(:((x;p) -> f(x+p)), [], [], [], [ - :anon => ([], [], [:f, :+], []) - ]) - @test testee(:(begin x; p end -> f(x+p)), [], [], [], [ - :anon => ([], [], [:f, :+], []) - ]) - @test testee(:(minimum(x) do (a, b); a + b end), [:x], [], [:minimum], [ - :anon => ([], [], [:+], []) - ]) - @test testee(:(f = x -> x * y), [], [:f], [], [ - :anon => ([:y], [], [:*], []) - ]) - @test testee(:(f = (x, y) -> x * y), [], [:f], [], [ - :anon => ([], [], [:*], []) - ]) - @test testee(:(f = (x, y = a + 1) -> x * y), [], [:f], [], [ - :anon => ([:a], [], [:*, :+], []) - ]) - @test testee(:((((a, b), c), (d, e)) -> a * b * c * d * e * f), [], [], [], [ - :anon => ([:f], [], [:*], []) - ]) - @test testee(:((a...) -> f(a...)), [], [], [], [ - :anon => ([], [], [:f], []) - ]) - @test testee(:(f = (args...) -> [args..., y]), [], [:f], [], [ - :anon => ([:y], [], [], []) - ]) - @test testee(:(f = (x, args...; kwargs...) -> [x, y, args..., kwargs...]), [], [:f], [], [ - :anon => ([:y], [], [], []) - ]) - @test testee(:(f = function (a, b) a + b * n end), [:n], [:f], [:+, :*], []) - @test testee(:(f = function () a + b end), [:a, :b], [:f], [:+], []) - - @test testee(:(g(; b=b) = b), [], [], [], [:g => ([:b], [], [], [])]) - @test testee(:(g(b=b) = b), [], [], [], [:g => ([:b], [], [], [])]) - @test testee(:(f(x = y) = x), [], [], [], [:f => ([:y], [], [], [])]) - @test testee(:(f(x, g=function(y=x) x + y + z end) = x * g(x)), [], [], [], [ - :f => ([:z], [], [:+, :*], []) - ]) - - @test testee(:(func(a)), [:a], [], [:func], []) - @test testee(:(func(a; b=c)), [:a, :c], [], [:func], []) - @test testee(:(func(a, b=c)), [:a, :c], [], [:func], []) - @test testee(:(√ b), [:b], [], [:√], []) - @test testee(:(funcs[i](b)), [:funcs, :i, :b], [], [], []) - @test testee(:(f(a)(b)), [:a, :b], [], [:f], []) - @test testee(:(f(a).b()), [:a], [], [:f], []) - - @test testee(:(a.b(c)), [:a, :c], [], [[:a,:b]], []) - @test testee(:(a.b.c(d)), [:a, :d], [], [[:a,:b,:c]], []) - @test testee(:(a.b(c)(d)), [:a, :c, :d], [], [[:a,:b]], []) - @test testee(:(a.b(c).d(e)), [:a, :c, :e], [], [[:a,:b]], []) - @test testee(:(a.b[c].d(e)), [:a, :c, :e], [], [], []) - @test testee(:(let aa = blah; aa.f() end), [:blah], [], [], []) - @test testee(:(let aa = blah; aa.f(a, b, c) end), [:blah, :a, :b, :c], [], [], []) - @test testee(:(f(a) = a.b()), [], [], [], [:f => ([], [], [], [])]) - - @test testee(:(function f() - function hello() - end - hello() - end), [], [], [], [:f => ([], [], [], [])]) - @test testee(:(function a() - b() = Test() - b() - end), [], [], [], [:a => ([], [], [:Test], [])]) - @test testee(:(begin - function f() - g() = z - g() - end - g() - end), [], [], [:g], [:f => ([:z], [], [], [])]) - end - @testset "Julia lowering" begin - @test test_expression_explorer(expr=:(a'b), references=[:a, :b], funccalls=[:*, :adjoint]) - end - @testset "Functions & types" begin - @test testee(:(function f(y::Int64=a)::String string(y) end), [], [], [], [ - :f => ([:String, :Int64, :a], [], [:string], []) - ]) - @test testee(:(f(a::A)::C = a.a;), [], [], [], [ - :f => ([:A, :C], [], [], []) - ]) - @test testee(:(function f(x::T; k=1) where T return x + 1 end), [], [], [], [ - :f => ([], [], [:+], []) - ]) - @test testee(:(function f(x::T; k=1) where {T,S <: R} return x + 1 end), [], [], [], [ - :f => ([:R], [], [:+], []) - ]) - @test testee(:(f(x)::String = x), [], [], [], [ - :f => ([:String], [], [], []) - ]) - @test testee(:(MIME"text/html"), [], [], [], [], [Symbol("@MIME_str")]) - @test testee(:(function f(::MIME"text/html") 1 end), [], [], [], [ - :f => ([], [], [], [], [Symbol("@MIME_str")]) - ]) - @test testee(:(a(a::AbstractArray{T}) where T = 5), [], [], [], [ - :a => ([:AbstractArray], [], [], []) - ]) - @test testee(:(a(a::AbstractArray{T,R}) where {T,S} = a + b), [], [], [], [ - :a => ([:AbstractArray, :b, :R], [], [:+], []) - ]) - @test testee(:(f(::A) = 1), [], [], [], [ - :f => ([:A], [], [], []) - ]) - @test testee(:(f(::A, ::B) = 1), [], [], [], [ - :f => ([:A, :B], [], [], []) - ]) - @test testee(:(f(a::A, ::B, c::C...) = a + c), [], [], [], [ - :f => ([:A, :B, :C], [], [:+], []) - ]) - - @test testee(:((obj::MyType)(x,y) = x + z), [], [], [], [ - :MyType => ([:z], [], [:+], []) - ]) - @test testee(:((obj::MyType)() = 1), [], [], [], [ - :MyType => ([], [], [], []) - ]) - @test testee(:((obj::MyType)(x, args...; kwargs...) = [x, y, args..., kwargs...]), [], [], [], [ - :MyType => ([:y], [], [], []) - ]) - @test testee(:(function (obj::MyType)(x, y) x + z end), [], [], [], [ - :MyType => ([:z], [], [:+], []) - ]) - @test testee(:(begin struct MyType x::String end; (obj::MyType)(y) = obj.x + y; end), [], [:MyType], [], [ - :MyType => ([:String], [], [:+], []) - ]) - @test testee(:(begin struct MyType x::String end; function(obj::MyType)(y) obj.x + y; end; end), [], [:MyType], [], [ - :MyType => ([:String], [], [:+], []) - ]) - @test testee(:((::MyType)(x,y) = x + y), [], [], [], [ - :MyType => ([], [], [:+], []) - ]) - @test testee(:((obj::typeof(Int64[]))(x, y::Float64) = obj + x + y), [], [], [], [ - :anon => ([:Int64, :Float64], [], [:+, :typeof], []) - ]) - @test testee(:((::Get(MyType))(x, y::OtherType) = y * x + z), [], [], [], [ - :anon => ([:MyType, :z, :OtherType], [], [:Get, :*, :+], []) - ]) - end - @testset "Scope modifiers" begin - @test testee(:(let global a, b = 1, 2 end), [], [:a, :b], [], []) - @test_broken testee(:(let global a = b = 1 end), [], [:a], [], []; verbose=false) - @test testee(:(let global k = 3 end), [], [:k], [], []) - @test_broken testee(:(let global k = r end), [], [:k], [], []; verbose=false) - @test testee(:(let global k = 3; k end), [], [:k], [], []) - @test testee(:(let global k += 3 end), [:k], [:k], [:+], []) - @test testee(:(let global k; k = 4 end), [], [:k], [], []) - @test testee(:(let global k; b = 5 end), [], [], [], []) - @test testee(:(let global x, y, z; b = 5; x = 1; (y,z) = 3 end), [], [:x, :y, :z], [], []) - @test testee(:(let global x, z; b = 5; x = 1; end), [], [:x], [], []) - @test testee(:(let a = 1, b = 2; show(a + b) end), [], [], [:show, :+], []) - - @test testee(:(begin local a, b = 1, 2 end), [], [], [], []) - @test testee(:(begin local a = b = 1 end), [], [:b], [], []) - @test testee(:(begin local k = 3 end), [], [], [], []) - @test testee(:(begin local k = r end), [:r], [], [], []) - @test testee(:(begin local k = 3; k; b = 4 end), [], [:b], [], []) - @test testee(:(begin local k += 3 end), [], [], [:+], []) # does not reference global k - @test testee(:(begin local k; k = 4 end), [], [], [], []) - @test testee(:(begin local k; b = 5 end), [], [:b], [], []) - @test testee(:(begin local r[1] = 5 end), [:r], [], [], []) - @test testee(:(begin local a, b; a = 1; b = 2 end), [], [], [], []) - @test testee(:(begin a; local a, b; a = 1; b = 2 end), [:a], [], [], []) - @test_broken testee(:(begin begin local a = 2 end; a end), [:a], [], [], []; verbose=false) - - @test testee(:(function f(x) global k = x end), [], [], [], [ - :f => ([], [:k], [], []) - ]) - @test testee(:((begin x = 1 end, y)), [:y], [:x], [], []) - @test testee(:(x = let global a += 1 end), [:a], [:x, :a], [:+], []) - end - @testset "`import` & `using`" begin - @test testee(:(using Plots), [], [:Plots], [], []) - @test testee(:(using Plots.ExpressionExplorer), [], [:ExpressionExplorer], [], []) - @test testee(:(using JSON, UUIDs), [], [:JSON, :UUIDs], [], []) - @test testee(:(import Pluto), [], [:Pluto], [], []) - @test testee(:(import Pluto: wow, wowie), [], [:wow, :wowie], [], []) - @test testee(:(import Pluto.ExpressionExplorer.wow, Plutowie), [], [:wow, :Plutowie], [], []) - @test testee(:(import .Pluto: wow), [], [:wow], [], []) - @test testee(:(import ..Pluto: wow), [], [:wow], [], []) - @test testee(:(let; import Pluto.wow, Dates; end), [], [:wow, :Dates], [], []) - @test testee(:(while false; import Pluto.wow, Dates; end), [], [:wow, :Dates], [], []) - @test testee(:(try; using Pluto.wow, Dates; catch; end), [], [:wow, :Dates], [], []) - @test testee(:(module A; import B end), [], [:A], [], []) - end - @testset "Foreign macros" begin - # parameterizedfunctions - @test testee(quote - f = @ode_def LotkaVolterra begin - dx = a*x - b*x*y - dy = -c*y + d*x*y - end a b c d - end, [], [:f], [], [], [Symbol("@ode_def")]) - @test testee(quote - f = @ode_def begin - dx = a*x - b*x*y - dy = -c*y + d*x*y - end a b c d - end, [], [:f], [], [], [Symbol("@ode_def")]) - # flux - @test testee(:(@functor Asdf), [], [], [], [], [Symbol("@functor")]) - # symbolics - @test testee(:(@variables a b c), [], [], [], [], [Symbol("@variables")]) - @test testee(:(@variables a b[1:2] c(t) d(..)), [], [], [], [], [Symbol("@variables")]) - @test testee(:(@variables a b[1:x] c[1:10](t) d(..)), [], [], [], [], [Symbol("@variables")]) - @test_nowarn testee(:(@variables(m, begin - x - y[i=1:2] >= i, (start = i, base_name = "Y_$i") - z, Bin - end)), [:m, :Bin], [:x, :y, :z], [Symbol("@variables")], [], verbose=false) - # jump - # @test testee(:(@variable(m, x)), [:m], [:x], [Symbol("@variable")], []) - # @test testee(:(@variable(m, 1<=x)), [:m], [:x], [Symbol("@variable")], []) - # @test testee(:(@variable(m, 1<=x<=2)), [:m], [:x], [Symbol("@variable")], []) - # @test testee(:(@variable(m, r <= x[i=keys(asdf)] <= ub[i])), [:m, :r, :asdf, :ub], [:x], [:keys, Symbol("@variable")], []) - # @test testee(:(@variable(m, x, lower_bound=0)), [:m], [:x], [Symbol("@variable")], []) - # @test testee(:(@variable(m, base_name="x", lower_bound=0)), [:m], [], [Symbol("@variable")], []) - # @test testee(:(@variables(m, begin - # x - # y[i=1:2] >= i, (start = i, base_name = "Y_$i") - # z, Bin - # end)), [:m, :Bin], [:x, :y, :z], [Symbol("@variables")], []) - end - @testset "Macros" begin - # Macros tests are not just in ExpressionExplorer now - - @test testee(:(@time a = 2), [], [], [], [], [Symbol("@time")]) - @test testee(:(@f(x; y=z)), [], [], [], [], [Symbol("@f")]) - @test testee(:(@f(x, y = z)), [], [], [], [], [Symbol("@f")]) # https://github.com/fonsp/Pluto.jl/issues/252 - @test testee(:(Base.@time a = 2), [], [], [], [], [[:Base, Symbol("@time")]]) - # @test_nowarn testee(:(@enum a b = d c), [:d], [:a, :b, :c], [Symbol("@enum")], []) - # @enum is tested in test/React.jl instead - @test testee(:(@gensym a b c), [], [:a, :b, :c], [:gensym], [], [Symbol("@gensym")]) - @test testee(:(Base.@gensym a b c), [], [:a, :b, :c], [:gensym], [], [[:Base, Symbol("@gensym")]]) - @test testee(:(Base.@kwdef struct A; x = 1; y::Int = two; z end), [], [], [], [], [[:Base, Symbol("@kwdef")]]) - @test testee(quote "asdf" f(x) = x end, [], [], [], [], [Symbol("@doc")]) - - @test testee(:(@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [Symbol("@bind")]) - @test testee(:(PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [[:PlutoRunner, Symbol("@bind")]]) - @test_broken testee(:(Main.PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :create_bond], [:PlutoRunner, Symbol("@bind")]], [], verbose=false) - @test testee(:(let @bind a b end), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [Symbol("@bind")]) - - @test testee(:(@asdf a = x1 b = x2 c = x3), [], [], [], [], [Symbol("@asdf")]) # https://github.com/fonsp/Pluto.jl/issues/670 - - @test testee(:(@einsum a[i,j] := x[i]*y[j]), [], [], [], [], [Symbol("@einsum")]) - @test testee(:(@tullio a := f(x)[i+2j, k[j]] init=z), [], [], [], [], [Symbol("@tullio")]) - @test testee(:(Pack.@asdf a[1,k[j]] := log(x[i]/y[j])), [], [], [], [], [[:Pack, Symbol("@asdf")]]) - - @test testee(:(`hey $(a = 1) $(b)`), [:b], [], [:cmd_gen], [], [Symbol("@cmd")]) - @test testee(:(md"hey $(@bind a b) $(a)"), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get], :getindex], [], [Symbol("@md_str"), Symbol("@bind")]) - @test testee(:(md"hey $(a) $(@bind a b)"), [:a, :b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get], :getindex], [], [Symbol("@md_str"), Symbol("@bind")]) - @test testee(:(html"a $(b = c)"), [], [], [], [], [Symbol("@html_str")]) - @test testee(:(md"a $(b = c) $(b)"), [:c], [:b], [:getindex], [], [Symbol("@md_str")]) - @test testee(:(md"\* $r"), [:r], [], [:getindex], [], [Symbol("@md_str")]) - @test testee(:(md"a \$(b = c)"), [], [], [:getindex], [], [Symbol("@md_str")]) - @test testee(:(macro a() end), [], [], [], [ - Symbol("@a") => ([], [], [], []) - ]) - @test testee(:(macro a(b::Int); b end), [], [], [], [ - Symbol("@a") => ([:Int], [], [], []) - ]) - @test testee(:(macro a(b::Int=c) end), [], [], [], [ - Symbol("@a") => ([:Int, :c], [], [], []) - ]) - @test testee(:(macro a(); b = c; return b end), [], [], [], [ - Symbol("@a") => ([:c], [], [], []) - ]) - @test test_expression_explorer( - expr=:(@parent @child 10), - macrocalls=[Symbol("@parent"), Symbol("@child")], - ) - @test test_expression_explorer( - expr=:(@parent begin @child 1 + @grandchild 10 end), - macrocalls=[Symbol("@parent"), Symbol("@child"), Symbol("@grandchild")], - ) - @test testee(macroexpand(Main, :(@noinline f(x) = x)), [], [], [], [ - Symbol("f") => ([], [], [], []) - ]) - end - @testset "Macros and heuristics" begin - @test test_expression_explorer( - expr=:(@macro import Pkg), - macrocalls=[Symbol("@macro")], - definitions=[:Pkg], - ) - @test test_expression_explorer( - expr=:(@macro Pkg.activate("..")), - macrocalls=[Symbol("@macro")], - references=[:Pkg], - funccalls=[[:Pkg, :activate]], - ) - @test test_expression_explorer( - expr=:(@macro Pkg.add("Pluto.jl")), - macrocalls=[Symbol("@macro")], - references=[:Pkg], - funccalls=[[:Pkg, :add]], - ) - @test test_expression_explorer( - expr=:(@macro include("Firebasey.jl")), - macrocalls=[Symbol("@macro")], - funccalls=[[:include]], - ) - end - @testset "Module imports" begin - @test test_expression_explorer( - expr=quote - module X - import ..imported_from_outside - end - end, - references=[:imported_from_outside], - definitions=[:X], - ) - @test test_expression_explorer( - expr=quote - module X - import ..imported_from_outside - import Y - import ...where_would_this_even_come_from - import .not_defined_but_sure - end - end, - references=[:imported_from_outside], - definitions=[:X], - ) - # More advanced, might not be possible easily - @test test_expression_explorer( - expr=quote - module X - module Y - import ...imported_from_outside - end - end - end, - references=[:imported_from_outside], - definitions=[:X] - ) + + +const ObjectID = typeof(objectid("hello computer")) + +function Base.show(io::IO, s::SymbolsState) + print(io, "SymbolsState([") + join(io, s.references, ", ") + print(io, "], [") + join(io, s.assignments, ", ") + print(io, "], [") + join(io, s.funccalls, ", ") + print(io, "], [") + if isempty(s.funcdefs) + print(io, "]") + else + println(io) + for (k, v) in s.funcdefs + print(io, " ", k, ": ", v) + println(io) + end + print(io, "]") end - @testset "String interpolation & expressions" begin - @test testee(:("a $b"), [:b], [], [], []) - @test testee(:("a $(b = c)"), [:c], [:b], [], []) - # @test_broken testee(:(`a $b`), [:b], [], [], []) - # @test_broken testee(:(`a $(b = c)`), [:c], [:b], [], []) - @test testee(:(ex = :(yayo)), [], [:ex], [], []) - @test testee(:(ex = :(yayo + $r)), [:r], [:ex], [], []) - @test test_expression_explorer( - expr=:(quote $(x) end), - references=[:x], - ) - @test test_expression_explorer( - expr=:(quote z = a + $(x) + b() end), - references=[:x], - ) - @test test_expression_explorer( - expr=:(:($(x))), - references=[:x], - ) - @test test_expression_explorer( - expr=:(:(z = a + $(x) + b())), - references=[:x], - ) + if !isempty(s.macrocalls) + print(io, "], [") + print(io, s.macrocalls) + print(io, "])") + else + print(io, ")") end - @testset "Extracting `using` and `import`" begin - expr = quote - using A - import B - if x - using .C: r - import ..D.E: f, g - else - import H.I, J, K.L - end - - quote - using Nonono - end +end + +"Calls `ExpressionExplorer.compute_symbolreferences` on the given `expr` and test the found SymbolsState against a given one, with convient syntax. + +# Example + +```jldoctest +julia> @test testee(:( + begin + a = b + 1 + f(x) = x / z + end), + [:b, :+], # 1st: expected references + [:a, :f], # 2nd: expected definitions + [:+], # 3rd: expected function calls + [ + :f => ([:z, :/], [], [:/], []) + ]) # 4th: expected function definitions, with inner symstate using the same syntax +true +``` +" +function testee(expr::Any, expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = []; verbose::Bool=true, transformer::Function=identify) + expected = easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls) + + expr_transformed = transformer(expr) + + original_hash = expr_hash(expr_transformed) + result = ExpressionExplorer.compute_symbolreferences(expr_transformed) + # should not throw: + ReactiveNode(result) + + new_hash = expr_hash(expr_transformed) + if original_hash != new_hash + error("\n== The expression explorer modified the expression. Don't do that! ==\n") + end + + # Anonymous function are given a random name, which looks like anon67387237861123 + # To make testing easier, we rename all such functions to anon + new_name(fn::FunctionName) = FunctionName(map(new_name, fn.parts)...) + new_name(sym::Symbol) = startswith(string(sym), "anon") ? :anon : sym + + result.assignments = Set(new_name.(result.assignments)) + result.funcdefs = let + newfuncdefs = Dict{FunctionNameSignaturePair,SymbolsState}() + for (k, v) in result.funcdefs + union!(newfuncdefs, Dict(FunctionNameSignaturePair(new_name(k.name), hash("hello")) => v)) end - result = ExpressionExplorer.compute_usings_imports(expr) - @test result.usings == Set{Expr}([ - :(using A), - :(using .C: r), - ]) - @test result.imports == Set{Expr}([ - :(import B), - :(import ..D.E: f, g), - :(import H.I, J, K.L), - ]) - - @test ExpressionExplorer.external_package_names(result) == Set{Symbol}([ - :A, :B, :H, :J, :K - ]) - - @test ExpressionExplorer.external_package_names(:(using Plots, Something.Else, .LocalModule)) == Set([:Plots, :Something]) - @test ExpressionExplorer.external_package_names(:(import Plots.A: b, c)) == Set([:Plots]) - - if VERSION >= v"1.6.0" - @test ExpressionExplorer.external_package_names(Meta.parse("import Foo as Bar, Baz.Naz as Jazz")) == Set([:Foo, :Baz]) + newfuncdefs + end + + if verbose && expected != result + println() + println("FAILED TEST") + println(expr) + println() + dump(expr, maxdepth=20) + println() + dump(expr_transformed, maxdepth=20) + println() + @show expected + resulted = result + @show resulted + println() + end + return expected == result +end + + + + +expr_hash(e::Expr) = objectid(e.head) + mapreduce(p -> objectid((p[1], expr_hash(p[2]))), +, enumerate(e.args); init=zero(ObjectID)) +expr_hash(x) = objectid(x) + + + + + +function easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = []) + array_to_set(array) = map(array) do k + new_k = FunctionName(k) + return new_k + end |> Set + new_expected_funccalls = array_to_set(expected_funccalls) + + new_expected_funcdefs = map(expected_funcdefs) do (k, v) + new_k = FunctionName(k) + new_v = v isa SymbolsState ? v : easy_symstate(v...) + return FunctionNameSignaturePair(new_k, hash("hello")) => new_v + end |> Dict + + new_expected_macrocalls = array_to_set(expected_macrocalls) + + SymbolsState(Set(expected_references), Set(expected_definitions), new_expected_funccalls, new_expected_funcdefs, new_expected_macrocalls) +end + + + + + +t(args...; kwargs...) = testee(args...; transformer=Pluto.ExpressionExplorerExtras.pretransform_pluto, kwargs...) + + +""" +Like `t` but actually a convenient syntax +""" +function test_expression_explorer(; expr, references=[], definitions=[], funccalls=[], funcdefs=[], macrocalls=[], kwargs...) + t(expr, references, definitions, funccalls, funcdefs, macrocalls; kwargs...) +end + +@testset "Macros w/ Pluto 1" begin + # Macros tests are not just in ExpressionExplorer now + + @test t(:(@time a = 2), [], [], [], [], [Symbol("@time")]) + @test t(:(@f(x; y=z)), [], [], [], [], [Symbol("@f")]) + @test t(:(@f(x, y = z)), [], [], [], [], [Symbol("@f")]) # https://github.com/fonsp/Pluto.jl/issues/252 + @test t(:(Base.@time a = 2), [], [], [], [], [[:Base, Symbol("@time")]]) + # @test_nowarn t(:(@enum a b = d c), [:d], [:a, :b, :c], [Symbol("@enum")], []) + # @enum is tested in test/React.jl instead + @test t(:(@gensym a b c), [], [:a, :b, :c], [:gensym], [], [Symbol("@gensym")]) + @test t(:(Base.@gensym a b c), [], [:a, :b, :c], [:gensym], [], [[:Base, Symbol("@gensym")]]) + @test t(:(Base.@kwdef struct A; x = 1; y::Int = two; z end), [], [], [], [], [[:Base, Symbol("@kwdef")]]) + @test t(quote "asdf" f(x) = x end, [], [], [], [], [Symbol("@doc")]) + + # @test t(:(@bind a b), [], [], [], [], [Symbol("@bind")]) + # @test t(:(PlutoRunner.@bind a b), [], [], [], [], [[:PlutoRunner, Symbol("@bind")]]) + # @test_broken t(:(Main.PlutoRunner.@bind a b), [:b], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :create_bond], [:PlutoRunner, Symbol("@bind")]], [], verbose=false) + # @test t(:(let @bind a b end), [], [], [], [], [Symbol("@bind")]) + + @test t(:(`hey $(a = 1) $(b)`), [:b], [], [:cmd_gen], [], [Symbol("@cmd")]) + # @test t(:(md"hey $(@bind a b) $(a)"), [:a], [], [[:getindex]], [], [Symbol("@md_str"), Symbol("@bind")]) + # @test t(:(md"hey $(a) $(@bind a b)"), [:a], [], [[:getindex]], [], [Symbol("@md_str"), Symbol("@bind")]) + + @test t(:(@asdf a = x1 b = x2 c = x3), [], [], [], [], [Symbol("@asdf")]) # https://github.com/fonsp/Pluto.jl/issues/670 + + @test t(:(@aa @bb xxx), [], [], [], [], [Symbol("@aa"), Symbol("@bb")]) + @test t(:(@aa @bb(xxx) @cc(yyy)), [], [], [], [], [Symbol("@aa"), Symbol("@bb"), Symbol("@cc")]) + + @test t(:(Pkg.activate()), [:Pkg], [], [[:Pkg,:activate]], [], []) + @test t(:(@aa(Pkg.activate())), [:Pkg], [], [[:Pkg,:activate]], [], [Symbol("@aa")]) + @test t(:(@aa @bb(Pkg.activate())), [:Pkg], [], [[:Pkg,:activate]], [], [Symbol("@aa"), Symbol("@bb")]) + @test t(:(@aa @assert @bb(Pkg.activate())), [:Pkg], [], [[:Pkg,:activate], [:throw], [:AssertionError]], [], [Symbol("@aa"), Symbol("@assert"), Symbol("@bb")]) + @test t(:(@aa @bb(Xxx.xxxxxxxx())), [], [], [], [], [Symbol("@aa"), Symbol("@bb")]) + + @test t(:(include()), [], [], [[:include]], [], []) + @test t(:(:(include())), [], [], [], [], []) + @test t(:(:($(include()))), [], [], [[:include]], [], []) + @test t(:(@xx include()), [], [], [[:include]], [], [Symbol("@xx")]) + @test t(quote + module A + include() + Pkg.activate() + @xoxo asdf end - end + end, [], [:A], [], [], []) + + + @test t(:(@aa @bb(using Zozo)), [], [:Zozo], [], [], [Symbol("@aa"), Symbol("@bb")]) + @test t(:(@aa(using Zozo)), [], [:Zozo], [], [], [Symbol("@aa")]) + @test t(:(using Zozo), [], [:Zozo], [], [], []) + + e = :(using Zozo) + @test ExpressionExplorer.compute_usings_imports( + e + ).usings == [e] + @test ExpressionExplorer.compute_usings_imports( + :(@aa @bb($e)) + ).usings == [e] + + + @test t(:(@einsum a[i,j] := x[i]*y[j]), [], [], [], [], [Symbol("@einsum")]) + @test t(:(@tullio a := f(x)[i+2j, k[j]] init=z), [], [], [], [], [Symbol("@tullio")]) + @test t(:(Pack.@asdf a[1,k[j]] := log(x[i]/y[j])), [], [], [], [], [[:Pack, Symbol("@asdf")]]) + + + @test t(:(html"a $(b = c)"), [], [], [], [], [Symbol("@html_str")]) + @test t(:(md"a $(b = c) $(b)"), [:c], [:b], [:getindex], [], [Symbol("@md_str")]) + @test t(:(md"\* $r"), [:r], [], [:getindex], [], [Symbol("@md_str")]) + @test t(:(md"a \$(b = c)"), [], [], [:getindex], [], [Symbol("@md_str")]) + @test t(:(macro a() end), [], [], [], [ + Symbol("@a") => ([], [], [], []) + ]) + @test t(:(macro a(b::Int); b end), [], [], [], [ + Symbol("@a") => ([:Int], [], [], []) + ]) + @test t(:(macro a(b::Int=c) end), [], [], [], [ + Symbol("@a") => ([:Int, :c], [], [], []) + ]) + @test t(:(macro a(); b = c; return b end), [], [], [], [ + Symbol("@a") => ([:c], [], [], []) + ]) + @test test_expression_explorer(; + expr=:(@parent @child 10), + macrocalls=[Symbol("@parent"), Symbol("@child")], + ) + @test test_expression_explorer(; + expr=:(@parent begin @child 1 + @grandchild 10 end), + macrocalls=[Symbol("@parent"), Symbol("@child"), Symbol("@grandchild")], + ) + @test t(macroexpand(Main, :(@noinline f(x) = x)), [], [], [], [ + Symbol("f") => ([], [], [], []) + ]) end + + +@testset "Macros w/ Pluto 2" begin + + @test t(:(@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [Symbol("@bind")]) + @test t(:(PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [[:PlutoRunner, Symbol("@bind")]]) + @test_broken t(:(Main.PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :create_bond], [:PlutoRunner, Symbol("@bind")]], [], verbose=false) + @test t(:(let @bind a b end), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get]], [], [Symbol("@bind")]) + + @test t(:(`hey $(a = 1) $(b)`), [:b], [], [:cmd_gen], [], [Symbol("@cmd")]) + @test t(:(md"hey $(@bind a b) $(a)"), [:b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get], :getindex], [], [Symbol("@md_str"), Symbol("@bind")]) + @test t(:(md"hey $(a) $(@bind a b)"), [:a, :b, :PlutoRunner, :Base, :Core], [:a], [[:PlutoRunner, :create_bond], [:Core, :applicable], [:Base, :get], :getindex], [], [Symbol("@md_str"), Symbol("@bind")]) + + +end \ No newline at end of file diff --git a/test/Logging.jl b/test/Logging.jl new file mode 100644 index 0000000000..b744763e67 --- /dev/null +++ b/test/Logging.jl @@ -0,0 +1,170 @@ +using Test +import UUIDs +import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, ClientSession, update_run! +using Pluto.WorkspaceManager: poll + +@testset "Logging" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = true + + notebook = Notebook(Cell.([ + "println(123)", + "println(stdout, 123)", + "println(stderr, 123)", + "display(123)", + "show(123)", + "popdisplay()", + "println(123)", + "pushdisplay(TextDisplay(devnull))", + "print(12); print(3)", # 9 + + """ + for i in 1:10 + @info "logging" i maxlog=2 + end + """, # 10 + + """ + for i in 1:10 + @info "logging" i maxlog=2 + @info "logging more" maxlog = 4 + @info "even more logging" + end + """, # 11 + + "t1 = @async sleep(3)", # 12 + "!istaskfailed(t1) && !istaskdone(t1)", # 13 + "t2 = @async run(`sleep 3`)", # 14 + "!istaskfailed(t2) && !istaskdone(t2)", # 15 + + """ + macro hello() + a = rand() + @info a + nothing + end + """, # 16 + + "@hello", # 17 + + "123", # 18 + + + "struct StructWithCustomShowThatLogs end", # 19 + """ # 20 + function Base.show(io::IO, ::StructWithCustomShowThatLogs) + println("stdio log") + @info "showing StructWithCustomShowThatLogs" + show(io, "hello") + end + """, + "StructWithCustomShowThatLogs()", # 21 + ])) + + @testset "Stdout" begin + + idx_123 = [1,2,3,4,5,7,9] + + update_run!(🍭, notebook, notebook.cells[1:9]) + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror + @test notebook.cells[5] |> noerror + @test notebook.cells[6] |> noerror + @test notebook.cells[7] |> noerror + @test notebook.cells[8] |> noerror + @test notebook.cells[9] |> noerror + + @test poll(5, 1/60) do + all(notebook.cells[idx_123]) do c + length(c.logs) == 1 + end + end + + @testset "123 - $(i)" for i in idx_123 + log = only(notebook.cells[i].logs) + @test log["level"] == "LogLevel(-555)" + @test strip(log["msg"][1]) == "123" + @test log["msg"][2] == MIME"text/plain"() + end + + update_run!(🍭, notebook, notebook.cells[12:15]) + update_run!(🍭, notebook, notebook.cells[[12,14]]) + @test notebook.cells[13].output.body == "true" + Sys.iswindows() || @test notebook.cells[15].output.body == "true" + + update_run!(🍭, notebook, notebook.cells[16:18]) + + @test isempty(notebook.cells[16].logs) + @test length(notebook.cells[17].logs) == 1 + @test isempty(notebook.cells[18].logs) + + update_run!(🍭, notebook, notebook.cells[18]) + update_run!(🍭, notebook, notebook.cells[17]) + + @test isempty(notebook.cells[16].logs) + @test length(notebook.cells[17].logs) == 1 + @test isempty(notebook.cells[18].logs) + + update_run!(🍭, notebook, notebook.cells[16]) + + @test isempty(notebook.cells[16].logs) + @test length(notebook.cells[17].logs) == 1 + @test isempty(notebook.cells[18].logs) + + update_run!(🍭, notebook, notebook.cells[19:21]) + + @test isempty(notebook.cells[19].logs) + @test isempty(notebook.cells[20].logs) + + @test poll(5, 1/60) do + length(notebook.cells[21].logs) == 2 + end + end + + @testset "Logging respects maxlog" begin + @testset "Single log" begin + + update_run!(🍭, notebook, notebook.cells[10]) + @test notebook.cells[10] |> noerror + + @test poll(5, 1/60) do + length(notebook.cells[10].logs) == 2 + end + + # Check that maxlog doesn't occur in the message + @test all(notebook.cells[10].logs) do log + all(log["kwargs"]) do kwarg + kwarg[1] != "maxlog" + end + end + + end + + @testset "Multiple log" begin + update_run!(🍭, notebook, notebook.cells[11]) + @test notebook.cells[11] |> noerror + + # Wait until all 16 logs are in + @test poll(5, 1/60) do + length(notebook.cells[11].logs) == 16 + end + + # Get the ids of the three logs and their counts. We are + # assuming that the logs are ordered same as in the loop. + ids = unique(getindex.(notebook.cells[11].logs, "id")) + counts = [count(log -> log["id"] == id, notebook.cells[11].logs) for id in ids] + @test counts == [2, 4, 10] + + # Check that maxlog doesn't occur in the messages + @test all(notebook.cells[11].logs) do log + all(log["kwargs"]) do kwarg + kwarg[1] != "maxlog" + end + end + end + end + + WorkspaceManager.unmake_workspace((🍭, notebook)) +end diff --git a/test/MacroAnalysis.jl b/test/MacroAnalysis.jl index 98757f5260..4c54571674 100644 --- a/test/MacroAnalysis.jl +++ b/test/MacroAnalysis.jl @@ -1,14 +1,12 @@ using Test import UUIDs import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, ClientSession, update_run! +import Memoize: @memoize @testset "Macro analysis" begin 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient - @testset "Base macro call" begin notebook = Notebook([ Cell("@enum Fruit 🍎 🍐"), @@ -62,12 +60,12 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie update_run!(🍭, notebook, notebook.cells) - setcode(cell(2), """macro my_identity(expr) + setcode!(cell(2), """macro my_identity(expr) esc(expr) end""") update_run!(🍭, notebook, cell(2)) - setcode(cell(3), "f(x) = x") + setcode!(cell(3), "f(x) = x") update_run!(🍭, notebook, cell(3)) @test cell(1) |> noerror @@ -200,15 +198,15 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test all(noerror, notebook.cells) - setcode(cell(1), raw""" + setcode!(cell(1), raw""" macro test(sym) esc(:($sym = true)) end """) update_run!(🍭, notebook, cell(1)) - setcode(cell(2), "x") - setcode(cell(3), "@test x") + setcode!(cell(2), "x") + setcode!(cell(3), "@test x") update_run!(🍭, notebook, notebook.cells[2:3]) @test cell(2).output.body == "true" @@ -220,18 +218,18 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie cell(idx) = notebook.cells[idx] update_run!(🍭, notebook, notebook.cells) - setcode(cell(1), "x") + setcode!(cell(1), "x") update_run!(🍭, notebook, cell(1)) @test cell(1).errored == true - setcode(cell(2), "@bar x") + setcode!(cell(2), "@bar x") update_run!(🍭, notebook, cell(2)) @test cell(1).errored == true @test cell(2).errored == true - setcode(cell(3), raw"""macro bar(sym) + setcode!(cell(3), raw"""macro bar(sym) esc(:($sym = "yay")) end""") update_run!(🍭, notebook, cell(3)) @@ -247,13 +245,13 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie cell(idx) = notebook.cells[idx] update_run!(🍭, notebook, notebook.cells) - setcode(cell(1), "x") + setcode!(cell(1), "x") update_run!(🍭, notebook, cell(1)) @test cell(1).errored == true - setcode(cell(3), "@a()") - setcode(cell(2), raw"""macro a() + setcode!(cell(3), "@a()") + setcode!(cell(2), raw"""macro a() quote macro b(sym) esc(:($sym = 42)) @@ -266,7 +264,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(2) |> noerror @test cell(3) |> noerror - setcode(cell(4), "@b x") + setcode!(cell(4), "@b x") update_run!(🍭, notebook, cell(4)) @test cell(1) |> noerror @@ -276,6 +274,27 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(1).output.body == "42" end + @testset "Removing macros undefvar errors dependent cells" begin + notebook = Notebook(Cell.([ + """macro m() + :(1 + 1) + end""", + "@m()", + ])) + + update_run!(🍭, notebook, notebook.cells) + + @test all(noerror, notebook.cells) + + setcode!(notebook.cells[begin], "") # remove definition of m + update_run!(🍭, notebook, notebook.cells[begin]) + + @test notebook.cells[begin] |> noerror + @test notebook.cells[end].errored + + @test expecterror(UndefVarError(Symbol("@m")), notebook.cells[end]; strict=VERSION >= v"1.7") + end + @testset "Redefines macro with new SymbolsState" begin notebook = Notebook(Cell.([ "@b x", @@ -291,7 +310,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(3).output.body == "42" @test cell(4).errored == true - setcode(cell(2), """macro b(_) + setcode!(cell(2), """macro b(_) esc(:(y = 42)) end""") update_run!(🍭, notebook, cell(2)) @@ -312,7 +331,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(3).output.body == "42" @test cell(4).errored == true - setcode(cell(2), """macro b(_) + setcode!(cell(2), """macro b(_) esc(:(y = 42)) end""") update_run!(🍭, notebook, [cell(1), cell(2)]) @@ -348,7 +367,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(4) |> noerror @test cell(5).errored == true - setcode(cell(2), "z = 39") + setcode!(cell(2), "z = 39") # running only 2, running all cells here works however update_run!(🍭, notebook, cell(2)) @@ -420,7 +439,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(5).errored == true @test cell(6) |> noerror - setcode(cell(6), "updater = 2") + setcode!(cell(6), "updater = 2") update_run!(🍭, notebook, cell(6)) # the output of cell 4 has not changed since the underlying computer @@ -444,13 +463,13 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(3).errored == true - setcode(cell(3), "huh(z)") + setcode!(cell(3), "huh(z)") update_run!(🍭, notebook, cell(3)) @test cell(3) |> noerror @test cell(3).output.body == "101010" - setcode(cell(4), "z = 1234") + setcode!(cell(4), "z = 1234") update_run!(🍭, notebook, cell(4)) @test cell(3) |> noerror @@ -518,7 +537,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie output_1 = cell(1).output.body @test sleep_time <= runtime - setcode(cell(3), "updater = :fast") + setcode!(cell(3), "updater = :fast") update_run!(🍭, notebook, cell(3)) @test noerror(cell(1)) @@ -535,7 +554,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test output_1 != cell(1).output.body output_3 = cell(1).output.body - setcode(cell(1), "@b()") # changing code generates a new 💻 + setcode!(cell(1), "@b()") # changing code generates a new 💻 update_run!(🍭, notebook, cell(1)) @test cell(1) |> noerror @@ -564,7 +583,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie update_run!(🍭, notebook, cell(5)) - @test occursin("UndefVarError: x", cell(1).output.body[:msg]) + @test expecterror(UndefVarError(:x), cell(1)) update_run!(🍭, notebook, cell(3)) update_run!(🍭, notebook, cell(2)) @@ -586,7 +605,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie update_run!(🍭, notebook, cell(2)) @test cell(2).errored == true - @test occursinerror("UndefVarError: @dateformat_str", cell(2)) == true + @test expecterror(UndefVarError(Symbol("@dateformat_str")), cell(2); strict=VERSION >= v"1.7") update_run!(🍭, notebook, notebook.cells) @@ -605,7 +624,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @testset "Package macro 2" begin 🍭.options.evaluation.workspace_use_distributed = true - + notebook = Notebook([ Cell("z = x^2 + y"), Cell("@variables x y"), @@ -613,7 +632,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie begin import Pkg Pkg.activate(mktempdir()) - Pkg.add(Pkg.PackageSpec(name="Symbolics", version="1")) + Pkg.add(Pkg.PackageSpec(name="Symbolics", version="5.5.1")) import Symbolics: @variables end """), @@ -629,7 +648,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(1) |> noerror @test cell(2) |> noerror - @test cell(2) |> noerror + @test cell(3) |> noerror update_run!(🍭, notebook, notebook.cells) @@ -642,13 +661,13 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test cell(1) |> noerror @test cell(2) |> noerror - setcode(cell(2), "@variables 🐰 y") + setcode!(cell(2), "@variables 🐰 y") update_run!(🍭, notebook, cell(2)) @test cell(1).errored @test cell(2) |> noerror - setcode(cell(1), "z = 🐰^2 + y") + setcode!(cell(1), "z = 🐰^2 + y") update_run!(🍭, notebook, cell(1)) @test cell(1) |> noerror @@ -679,7 +698,7 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie module_from_cell2 = cell(2).output.body[:elements][1][2][1] module_from_cell3 = cell(3).output.body - @test_broken module_from_cell2 == module_from_cell3 + @test module_from_cell2 == module_from_cell3 end @testset "Definitions" begin @@ -701,13 +720,27 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test :b ∈ notebook.topology.nodes[cell(3)].definitions @test [:c, Symbol("@my_assign")] ⊆ notebook.topology.nodes[cell(3)].references - setcode(notebook.cells[2], "c = :world") + setcode!(notebook.cells[2], "c = :world") update_run!(🍭, notebook, cell(2)) @test ":world" == cell(3).output.body @test ":world" == cell(4).output.body end + @testset "Is just text macros" begin + notebook = Notebook(Cell.([ + """ + md"# Hello world!" + """, + """ + "no julia value here" + """, + ])) + update_run!(🍭, notebook, notebook.cells) + + @test isempty(notebook.topology.unresolved_cells) + end + @testset "Macros using import" begin notebook = Notebook(Cell.([ """ @@ -774,4 +807,120 @@ import Pluto: PlutoRunner, Notebook, WorkspaceManager, Cell, ServerSession, Clie @test all(cell.([1,2]) .|> noerror) @test cell(2).output.body == ":this_should_be_returned" end + + @testset "Doc strings" begin + notebook = Notebook(Cell.([ + "x = 1", + raw""" + "::Bool" + f(::Bool) = x + """, + raw""" + "::Int" + f(::Int) = 1 + """, + ])) + + trigger, bool, int = notebook.cells + + workspace = WorkspaceManager.get_workspace((🍭, notebook)) + workspace_module = getproperty(Main, workspace.module_name) + + # Propose suggestions when no binding is found + doc_content, status = PlutoRunner.doc_fetcher("filer", workspace_module) + @test status == :👍 + @test occursin("Similar results:", doc_content) + @test occursin("filter", doc_content) + + update_run!(🍭, notebook, notebook.cells) + @test all(noerror, notebook.cells) + @test occursin("::Bool", bool.output.body) + @test !occursin("::Int", bool.output.body) + @test occursin("::Bool", int.output.body) + @test occursin("::Int", int.output.body) + + setcode!(int, raw""" + "::Int new docstring" + f(::Int) = 1 + """) + update_run!(🍭, notebook, int) + + @test occursin("::Bool", int.output.body) + @test occursin("::Int new docstring", int.output.body) + + update_run!(🍭, notebook, trigger) + + @test occursin("::Bool", bool.output.body) + @test occursin("::Int new docstring", bool.output.body) + @test length(eachmatch(r"Bool", bool.output.body) |> collect) == 1 + @test length(eachmatch(r"Int", bool.output.body) |> collect) == 1 + + update_run!(🍭, notebook, trigger) + + @test length(eachmatch(r"Bool", bool.output.body) |> collect) == 1 + + setcode!(int, "") + update_run!(🍭, notebook, [bool, int]) + @test !occursin("::Int", bool.output.body) + + setcode!(bool, """ + "An empty conjugate" + Base.conj() = x + """) + + update_run!(🍭, notebook, bool) + @test noerror(bool) + @test noerror(trigger) + @test occursin("An empty conjugate", bool.output.body) + @test occursin("complex conjugate", bool.output.body) + + setcode!(bool, "Docs.doc(conj)") + update_run!(🍭, notebook, bool) + @test !occursin("An empty conjugate", bool.output.body) + @test occursin("complex conjugate", bool.output.body) + end + + @testset "Delete methods from macros" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = false + + notebook = Notebook([ + Cell("using Memoize"), + Cell(""" + macro user_defined() + quote + struct ASD end + custom_func(::ASD) = "ASD" + end |> esc + end + """), + Cell("@user_defined"), + Cell("methods(custom_func)"), + Cell(""" + @memoize function memoized_func(a) + println("Running") + 2a + end + """), + Cell("methods(memoized_func)"), + ]) + cell(idx) = notebook.cells[idx] + + update_run!(🍭, notebook, notebook.cells) + + @test :custom_func ∈ notebook.topology.nodes[cell(3)].funcdefs_without_signatures + @test cell(4) |> noerror + @test :memoized_func ∈ notebook.topology.nodes[cell(5)].funcdefs_without_signatures + @test cell(6) |> noerror + + cell(3).code = "#=$(cell(3).code)=#" + cell(5).code = "#=$(cell(5).code)=#" + + update_run!(🍭, notebook, notebook.cells) + + @test :custom_func ∉ notebook.topology.nodes[cell(3)].funcdefs_without_signatures + @test expecterror(UndefVarError(:custom_func), cell(4)) + @test :memoized_func ∉ notebook.topology.nodes[cell(5)].funcdefs_without_signatures + @test expecterror(UndefVarError(:memoized_func), cell(6)) + end end diff --git a/test/MethodSignatures.jl b/test/MethodSignatures.jl index e0c1619da7..8e57cba45b 100644 --- a/test/MethodSignatures.jl +++ b/test/MethodSignatures.jl @@ -1,6 +1,6 @@ using Test -import Pluto.ExpressionExplorer: SymbolsState, compute_symbolreferences, FunctionNameSignaturePair +import Pluto.ExpressionExplorer: compute_symbolreferences @testset "Method signatures" begin diff --git a/test/MoreAnalysis.jl b/test/MoreAnalysis.jl index 037414888e..a08516f299 100644 --- a/test/MoreAnalysis.jl +++ b/test/MoreAnalysis.jl @@ -1,4 +1,4 @@ -import Pluto: Pluto, Cell +import Pluto: Pluto, Cell, ExpressionExplorerExtras import Pluto.MoreAnalysis using Test @@ -74,4 +74,44 @@ using Test @test transform(connections) == transform(wanted_connections) end -end \ No newline at end of file + + + + @testset "can_be_function_wrapped" begin + + c = ExpressionExplorerExtras.can_be_function_wrapped + + + @test c(quote + a = b + C + if d + for i = 1:10 + while Y + end + end + end + end) + + + @test c(quote + map(1:10) do i + i + 1 + end + end) + + + @test !c(quote + function x(x) + X + end + end) + + @test !c(quote + if false + using Asdf + end + end) + + + end +end diff --git a/test/Notebook.jl b/test/Notebook.jl index ab6336dc7d..8d4d83e531 100644 --- a/test/Notebook.jl +++ b/test/Notebook.jl @@ -1,5 +1,6 @@ using Test -import Pluto: Notebook, ServerSession, ClientSession, Cell, load_notebook, load_notebook_nobackup, save_notebook, WorkspaceManager, cutename, numbered_until_new, readwrite, without_pluto_file_extension +import Pluto: Notebook, ServerSession, ClientSession, Cell, load_notebook, load_notebook_nobackup, save_notebook, WorkspaceManager, cutename, numbered_until_new, readwrite, without_pluto_file_extension, update_run!, get_metadata_no_default, is_disabled, create_cell_metadata, update_skipped_cells_dependency! +import Pluto.WorkspaceManager import Random import Pkg import UUIDs: UUID @@ -29,6 +30,70 @@ function basic_notebook() ]) |> init_packages! end +function cell_metadata_notebook() + Notebook([ + Cell( + code="100*a + b", + metadata=Dict( + "a metadata tag" => Dict( + "boolean" => true, + "string" => "String", + "number" => 10000, + ), + "disabled" => true, + ) |> create_cell_metadata, + ), + ]) |> init_packages! +end + +function ingredients(path::String) + # this is from the Julia source code (evalfile in base/loading.jl) + # but with the modification that it returns the module instead of the last object + name = Symbol(basename(path)) + m = Module(name) + Core.eval(m, + Expr(:toplevel, + :(eval(x) = $(Expr(:core, :eval))($name, x)), + :(include(x) = $(Expr(:top, :include))($name, x)), + :(include(mapexpr::Function, x) = $(Expr(:top, :include))(mapexpr, $name, x)), + :(include($path)))) + m +end + +function skip_as_script_notebook() + Notebook([ + Cell( + code="skipped_var = 10", + metadata=Dict( + "skip_as_script" => true, + ) |> create_cell_metadata, + ), + Cell( + code="non_skipped_var = 15", + ), + Cell( + code="dependent_var = skipped_var + 1", + ), + ]) |> init_packages! +end + +function notebook_metadata_notebook() + nb = Notebook([ + Cell(code="n * (n + 1) / 2"), + ]) |> init_packages! + nb.metadata = Dict( + "boolean" => true, + "string" => "String", + "number" => 10000, + "ozymandias" => Dict( + "l1" => "And on the pedestal, these words appear:", + "l2" => "My name is Ozymandias, King of Kings;", + "l3" => "Look on my Works, ye Mighty, and despair!", + ), + ) + nb +end + function shuffled_notebook() Notebook([ Cell("z = y"), @@ -67,7 +132,7 @@ end function init_packages!(nb::Notebook) nb.topology = Pluto.updated_topology(nb.topology, nb, nb.cells) - Pluto.sync_nbpkg_core(nb) + Pluto.sync_nbpkg_core(nb, nb.topology, nb.topology) return nb end @@ -125,11 +190,6 @@ end 🍭 = ServerSession() for (name, nb) in nbs nb.path = tempname() * "é🧡💛.jl" - - client = ClientSession(Symbol("client", rand(UInt16)), nothing) - client.connected_notebook = nb - - 🍭.connected_clients[client.id] = client end @testset "I/O basic" begin @@ -137,13 +197,168 @@ end save_notebook(nb) # @info "File" name Text(read(nb.path,String)) result = load_notebook_nobackup(nb.path) - @test notebook_inputs_equal(nb, result) + @test_notebook_inputs_equal(nb, result) end end + @testset "Cell Metadata" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = false + + @testset "Disabling & Metadata" begin + nb = cell_metadata_notebook() + update_run!(🍭, nb, nb.cells) + cell = first(values(nb.cells_dict)) + @test get_metadata_no_default(cell) == Dict( + "a metadata tag" => Dict( + "boolean" => true, + "string" => "String", + "number" => 10000, + ), + "disabled" => true, # enhanced metadata because cell is disabled + ) + + save_notebook(nb) + result = load_notebook_nobackup(nb.path) + @test_notebook_inputs_equal(nb, result) + cell = first(nb.cells) + @test is_disabled(cell) + @test get_metadata_no_default(cell) == Dict( + "a metadata tag" => Dict( + "boolean" => true, + "string" => "String", + "number" => 10000, + ), + "disabled" => true, + ) + + WorkspaceManager.unmake_workspace((🍭, nb); verbose=false) + end + end + + @testset "Notebook Metadata" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = false + + nb = notebook_metadata_notebook() + update_run!(🍭, nb, nb.cells) + + @test nb.metadata == Dict( + "boolean" => true, + "string" => "String", + "number" => 10000, + "ozymandias" => Dict( + "l1" => "And on the pedestal, these words appear:", + "l2" => "My name is Ozymandias, King of Kings;", + "l3" => "Look on my Works, ye Mighty, and despair!", + ), + ) + + save_notebook(nb) + nb_loaded = load_notebook_nobackup(nb.path) + @test nb.metadata == nb_loaded.metadata + + WorkspaceManager.unmake_workspace((🍭, nb); verbose=false) + end + + @testset "Skip as script" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = false + + nb = skip_as_script_notebook() + update_run!(🍭, nb, nb.cells) + + save_notebook(nb) + + m = ingredients(nb.path) + @test !isdefined(m, :skipped_var) + @test !isdefined(m, :dependent_var) + @test m.non_skipped_var == 15 + + # Test that `load_notebook` doesn't break commented out cells + load_notebook(nb.path) + m = ingredients(nb.path) + @test !isdefined(m, :skipped_var) + @test !isdefined(m, :dependent_var) + @test m.non_skipped_var == 15 + + nb.cells[1].metadata["skip_as_script"] = false + update_skipped_cells_dependency!(nb) + save_notebook(nb) + + m = ingredients(nb.path) + @test m.skipped_var == 10 + @test m.non_skipped_var == 15 + @test m.dependent_var == 11 + + + WorkspaceManager.unmake_workspace((🍭, nb); verbose=false) + end + + @testset "More Metadata" begin + test_file_contents = """ + ### A Pluto.jl notebook ### + # v0.19.4 + + @hello from the future where we might put extra stuff here + + #> [hello] + #> world = [1, 2, 3] + #> [frontmatter] + #> title = "cool stuff" + + using Markdown + using SecretThings + + # asdfasdf + + # ╔═╡ a86be878-d616-11ec-05a3-c902726cee5f + # ╠═╡ disabled = true + # ╠═╡ fonsi = 123 + #=╠═╡ + 1 + 1 + ╠═╡ =# + + # ╔═╡ Cell order: + # ╠═a86be878-d616-11ec-05a3-c902726cee5f + + # ok thx byeeeee + + """ + + test_filename = tempname() + write(test_filename, test_file_contents) + nb = load_notebook_nobackup(test_filename) + @test nb.metadata == Dict( + "hello" => Dict( + "world" => [1,2,3], + ), + "frontmatter" => Dict( + "title" => "cool stuff", + ), + ) + + @test get_metadata_no_default(only(nb.cells)) == Dict( + "disabled" => true, + "fonsi" => 123, + ) + + @test Pluto.frontmatter(nb) == Dict( + "title" => "cool stuff", + ) + + Pluto.set_frontmatter!(nb, Dict("a" => "b")) + @test Pluto.frontmatter(nb) == Dict("a" => "b") + + Pluto.set_frontmatter!(nb, nothing) + @test Pluto.frontmatter(nb) == Dict() + Pluto.set_frontmatter!(nb, nothing) + @test Pluto.frontmatter(nb) == Dict() + end + @testset "I/O overloaded" begin @testset "$(name)" for (name, nb) in nbs - @test let + let tasks = [] for i in 1:16 push!(tasks, @async save_notebook(nb)) @@ -153,7 +368,7 @@ end end wait.(tasks) result = load_notebook_nobackup(nb.path) - notebook_inputs_equal(nb, result) + @test_notebook_inputs_equal(nb, result) end end end @@ -251,15 +466,15 @@ end @testset "$(name)" for (name, nb) in nbs file_contents = sprint(save_notebook, nb) - @test let + let result = sread(load_notebook_nobackup, file_contents, nb.path) - notebook_inputs_equal(nb, result) + @test_notebook_inputs_equal(nb, result) end - @test let + let file_contents_windowsed = replace(file_contents, "\n" => "\r\n") result_windowsed = sread(load_notebook_nobackup, file_contents_windowsed, nb.path) - notebook_inputs_equal(nb, result_windowsed) + @test_notebook_inputs_equal(nb, result_windowsed) end end end @@ -334,16 +549,29 @@ end end end - @testset "Import & export HTML" begin + @testset "Export HTML" begin nb = basic_notebook() - export_html = Pluto.generate_html(nb) + nb.metadata["frontmatter"] = Dict{String,Any}( + "title" => "My ["aaa", "bbb"], + "description" => "ccc", + ) + export_html = replace(Pluto.generate_html(nb), "'" => "\"") + + @test occursin("My<Title", export_html) + @test occursin("""""", export_html) + @test occursin("""""", export_html) + @test occursin("""""", export_html) + @test occursin("""""", export_html) + @test occursin("""""", export_html) embedded_jl = Pluto.embedded_notebookfile(export_html) jl_path = tempname() write(jl_path, embedded_jl) result = load_notebook_nobackup(jl_path) - @test notebook_inputs_equal(nb, result; check_paths_equality=false) + @test_notebook_inputs_equal(nb, result, false) filename = "howdy.jl" @@ -351,6 +579,15 @@ end export_html = Pluto.generate_html(nb; notebookfile_js=filename) @test occursin(filename, export_html) @test_throws ArgumentError Pluto.embedded_notebookfile(export_html) + + + export_html = Pluto.generate_index_html() + @test occursin("", export_html) + @test !occursin(" noerror @test notebook.cells[3].output.rootassignee === nothing update_run!(🍭, notebook, notebook.cells[4]) @test notebook.cells[4].output.body == "16" - @test notebook.cells[4].errored == false + @test notebook.cells[4] |> noerror @test notebook.cells[4].output.rootassignee === nothing - setcode(notebook.cells[1], "x = 912") + setcode!(notebook.cells[1], "x = 912") update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[4].output.body == "916" - setcode(notebook.cells[3], "f(x) = x") + setcode!(notebook.cells[3], "f(x) = x") update_run!(🍭, notebook, notebook.cells[3]) @test notebook.cells[4].output.body == "4" - setcode(notebook.cells[1], "x = 1") - setcode(notebook.cells[2], "y = 2") + setcode!(notebook.cells[1], "x = 1") + setcode!(notebook.cells[2], "y = 2") update_run!(🍭, notebook, notebook.cells[1:2]) update_run!(🍭, notebook, notebook.cells[5:6]) - @test notebook.cells[5].errored == false + @test notebook.cells[5] |> noerror @test notebook.cells[6].output.body == "3" - setcode(notebook.cells[2], "y = 1") + setcode!(notebook.cells[2], "y = 1") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[6].output.body == "2" - setcode(notebook.cells[1], "x = 2") + setcode!(notebook.cells[1], "x = 2") update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[6].output.body == "3" update_run!(🍭, notebook, notebook.cells[7:8]) - @test if parallel - notebook.cells[8].output.body != string(Distributed.myid()) + if workertype === :Distributed + @test notebook.cells[8].output.body ∉ ("1", string(Distributed.myid())) + elseif workertype === :Malt + @test notebook.cells[8].output.body == "1" + elseif workertype === :InProcess + @test notebook.cells[8].output.body == string(Distributed.myid()) else - notebook.cells[8].output.body == string(Distributed.myid()) + error() end - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @@ -95,7 +102,6 @@ import Distributed Cell("g(x) = 5"), Cell("g = 6"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1]) @@ -103,40 +109,40 @@ import Distributed @test occursinerror("Multiple", notebook.cells[1]) @test occursinerror("Multiple", notebook.cells[2]) - setcode(notebook.cells[1], "") + setcode!(notebook.cells[1], "") update_run!(🍭, notebook, notebook.cells[1]) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror # https://github.com/fonsp/Pluto.jl/issues/26 - setcode(notebook.cells[1], "x = 1") + setcode!(notebook.cells[1], "x = 1") update_run!(🍭, notebook, notebook.cells[1]) - setcode(notebook.cells[2], "x") + setcode!(notebook.cells[2], "x") update_run!(🍭, notebook, notebook.cells[2]) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror update_run!(🍭, notebook, notebook.cells[3]) update_run!(🍭, notebook, notebook.cells[4]) @test occursinerror("Multiple", notebook.cells[3]) @test occursinerror("Multiple", notebook.cells[4]) - setcode(notebook.cells[3], "") + setcode!(notebook.cells[3], "") update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror update_run!(🍭, notebook, notebook.cells[5]) update_run!(🍭, notebook, notebook.cells[6]) @test occursinerror("Multiple", notebook.cells[5]) @test occursinerror("Multiple", notebook.cells[6]) - setcode(notebook.cells[5], "") + setcode!(notebook.cells[5], "") update_run!(🍭, notebook, notebook.cells[5]) - @test notebook.cells[5].errored == false - @test notebook.cells[6].errored == false + @test notebook.cells[5] |> noerror + @test notebook.cells[6] |> noerror - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Mutliple assignments topology" begin @@ -148,27 +154,77 @@ import Distributed ]) notebook.topology = Pluto.updated_topology(notebook.topology, notebook, notebook.cells) - let topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells[[1]]) + let topo_order = Pluto.topological_order(notebook.topology, notebook.cells[[1]]) @test indexin(topo_order.runnable, notebook.cells) == [1,2] @test topo_order.errable |> keys == notebook.cells[[3,4]] |> Set end - let topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells[[1]], allow_multiple_defs=true) + let topo_order = Pluto.topological_order(notebook.topology, notebook.cells[[1]], allow_multiple_defs=true) @test indexin(topo_order.runnable, notebook.cells) == [1,3,4,2] # x first, y second and third, z last # this also tests whether multiple defs run in page order @test topo_order.errable == Dict() end end + @testset "Simple insert cell" begin + notebook = Notebook(Cell[]) + update_run!(🍭, notebook, notebook.cells) + + insert_cell!(notebook, Cell("a = 1")) + update_run!(🍭, notebook, notebook.cells[begin]) + + insert_cell!(notebook, Cell("b = 2")) + update_run!(🍭, notebook, notebook.cells[begin+1]) + + insert_cell!(notebook, Cell("c = 3")) + update_run!(🍭, notebook, notebook.cells[begin+2]) + + insert_cell!(notebook, Cell("a + b + c")) + update_run!(🍭, notebook, notebook.cells[begin+3]) + + @test notebook.cells[begin+3].output.body == "6" + + setcode!(notebook.cells[begin+1], "b = 10") + update_run!(🍭, notebook, notebook.cells[begin+1]) + + @test notebook.cells[begin+3].output.body == "14" + end + + @testset "Simple delete cell" begin + notebook = Notebook(Cell.([ + "x = 42", + "x", + ])) + update_run!(🍭, notebook, notebook.cells) + + @test all(noerror, notebook.cells) + + delete_cell!(notebook, notebook.cells[begin]) + @test length(notebook.cells) == 1 + + update_run!(🍭, notebook, Cell[]) + + @test expecterror(UndefVarError(:x), notebook.cells[begin]) + end + + @testset ".. as an identifier" begin + notebook = Notebook(Cell.([ + ".. = 1", + "..", + ])) + update_run!(🍭, notebook, notebook.cells) + + @test all(noerror, notebook.cells) + @test notebook.cells[end].output.body == "1" + end # PlutoTest.jl is only working on Julia version >= 1.6 - VERSION >= v"1.6" && @testset "Test Firebasey" begin + @testset "Test Firebasey" begin 🍭.options.evaluation.workspace_use_distributed = true file = tempname() write(file, read(normpath(Pluto.project_relative_path("src", "webserver", "Firebasey.jl")))) notebook = Pluto.load_notebook_nobackup(file) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @@ -194,14 +250,14 @@ import Distributed ]) notebook.topology = Pluto.updated_topology(notebook.topology, notebook, notebook.cells) - topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells) + topo_order = Pluto.topological_order(notebook.topology, notebook.cells) @test indexin(topo_order.runnable, notebook.cells) == [6, 5, 4, 7, 3, 1, 2, 8] # 6, 5, 4, 3 should run first (this is implemented using `cell_precedence_heuristic`), in that order # 1, 2, 7 remain, and should run in notebook order. # if the cells were placed in reverse order... reverse!(notebook.cell_order) - topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells) + topo_order = Pluto.topological_order(notebook.topology, notebook.cells) @test indexin(topo_order.runnable, reverse(notebook.cells)) == [6, 5, 4, 7, 3, 8, 2, 1] # 6, 5, 4, 3 should run first (this is implemented using `cell_precedence_heuristic`), in that order # 1, 2, 7 remain, and should run in notebook order, which is 7, 2, 1. @@ -223,7 +279,7 @@ import Distributed notebook.topology = Pluto.updated_topology(notebook.topology, notebook, notebook.cells) - topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells) + topo_order = Pluto.topological_order(notebook.topology, notebook.cells) comesbefore(A, first, second) = findfirst(isequal(first),A) < findfirst(isequal(second), A) @@ -242,7 +298,62 @@ import Distributed @test comesbefore(run_order, 4, 3) end - + @testset "Cleanup of workspace variable" begin + notebook = Notebook([ + Cell("x = 10000"), + ]) + + update_run!(🍭, notebook, notebook.cells[1:1]) + + @test haskey(WorkspaceManager.active_workspaces, notebook.notebook_id) + w = fetch(WorkspaceManager.active_workspaces[notebook.notebook_id]) + oldmod = getproperty(Main, w.module_name) + + setcode!(notebook.cells[begin], "") + update_run!(🍭, notebook, notebook.cells[1:1]) + + @test isdefined(oldmod, :x) + @test isnothing(getproperty(oldmod, :x)) + + newmod = getproperty(Main, w.module_name) + @test !isdefined(newmod, :x) + end + + @testset "Cleanup only Pluto controlled modules" begin + notebook = Notebook([ + Cell("""Core.eval(Main, :( + module var\"Pluto#2443\" + x = 1000 + end + ))"""), + Cell("import .Main.var\"Pluto#2443\": x"), + Cell("x"), + ]) + + update_run!(🍭, notebook, notebook.cells) + @test noerror(notebook.cells[1]) + @test noerror(notebook.cells[2]) + @test noerror(notebook.cells[3]) + + @test haskey(WorkspaceManager.active_workspaces, notebook.notebook_id) + w = fetch(WorkspaceManager.active_workspaces[notebook.notebook_id]) + oldmod = getproperty(Main, w.module_name) + + setcode!(notebook.cells[2], "") + setcode!(notebook.cells[3], "") + + update_run!(🍭, notebook, notebook.cells) + + @test isdefined(oldmod, :x) + @test which(oldmod, :x) != oldmod + @test !isnothing(getproperty(oldmod, :x)) + + newmod = getproperty(Main, w.module_name) + @test !isdefined(newmod, :x) + + @test !isnothing(Main.var"Pluto#2443".x) + end + @testset "Mixed usings and reactivity" begin notebook = Notebook([ Cell("a; using Dates"), @@ -251,7 +362,7 @@ import Distributed ]) notebook.topology = Pluto.updated_topology(notebook.topology, notebook, notebook.cells) - topo_order = Pluto.topological_order(notebook, notebook.topology, notebook.cells) + topo_order = Pluto.topological_order(notebook.topology, notebook.cells) run_order = indexin(topo_order.runnable, notebook.cells) @test run_order == [3, 1, 2] @@ -263,17 +374,16 @@ import Distributed Cell("using Dates"), Cell("July"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1:1]) @test notebook.cells[1].errored == true # this cell is before the using Dates and will error - @test notebook.cells[3].errored == false # using the position in the notebook this cell will not error + @test notebook.cells[3] |> noerror # using the position in the notebook this cell will not error update_run!(🍭, notebook, notebook.cells[2:2]) - @test notebook.cells[1].errored == false - @test notebook.cells[3].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[3] |> noerror end @testset "Reactive usings 2" begin @@ -283,26 +393,25 @@ import Distributed Cell("December"), Cell(""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) - @test notebook.cells[1].errored == false - @test notebook.cells[3].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[3] |> noerror - setcode(notebook.cells[2], "") + setcode!(notebook.cells[2], "") update_run!(🍭, notebook, notebook.cells[2:2]) @test notebook.cells[1].errored == true @test notebook.cells[3].errored == true - setcode(notebook.cells[4], "December = 13") + setcode!(notebook.cells[4], "December = 13") update_run!(🍭, notebook, notebook.cells[4:4]) @test notebook.cells[1].errored == true @test notebook.cells[3] |> noerror - setcode(notebook.cells[2], "using Dates") + setcode!(notebook.cells[2], "using Dates") update_run!(🍭, notebook, notebook.cells[2:2]) @test notebook.cells[1] |> noerror @@ -315,14 +424,13 @@ import Distributed Cell("archive_artifact"), Cell("using Unknown.Package"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test notebook.cells[1].errored == true @test notebook.cells[2].errored == true - setcode(notebook.cells[2], "using Pkg.Artifacts") + setcode!(notebook.cells[2], "using Pkg.Artifacts") update_run!(🍭, notebook, notebook.cells) @test notebook.cells[1] |> noerror @@ -339,7 +447,6 @@ import Distributed Cell(""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @@ -347,7 +454,7 @@ import Distributed @test notebook.cells[2].errored == true @test notebook.cells[3].errored == true - setcode(notebook.cells[4], "import Pkg; using Dates, Printf, Pkg.Artifacts") + setcode!(notebook.cells[4], "import Pkg; using Dates, Printf, Pkg.Artifacts") update_run!(🍭, notebook, notebook.cells[4:4]) @test notebook.cells[1] |> noerror @@ -367,13 +474,12 @@ import Distributed "December = 3", ])) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test all(noerror, notebook.cells) - setcode(notebook.cells[begin], raw""" + setcode!(notebook.cells[begin], raw""" begin @eval(module Hello December = 12 @@ -386,7 +492,7 @@ import Distributed @test all(noerror, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Function dependencies" begin @@ -400,7 +506,6 @@ import Distributed "b = 10", ])) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test :conj ∈ notebook.topology.nodes[notebook.cells[3]].soft_definitions @@ -426,7 +531,6 @@ import Distributed "MyStruct(1.) |> inv" ])) cell(idx) = notebook.cells[idx] - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test cell(1) |> noerror @@ -434,10 +538,10 @@ import Distributed @test cell(3) |> noerror # Empty and run cells to remove the Base overloads that we created, just to be sure - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "More challenging reactivity of extended function" begin @@ -455,28 +559,27 @@ import Distributed "inv(a)", ])) cell(idx) = notebook.cells[idx] - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test all(noerror, notebook.cells) @test notebook.cells[end].output.body == "\"blahblah\"" - setcode(cell(1), "Base.inv(s::String) = s * \"suffix\"") + setcode!(cell(1), "Base.inv(s::String) = s * \"suffix\"") update_run!(🍭, notebook, cell(1)) @test all(noerror, notebook.cells) @test notebook.cells[end].output.body == "\"blahblahsuffixsuffix\"" # 2 invs, 1 in constructor, 1 in inv(::MyStruct) - setcode(cell(3), "Base.inv(ms::MyStruct) = ms.x") # remove inv in inv(::MyStruct) + setcode!(cell(3), "Base.inv(ms::MyStruct) = ms.x") # remove inv in inv(::MyStruct) update_run!(🍭, notebook, cell(3)) @test all(noerror, notebook.cells) @test notebook.cells[end].output.body == "\"blahblahsuffix\"" # only one inv # Empty and run cells to remove the Base overloads that we created, just to be sure - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "multiple cells cycle" begin @@ -487,7 +590,6 @@ import Distributed "Base.inv(x::Float64) = a", "d = Float64(c)", ])) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test all(noerror, notebook.cells) @@ -502,16 +604,15 @@ import Distributed "Base.inv(::Float64) = y", "inv(1.0)", ])) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @test notebook.cells[end].errored == true @test occursinerror("Cyclic", notebook.cells[1]) - @test occursinerror("UndefVarError: y", notebook.cells[end]) # this is an UndefVarError and not a CyclicError + @test expecterror(UndefVarError(:y), notebook.cells[end]) # this is an UndefVarError and not a CyclicError - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Reactive methods definitions" begin @@ -525,13 +626,12 @@ import Distributed "", ])) cell(idx) = notebook.cells[idx] - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) output_21 = cell(2).output.body @test contains(output_21, "sqrt(🍕)") - setcode(cell(3), """ + setcode!(cell(3), """ Base.sqrt(x::Int) = sqrt(Float64(x)^2) """) update_run!(🍭, notebook, cell(3)) @@ -543,9 +643,9 @@ import Distributed @test output_21 != output_22 # cell2 re-run @test contains(output_22, "sqrt(🍕)") - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Don't lose basic generic types with macros" begin @@ -590,9 +690,9 @@ import Distributed @test notebook.cells[1].output.body == output_1 @test noerror(notebook.cells[2]) - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Multiple methods across cells" begin @@ -633,32 +733,31 @@ import Distributed e14 end"""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1:4]) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror @test notebook.cells[3].output.body == "1" @test notebook.cells[4].output.body == "2" - setcode(notebook.cells[1], "a(x,x) = 999") + setcode!(notebook.cells[1], "a(x,x) = 999") update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[1].errored == true @test notebook.cells[2].errored == true @test notebook.cells[3].errored == true @test notebook.cells[4].errored == true - setcode(notebook.cells[1], "a(x) = 1") + setcode!(notebook.cells[1], "a(x) = 1") update_run!(🍭, notebook, notebook.cells[1]) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror @test notebook.cells[3].output.body == "1" @test notebook.cells[4].output.body == "2" - setcode(notebook.cells[1], "") + setcode!(notebook.cells[1], "") update_run!(🍭, notebook, notebook.cells[1]) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror @test notebook.cells[3].errored == true @test notebook.cells[4].output.body == "2" @@ -668,18 +767,18 @@ import Distributed @test notebook.cells[7].errored == true @test notebook.cells[8].errored == true - setcode(notebook.cells[5], "") + setcode!(notebook.cells[5], "") update_run!(🍭, notebook, notebook.cells[5]) - @test notebook.cells[5].errored == false - @test notebook.cells[6].errored == false + @test notebook.cells[5] |> noerror + @test notebook.cells[6] |> noerror @test notebook.cells[7].errored == true @test notebook.cells[8].output.body == "6" - setcode(notebook.cells[5], "b = 5") - setcode(notebook.cells[6], "") + setcode!(notebook.cells[5], "b = 5") + setcode!(notebook.cells[6], "") update_run!(🍭, notebook, notebook.cells[5:6]) - @test notebook.cells[5].errored == false - @test notebook.cells[6].errored == false + @test notebook.cells[5] |> noerror + @test notebook.cells[6] |> noerror @test notebook.cells[7].output.body == "12" @test notebook.cells[8].errored == true @@ -687,20 +786,20 @@ import Distributed @test notebook.cells[12].output.body == "missing" update_run!(🍭, notebook, notebook.cells[9:10]) - @test notebook.cells[9].errored == false - @test notebook.cells[10].errored == false + @test notebook.cells[9] |> noerror + @test notebook.cells[10] |> noerror @test notebook.cells[11].output.body == "9" @test notebook.cells[12].output.body == "10" @test notebook.cells[13].output.body == "10" update_run!(🍭, notebook, notebook.cells[13]) @test notebook.cells[13].output.body == "10" - setcode(notebook.cells[9], "") + setcode!(notebook.cells[9], "") update_run!(🍭, notebook, notebook.cells[9]) @test notebook.cells[11].errored == true @test notebook.cells[12].output.body == "10" - setcode(notebook.cells[10], "") + setcode!(notebook.cells[10], "") update_run!(🍭, notebook, notebook.cells[10]) @test notebook.cells[11].errored == true @test notebook.cells[12].output.body == "missing" @@ -717,22 +816,22 @@ import Distributed @test notebook.cells[18].errored == true update_run!(🍭, notebook, notebook.cells[14]) - @test notebook.cells[16].errored == false + @test notebook.cells[16] |> noerror @test notebook.cells[17].errored == true - @test notebook.cells[18].errored == false + @test notebook.cells[18] |> noerror update_run!(🍭, notebook, notebook.cells[15]) - @test notebook.cells[16].errored == false - @test notebook.cells[17].errored == false - @test notebook.cells[18].errored == false + @test notebook.cells[16] |> noerror + @test notebook.cells[17] |> noerror + @test notebook.cells[18] |> noerror - setcode(notebook.cells[14], "") + setcode!(notebook.cells[14], "") update_run!(🍭, notebook, notebook.cells[14]) @test notebook.cells[16].errored == true - @test notebook.cells[17].errored == false - @test notebook.cells[18].errored == false + @test notebook.cells[17] |> noerror + @test notebook.cells[18] |> noerror - setcode(notebook.cells[15], "") + setcode!(notebook.cells[15], "") update_run!(🍭, notebook, notebook.cells[15]) @test notebook.cells[16].errored == true @test notebook.cells[17].errored == true @@ -745,11 +844,11 @@ import Distributed # Cell("e(22)"), update_run!(🍭, notebook, notebook.cells[19:22]) - @test notebook.cells[19].errored == false - @test notebook.cells[21].errored == false + @test notebook.cells[19] |> noerror + @test notebook.cells[21] |> noerror @test notebook.cells[22].errored == true - setcode(notebook.cells[20], "asdf(x) = asdf(x,x)") + setcode!(notebook.cells[20], "asdf(x) = asdf(x,x)") update_run!(🍭, notebook, notebook.cells[20]) @test occursinerror("Multiple definitions", notebook.cells[19]) @test occursinerror("Multiple definitions", notebook.cells[20]) @@ -758,42 +857,42 @@ import Distributed @test notebook.cells[21].errored == true @test notebook.cells[22].errored == true - setcode(notebook.cells[20], "") + setcode!(notebook.cells[20], "") update_run!(🍭, notebook, notebook.cells[20]) - @test notebook.cells[19].errored == false - @test notebook.cells[20].errored == false - @test notebook.cells[21].errored == false + @test notebook.cells[19] |> noerror + @test notebook.cells[20] |> noerror + @test notebook.cells[21] |> noerror @test notebook.cells[22].errored == true - setcode(notebook.cells[19], "begin struct asdf; x; y; end; asdf(x) = asdf(x,x); end") - setcode(notebook.cells[20], "") + setcode!(notebook.cells[19], "begin struct asdf; x; y; end; asdf(x) = asdf(x,x); end") + setcode!(notebook.cells[20], "") update_run!(🍭, notebook, notebook.cells[19:20]) - @test notebook.cells[19].errored == false - @test notebook.cells[20].errored == false - @test notebook.cells[21].errored == false - @test notebook.cells[22].errored == false + @test notebook.cells[19] |> noerror + @test notebook.cells[20] |> noerror + @test notebook.cells[21] |> noerror + @test notebook.cells[22] |> noerror update_run!(🍭, notebook, notebook.cells[23:27]) - @test notebook.cells[23].errored == false - @test notebook.cells[24].errored == false - @test notebook.cells[25].errored == false - @test notebook.cells[26].errored == false - @test notebook.cells[27].errored == false + @test notebook.cells[23] |> noerror + @test notebook.cells[24] |> noerror + @test notebook.cells[25] |> noerror + @test notebook.cells[26] |> noerror + @test notebook.cells[27] |> noerror update_run!(🍭, notebook, notebook.cells[23:27]) - @test notebook.cells[23].errored == false - @test notebook.cells[24].errored == false - @test notebook.cells[25].errored == false - @test notebook.cells[26].errored == false - @test notebook.cells[27].errored == false + @test notebook.cells[23] |> noerror + @test notebook.cells[24] |> noerror + @test notebook.cells[25] |> noerror + @test notebook.cells[26] |> noerror + @test notebook.cells[27] |> noerror - setcode.(notebook.cells[23:27], [""]) + setcode!.(notebook.cells[23:27], [""]) update_run!(🍭, notebook, notebook.cells[23:27]) - setcode(notebook.cells[23], "@assert !any(isdefined.([@__MODULE__], [Symbol(:e,i) for i in 1:14]))") + setcode!(notebook.cells[23], "@assert !any(isdefined.([@__MODULE__], [Symbol(:e,i) for i in 1:14]))") update_run!(🍭, notebook, notebook.cells[23]) - @test notebook.cells[23].errored == false + @test notebook.cells[23] |> noerror - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) # for some unsupported edge cases, see: # https://github.com/fonsp/Pluto.jl/issues/177#issuecomment-645039993 @@ -852,7 +951,6 @@ import Distributed Cell("j(x) = (x > 0) ? f(x-1) : :done") Cell("f(8)") ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1:3]) @test occursinerror("Cyclic reference", notebook.cells[1]) @@ -863,13 +961,13 @@ import Distributed @test occursinerror("yyy", notebook.cells[2]) @test occursinerror("UndefVarError", notebook.cells[3]) - setcode(notebook.cells[1], "xxx = 1") + setcode!(notebook.cells[1], "xxx = 1") update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[1].output.body == "1" @test notebook.cells[2].output.body == "1" @test notebook.cells[3].output.body == "1" - setcode(notebook.cells[1], "xxx = zzz") + setcode!(notebook.cells[1], "xxx = zzz") update_run!(🍭, notebook, notebook.cells[1]) @test occursinerror("Cyclic reference", notebook.cells[1]) @test occursinerror("Cyclic reference", notebook.cells[2]) @@ -884,7 +982,7 @@ import Distributed @test occursinerror("yyy", notebook.cells[3]) @test occursinerror("zzz", notebook.cells[3]) - setcode(notebook.cells[3], "zzz = 3") + setcode!(notebook.cells[3], "zzz = 3") update_run!(🍭, notebook, notebook.cells[3]) @test notebook.cells[1].output.body == "3" @test notebook.cells[2].output.body == "3" @@ -940,10 +1038,10 @@ import Distributed @assert length(notebook.cells) == 32 # Empty and run cells to remove the Base overloads that we created, just to be sure - setcode.(notebook.cells, [""]) + setcode!.(notebook.cells, [""]) update_run!(🍭, notebook, notebook.cells) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Variable deletion" begin @@ -953,34 +1051,33 @@ import Distributed Cell("struct a; x end"), Cell("a") ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1:2]) @test notebook.cells[1].output.body == notebook.cells[2].output.body - setcode(notebook.cells[1], "") + setcode!(notebook.cells[1], "") update_run!(🍭, notebook, notebook.cells[1]) - @test notebook.cells[1].errored == false - @test occursinerror("x not defined", notebook.cells[2]) + @test notebook.cells[1] |> noerror + @test expecterror(UndefVarError(:x), notebook.cells[2]) update_run!(🍭, notebook, notebook.cells[4]) update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false - setcode(notebook.cells[3], "struct a; x; y end") + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror + setcode!(notebook.cells[3], "struct a; x; y end") update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false - setcode(notebook.cells[3], "") + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror + setcode!(notebook.cells[3], "") update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false + @test notebook.cells[3] |> noerror @test notebook.cells[4].errored == true - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Recursion" begin @@ -995,40 +1092,38 @@ import Distributed Cell("h(4)"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[1].output.body == "f" || startswith(notebook.cells[1].output.body, "f (generic function with ") - @test notebook.cells[1].errored == false + @test notebook.cells[1] |> noerror update_run!(🍭, notebook, notebook.cells[2:3]) - @test notebook.cells[2].errored == false - @test notebook.cells[3].errored == false + @test notebook.cells[2] |> noerror + @test notebook.cells[3] |> noerror update_run!(🍭, notebook, notebook.cells[3]) - @test notebook.cells[3].errored == false + @test notebook.cells[3] |> noerror update_run!(🍭, notebook, notebook.cells[4]) @test notebook.cells[4].output.body == "2" - setcode(notebook.cells[2], "k = 2") + setcode!(notebook.cells[2], "k = 2") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[4].output.body == "4" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Variable cannot reference its previous value" begin notebook = Notebook([ Cell("x = 3") ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1]) - setcode(notebook.cells[1], "x = x + 1") + setcode!(notebook.cells[1], "x = x + 1") update_run!(🍭, notebook, notebook.cells[1]) @test occursinerror("UndefVarError", notebook.cells[1]) - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end notebook = Notebook([ @@ -1088,106 +1183,105 @@ import Distributed Cell("using Dates"), Cell("year(DateTime(31))"), ]) - fakeclient.connected_notebook = notebook @testset "Changing functions" begin update_run!(🍭, notebook, notebook.cells[2]) - @test notebook.cells[2].errored == false + @test notebook.cells[2] |> noerror update_run!(🍭, notebook, notebook.cells[1]) update_run!(🍭, notebook, notebook.cells[3]) @test notebook.cells[3].output.body == "4" - setcode(notebook.cells[1], "y = 2") + setcode!(notebook.cells[1], "y = 2") update_run!(🍭, notebook, notebook.cells[1]) @test notebook.cells[3].output.body == "5" - @test notebook.cells[2].errored == false + @test notebook.cells[2] |> noerror - setcode(notebook.cells[1], "y") + setcode!(notebook.cells[1], "y") update_run!(🍭, notebook, notebook.cells[1]) @test occursinerror("UndefVarError", notebook.cells[1]) - @test notebook.cells[2].errored == false + @test notebook.cells[2] |> noerror @test occursinerror("UndefVarError", notebook.cells[3]) update_run!(🍭, notebook, notebook.cells[4]) update_run!(🍭, notebook, notebook.cells[5]) @test notebook.cells[5].output.body == "11" - setcode(notebook.cells[4], "g(a) = a+a") + setcode!(notebook.cells[4], "g(a) = a+a") update_run!(🍭, notebook, notebook.cells[4]) - @test notebook.cells[4].errored == false + @test notebook.cells[4] |> noerror @test notebook.cells[5].errored == true - setcode(notebook.cells[5], "g(5)") + setcode!(notebook.cells[5], "g(5)") update_run!(🍭, notebook, notebook.cells[5]) @test notebook.cells[5].output.body == "10" update_run!(🍭, notebook, notebook.cells[6]) update_run!(🍭, notebook, notebook.cells[7]) update_run!(🍭, notebook, notebook.cells[8]) - @test notebook.cells[6].errored == false - @test notebook.cells[7].errored == false + @test notebook.cells[6] |> noerror + @test notebook.cells[7] |> noerror @test notebook.cells[8].errored == true - setcode(notebook.cells[6], "h(x::Float64) = 2.0 * x") + setcode!(notebook.cells[6], "h(x::Float64) = 2.0 * x") update_run!(🍭, notebook, notebook.cells[6]) - @test notebook.cells[6].errored == false + @test notebook.cells[6] |> noerror @test notebook.cells[7].errored == true - @test notebook.cells[8].errored == false + @test notebook.cells[8] |> noerror update_run!(🍭, notebook, notebook.cells[9:10]) - @test notebook.cells[9].errored == false + @test notebook.cells[9] |> noerror @test notebook.cells[10].output.body == "true" - setcode(notebook.cells[9], "p = p") + setcode!(notebook.cells[9], "p = p") update_run!(🍭, notebook, notebook.cells[9]) @test occursinerror("UndefVarError", notebook.cells[9]) - setcode(notebook.cells[9], "p = 9") + setcode!(notebook.cells[9], "p = 9") update_run!(🍭, notebook, notebook.cells[9]) - @test notebook.cells[9].errored == false + @test notebook.cells[9] |> noerror @test notebook.cells[10].output.body == "false" - setcode(notebook.cells[9], "p(x) = 9") + setcode!(notebook.cells[9], "p(x) = 9") update_run!(🍭, notebook, notebook.cells[9]) - @test notebook.cells[9].errored == false + @test notebook.cells[9] |> noerror @test notebook.cells[10].output.body == "true" end @testset "Extending imported functions" begin update_run!(🍭, notebook, notebook.cells[11:15]) - @test_broken notebook.cells[11].errored == false - @test_broken notebook.cells[12].errored == false # multiple definitions for `Something` should be okay? == false - @test notebook.cells[13].errored == false + @test_broken notebook.cells[11] |> noerror + @test_broken notebook.cells[12] |> noerror # multiple definitions for `Something` should be okay? == false + @test notebook.cells[13] |> noerror @test notebook.cells[14].errored == true # the definition for a was created before `a` was used, so it hides the `a` from `Something` @test notebook.cells[15].output.body == "15" @test_nowarn update_run!(🍭, notebook, notebook.cells[13:15]) - @test notebook.cells[13].errored == false + @test notebook.cells[13] |> noerror @test notebook.cells[14].errored == true # the definition for a was created before `a` was used, so it hides the `a` from `Something` @test notebook.cells[15].output.body == "15" @test_nowarn update_run!(🍭, notebook, notebook.cells[16:20]) - @test notebook.cells[16].errored == false + @test notebook.cells[16] |> noerror @test occursinerror("Multiple", notebook.cells[17]) @test occursinerror("Multiple", notebook.cells[18]) @test occursinerror("UndefVarError", notebook.cells[19]) @test occursinerror("UndefVarError", notebook.cells[20]) @test_nowarn update_run!(🍭, notebook, notebook.cells[21:24]) - @test notebook.cells[21].errored == false - @test notebook.cells[22].errored == false - @test notebook.cells[23].errored == false + @test notebook.cells[21] |> noerror + @test notebook.cells[22] |> noerror + @test notebook.cells[23] |> noerror @test notebook.cells[23].output.body == "\"🐟\"" @test notebook.cells[24].output.body == "24" - setcode(notebook.cells[22], "import .Wow: c") + setcode!(notebook.cells[22], "import .Wow: c") @test_nowarn update_run!(🍭, notebook, notebook.cells[22]) - @test notebook.cells[22].errored == false + @test notebook.cells[22] |> noerror @test notebook.cells[23].output.body == "\"🐟\"" - @test notebook.cells[23].errored == false + @test notebook.cells[23] |> noerror @test notebook.cells[24].errored == true # the extension should no longer exist # https://github.com/fonsp/Pluto.jl/issues/59 @@ -1199,7 +1293,7 @@ import Distributed @test_nowarn update_run!(🍭, notebook, notebook.cells[25]) @test notebook.cells[25].output.body == "🐟" - setcode(notebook.cells[26], "") + setcode!(notebook.cells[26], "") @test_nowarn update_run!(🍭, notebook, notebook.cells[26]) @test_nowarn update_run!(🍭, notebook, notebook.cells[25]) @test notebook.cells[25].output.body isa Dict @@ -1214,7 +1308,7 @@ import Distributed @test notebook.cells[28].output.body == "\"🎈\"" @test notebook.cells[29].output.body == "\"🎈\"" - setcode(notebook.cells[27], "") + setcode!(notebook.cells[27], "") update_run!(🍭, notebook, notebook.cells[27]) @test notebook.cells[28].output.body == "false" @test notebook.cells[29].output.body == "true" # removing the overload doesn't trigger automatic re-eval because `isodd` doesn't match `Base.isodd` @@ -1225,16 +1319,16 @@ import Distributed @testset "Using external libraries" begin update_run!(🍭, notebook, notebook.cells[30:31]) - @test notebook.cells[30].errored == false + @test notebook.cells[30] |> noerror @test notebook.cells[31].output.body == "31" update_run!(🍭, notebook, notebook.cells[31]) @test notebook.cells[31].output.body == "31" - setcode(notebook.cells[30], "") + setcode!(notebook.cells[30], "") update_run!(🍭, notebook, notebook.cells[30:31]) @test occursinerror("UndefVarError", notebook.cells[31]) end - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) @testset "Functional programming" begin notebook = Notebook([ @@ -1249,32 +1343,31 @@ import Distributed Cell("h = [x -> x + b][1]"), Cell("h(8)"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1:2]) @test notebook.cells[1].output.body == "1" @test notebook.cells[2].output.body == "4" update_run!(🍭, notebook, notebook.cells[3:6]) - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false - @test notebook.cells[5].errored == false - @test notebook.cells[6].errored == false + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror + @test notebook.cells[5] |> noerror + @test notebook.cells[6] |> noerror @test notebook.cells[6].output.body == "9" - setcode(notebook.cells[3], "b = -3") + setcode!(notebook.cells[3], "b = -3") update_run!(🍭, notebook, notebook.cells[3]) @test notebook.cells[6].output.body == "3" update_run!(🍭, notebook, notebook.cells[7:8]) - @test notebook.cells[7].errored == false + @test notebook.cells[7] |> noerror @test notebook.cells[8].output.body == "5" - setcode(notebook.cells[3], "b = 3") + setcode!(notebook.cells[3], "b = 3") update_run!(🍭, notebook, notebook.cells[3]) @test notebook.cells[8].output.body == "11" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @@ -1305,14 +1398,13 @@ import Distributed Cell("map(14:14) do i; global apple = orange; end"), Cell("orange = 15"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1]) update_run!(🍭, notebook, notebook.cells[2]) @test occursinerror("Multiple definitions for x", notebook.cells[1]) @test occursinerror("Multiple definitions for x", notebook.cells[1]) - setcode(notebook.cells[2], "x + 1") + setcode!(notebook.cells[2], "x + 1") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[1].output.body == "1" @test notebook.cells[2].output.body == "2" @@ -1337,7 +1429,7 @@ import Distributed update_run!(🍭, notebook, notebook.cells[9:10]) @test !occursinerror("UndefVarError", notebook.cells[9]) - @test notebook.cells[10].errored == false + @test notebook.cells[10] |> noerror update_run!(🍭, notebook, notebook.cells[11]) @test_broken notebook.cells[9].errored == true @@ -1349,13 +1441,13 @@ import Distributed update_run!(🍭, notebook, notebook.cells[13:15]) @test notebook.cells[13].output.body == "15" - @test notebook.cells[14].errored == false + @test notebook.cells[14] |> noerror - setcode(notebook.cells[15], "orange = 10005") + setcode!(notebook.cells[15], "orange = 10005") update_run!(🍭, notebook, notebook.cells[15]) @test notebook.cells[13].output.body == "10005" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "No top level return" begin @@ -1427,7 +1519,32 @@ import Distributed @test notebook.cells[17] |> noerror @test notebook.cells[18] |> noerror - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) + end + + @testset "Using package from module" begin + notebook = Notebook([ + Cell("""module A + using Dates + end"""), + Cell(""), + Cell("December"), + ]) + + update_run!(🍭, notebook, notebook.cells) + + @test notebook.cells[begin] |> noerror + @test occursinerror("UndefVarError", notebook.cells[end]) + + setcode!(notebook.cells[2], "using Dates") + + update_run!(🍭, notebook, [notebook.cells[2]]) + + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror + @test notebook.cells[3] |> noerror + + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Function wrapping" begin @@ -1483,7 +1600,7 @@ import Distributed ]) update_run!(🍭, notebook, notebook.cells) - @test notebook.cells[1].errored == false + @test notebook.cells[1] |> noerror @test notebook.cells[1].output.body == "false" @test notebook.cells[22].output.body == "Expr" @test notebook.cells[25].output.body == ":(:value)" @@ -1510,21 +1627,21 @@ import Distributed @test 0.1 * good < notebook.cells[3].runtime / 1.0e9 < 0.5 * bad old = notebook.cells[4].output.body - setcode(notebook.cells[4], "4.0") + setcode!(notebook.cells[4], "4.0") update_run!(🍭, notebook, notebook.cells[4]) @test old != notebook.cells[4].output.body old = notebook.cells[5].output.body - setcode(notebook.cells[5], "[5.0]") + setcode!(notebook.cells[5], "[5.0]") update_run!(🍭, notebook, notebook.cells[5]) @test old != notebook.cells[5].output.body old = notebook.cells[6].output.body - setcode(notebook.cells[6], "66 / 6") + setcode!(notebook.cells[6], "66 / 6") update_run!(🍭, notebook, notebook.cells[6]) @test old != notebook.cells[6].output.body - @test notebook.cells[7].errored == false + @test notebook.cells[7] |> noerror @test notebook.cells[7].output.body == "false" @test occursinerror("UndefVarError", notebook.cells[8]) @@ -1543,16 +1660,16 @@ import Distributed @test notebook.cells[19].output.body == ":(1 + 1)" @test notebook.cells[20].output.body == ":(1 + 1)" - @test notebook.cells[27].errored == false + @test notebook.cells[27] |> noerror @test notebook.topology.codes[notebook.cells[27]].function_wrapped == false - @test notebook.cells[28].errored == false + @test notebook.cells[28] |> noerror update_run!(🍭, notebook, notebook.cells[29:30]) - @test notebook.cells[29].errored == false - @test notebook.cells[30].errored == false + @test notebook.cells[29] |> noerror + @test notebook.cells[30] |> noerror - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) @testset "Expression hash" begin @@ -1601,7 +1718,6 @@ import Distributed Cell("g(x) = x + y"), Cell("y = 22"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells[1]) @@ -1634,26 +1750,66 @@ import Distributed update_run!(🍭, notebook, notebook.cells[16:18]) - @test notebook.cells[16].errored == false + @test notebook.cells[16] |> noerror @test notebook.cells[16].output.body == "34" - @test notebook.cells[17].errored == false - @test notebook.cells[18].errored == false + @test notebook.cells[17] |> noerror + @test notebook.cells[18] |> noerror - setcode(notebook.cells[18], "υ = 8") + setcode!(notebook.cells[18], "υ = 8") update_run!(🍭, notebook, notebook.cells[18]) @test notebook.cells[16].output.body == "24" update_run!(🍭, notebook, notebook.cells[19:22]) - @test notebook.cells[19].errored == false + @test notebook.cells[19] |> noerror @test notebook.cells[19].output.body == "60" - @test notebook.cells[20].errored == false - @test notebook.cells[21].errored == false - @test notebook.cells[22].errored == false + @test notebook.cells[20] |> noerror + @test notebook.cells[21] |> noerror + @test notebook.cells[22] |> noerror - setcode(notebook.cells[22], "y = 0") + setcode!(notebook.cells[22], "y = 0") update_run!(🍭, notebook, notebook.cells[22]) @test notebook.cells[19].output.body == "38" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) + end + + @testset "Broadcast bug - Issue #2211" begin + notebook = Notebook(Cell.([ + "abstract type AbstractFoo{T} <: AbstractMatrix{T} end", + "struct X{T} <: AbstractFoo{T} end", + "convert(::Type{AbstractArray{T}}, S::AbstractFoo) where {T<:Number} = convert(AbstractFoo{T}, S)", + "Base.convert(::Type{AbstractArray{T}}, ::AbstractFoo) where {T} = nothing", + "Base.size(::AbstractFoo) = (2,2)", + "Base.getindex(::AbstractFoo{T}, args...) where {T} = one(T)", + "x = X{Float64}()", + "y = zeros(2,)", + "x, y", + ])) + update_run!(🍭, notebook, notebook.cells) + @test all(noerror, notebook.cells) + end + + @testset "ParseError messages" begin + notebook = Notebook(Cell.([ + "begin", + "\n\nend", + ])) + update_run!(🍭, notebook, notebook.cells) + @test Pluto.is_just_text(notebook.topology, notebook.cells[1]) + @test Pluto.is_just_text(notebook.topology, notebook.cells[2]) + @static if VERSION >= v"1.10.0-DEV.1548" # ~JuliaSyntax PR Pluto.jl#2526 julia#46372 + @test haskey(notebook.cells[1].output.body, :source) + @test haskey(notebook.cells[1].output.body, :diagnostics) + + @test haskey(notebook.cells[2].output.body, :source) + @test haskey(notebook.cells[2].output.body, :diagnostics) + else + @test !occursinerror("(incomplete ", notebook.cells[1]) + @test !occursinerror("(incomplete ", notebook.cells[2]) + + @show notebook.cells[1].output.body + @test startswith(notebook.cells[1].output.body[:msg], "syntax:") + @test startswith(notebook.cells[2].output.body[:msg], "syntax:") + end end end diff --git a/test/ReloadFromFile.jl b/test/ReloadFromFile.jl index a9c4bb909c..ec602fee3c 100644 --- a/test/ReloadFromFile.jl +++ b/test/ReloadFromFile.jl @@ -1,25 +1,34 @@ using Test -import Pluto: Configuration, Notebook, ServerSession, ClientSession, update_run!, Cell, WorkspaceManager, SessionActions +import Pluto: Configuration, Notebook, ServerSession, ClientSession, update_run!, Cell, WorkspaceManager, SessionActions, save_notebook import Pluto.Configuration: Options, EvaluationOptions -import Distributed using Pluto.WorkspaceManager: poll import Pkg + +function retry(f::Function, n) + try + f() + catch e + if n > 0 + retry(f, n - 1) + else + rethrow(e) + end + end +end + @testset "Reload from file" begin + retry(3) do + 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false 🍭.options.server.auto_reload_from_file = true - timeout_between_tests = 🍭.options.server.auto_reload_from_file_cooldown * 1.5 - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient - notebook = SessionActions.new(🍭; run_async=false) - fakeclient.connected_notebook = notebook ### sleep(timeout_between_tests) @@ -34,18 +43,18 @@ import Pkg write(notebook.path, file1) - @test poll(30) do + @assert poll(30) do length(notebook.cells) == 3 end - @test poll(5) do + @assert poll(5) do notebook.cells[1].output.body == "123" end - @test poll(5) do + @assert poll(5) do all(c -> !c.running, notebook.cells) end - @test notebook.cells[2].output.body == "246" - @test notebook.cells[3].errored == false + @assert notebook.cells[2].output.body == "246" + @assert notebook.cells[3] |> noerror original_rand_output = notebook.cells[3].output.body @@ -58,12 +67,12 @@ import Pkg file2 = sprint(Pluto.save_notebook, nb2) write(notebook.path, file2) - @test poll(10) do + @assert poll(10) do notebook.cells[3].output.body == "123" end # notebook order reversed, but cell should not re-run - @test original_rand_output == notebook.cells[1].output.body + @assert original_rand_output == notebook.cells[1].output.body ### @@ -74,28 +83,83 @@ import Pkg write(notebook.path, file3) - @test poll(10) do + @assert poll(10) do notebook.cells[1].output.body == "6" end - @test poll(5) do + @assert poll(5) do all(c -> !c.running, notebook.cells) end - @test notebook.cells[2].output.body == "12" + @assert notebook.cells[2].output.body == "12" # notebook order reversed again, but cell should not re-run - @test original_rand_output == notebook.cells[3].output.body - + @assert original_rand_output == notebook.cells[3].output.body + + ### sleep(timeout_between_tests) - file4 = read(joinpath(@__DIR__, "packages", "simple_stdlib_import.jl"), String) + file4 = read(notebook.path, String) + last_hot_reload_time4 = notebook.last_hot_reload_time + notebook.cells[3].code_folded = true + save_notebook(notebook) + sleep(timeout_between_tests) + + file5 = read(notebook.path, String) + @test file4 != file5 + @test notebook.cells[3].code_folded write(notebook.path, file4) - @test poll(10) do + @assert poll(10) do + notebook.cells[3].code_folded == false + end + + # cell folded, but cell should not re-run + @assert original_rand_output == notebook.cells[3].output.body + + @assert poll(10) do + last_hot_reload_time5 = notebook.last_hot_reload_time + last_hot_reload_time5 != last_hot_reload_time4 + end + + ### + sleep(timeout_between_tests) + + + file6 = read(notebook.path, String) + Pluto.set_disabled(notebook.cells[3], true) + save_notebook(notebook) + sleep(timeout_between_tests) + + file7 = read(notebook.path, String) + @assert file6 != file7 + @assert Pluto.is_disabled(notebook.cells[3]) + + write(notebook.path, file6) + @assert poll(10) do + !Pluto.is_disabled(notebook.cells[3]) + end + + # cell disabled and re-enabled, so it should re-run + @assert poll(10) do + original_rand_output != notebook.cells[3].output.body + end + + + ### + sleep(timeout_between_tests) + + file8 = read(joinpath(@__DIR__, "packages", "simple_stdlib_import.jl"), String) + write(notebook.path, file8) + + + @assert poll(10) do notebook.cells[2].output.body == "false" end - @test length(notebook.cells) == 2 - @test notebook.nbpkg_restart_required_msg !== nothing -end \ No newline at end of file + + @assert length(notebook.cells) == 2 + @assert notebook.nbpkg_restart_required_msg !== nothing +end +@test true +end diff --git a/test/RichOutput.jl b/test/RichOutput.jl index 20a79050c6..69e1eccff9 100644 --- a/test/RichOutput.jl +++ b/test/RichOutput.jl @@ -7,8 +7,6 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient @testset "Tree viewer" begin @testset "Basics" begin @@ -44,7 +42,6 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb Cell("[ rand(50,50) ]"), Cell("[ rand(500,500) ]"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @@ -98,7 +95,7 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test sizes[2] < sizes[1] * 1.5 @test sizes[4] < sizes[3] * 1.5 - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Overloaded Base.show" begin @@ -122,7 +119,6 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb C(3) end"""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @@ -133,7 +129,7 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test notebook.cells[3].output.mime isa MIME"text/plain" @test notebook.cells[3].output.body == "3" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @@ -143,8 +139,36 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb notebook = Notebook([ Cell("using OffsetArrays"), Cell("OffsetArray(zeros(3), 20:22)"), + + Cell(""" + begin + struct BadImplementation <: AbstractVector{Int64} + end + function Base.show(io::IO, ::MIME"text/plain", b::BadImplementation) + write(io, "fallback") + end + end + """), + + Cell(""" + begin + struct OneTwoThree <: AbstractVector{Int64} + end + + + function Base.show(io::IO, ::MIME"text/plain", b::OneTwoThree) + write(io, "fallback") + end + + Base.size(::OneTwoThree) = (3,) + Base.getindex(::OneTwoThree, i) = 100 + i + end + """), + + Cell("BadImplementation()"), + Cell("OneTwoThree()"), + ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) @@ -152,10 +176,18 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb s = string(notebook.cells[2].output.body) @test occursin("OffsetArray", s) @test occursin("21", s) - if VERSION >= v"1.3" - # once in the prefix, once as index - @test count("22", s) >= 2 - end + # once in the prefix, once as index + @test count("22", s) >= 2 + + @test notebook.cells[5].output.mime isa MIME"text/plain" + @test notebook.cells[5].output.body == "fallback" + + @test notebook.cells[6].output.mime isa MIME"application/vnd.pluto.tree+object" + s = string(notebook.cells[6].output.body) + @test occursin("OneTwoThree", s) + @test occursin("101", s) + @test occursin("102", s) + @test occursin("103", s) WorkspaceManager.unmake_workspace((🍭, notebook)) 🍭.options.evaluation.workspace_use_distributed = false @@ -187,17 +219,31 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb x[] = (1,x) end"""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror end end + @testset "embed_display" begin + 🍭.options.evaluation.workspace_use_distributed = false + notebook = Notebook([ + Cell("x = randn(10)"), + Cell(raw"md\"x = $(embed_display(x))\"") + ]) + update_run!(🍭, notebook, notebook.cells) + + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror + + @test notebook.cells[2].output.body isa String + @test occursin("getPublishedObject", notebook.cells[2].output.body) + end + @testset "Table viewer" begin 🍭.options.evaluation.workspace_use_distributed = true notebook = Notebook([ @@ -224,13 +270,13 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb (a=16, b=16,) (a=16, b=16,) ]"""), + Cell("Union{}[]"), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) - @test notebook.cells[2].output.mime isa MIME"application/vnd.pluto.table+object" - @test notebook.cells[3].output.mime isa MIME"application/vnd.pluto.table+object" + # @test notebook.cells[2].output.mime isa MIME"application/vnd.pluto.table+object" + # @test notebook.cells[3].output.mime isa MIME"application/vnd.pluto.table+object" @test notebook.cells[4].output.mime isa MIME"application/vnd.pluto.table+object" @test notebook.cells[5].output.mime isa MIME"application/vnd.pluto.table+object" @test notebook.cells[6].output.mime isa MIME"application/vnd.pluto.table+object" @@ -242,8 +288,9 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test notebook.cells[14].output.mime isa MIME"application/vnd.pluto.tree+object" @test notebook.cells[15].output.mime isa MIME"application/vnd.pluto.tree+object" @test notebook.cells[16].output.mime isa MIME"application/vnd.pluto.tree+object" - @test notebook.cells[2].output.body isa Dict - @test notebook.cells[3].output.body isa Dict + @test notebook.cells[17].output.mime isa MIME"application/vnd.pluto.tree+object" + # @test notebook.cells[2].output.body isa Dict + # @test notebook.cells[3].output.body isa Dict @test notebook.cells[4].output.body isa Dict @test notebook.cells[5].output.body isa Dict @test notebook.cells[6].output.body isa Dict @@ -255,11 +302,14 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test notebook.cells[14].output.body isa Dict @test notebook.cells[15].output.body isa Dict @test notebook.cells[16].output.body isa Dict + @test notebook.cells[17].output.body isa Dict @test occursin("String?", string(notebook.cells[13].output.body)) # Issue 1490. @test notebook.cells[10].output.mime isa MIME"text/plain" - @test notebook.cells[10].errored == false + @test notebook.cells[10] |> noerror + @test notebook.cells[17] |> noerror # Issue 1815 + # to see if we truncated correctly, we convert the output to string and check how big it is # because we don't want to test too specifically roughsize(x) = length(string(x)) @@ -292,7 +342,6 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb Cell("0 + 10;\n10;"), Cell("0 + 11;\n11"), ]) - fakeclient.connected_notebook = notebook @testset "Strange code" begin update_run!(🍭, notebook, notebook.cells[1]) @@ -306,26 +355,26 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb update_run!(🍭, notebook, notebook.cells[3:end]) @test occursinerror("syntax: extra token after", notebook.cells[3]) - @test notebook.cells[4].errored == false + @test notebook.cells[4] |> noerror @test notebook.cells[4].output.body == "4" @test notebook.cells[4].output.rootassignee == :c - @test notebook.cells[5].errored == false + @test notebook.cells[5] |> noerror @test notebook.cells[5].output.body == "" @test notebook.cells[5].output.rootassignee === nothing - @test notebook.cells[6].errored == false + @test notebook.cells[6] |> noerror @test notebook.cells[6].output.body == "6" @test notebook.cells[6].output.rootassignee === nothing - @test notebook.cells[7].errored == false + @test notebook.cells[7] |> noerror @test notebook.cells[7].output.body == "" @test notebook.cells[7].output.rootassignee === nothing - @test notebook.cells[8].errored == false + @test notebook.cells[8] |> noerror @test notebook.cells[8].output.body == "" - @test notebook.cells[9].errored == false + @test notebook.cells[9] |> noerror @test notebook.cells[9].output.body == "" @test occursinerror("syntax: extra token after", notebook.cells[10]) @@ -333,7 +382,7 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test occursinerror("syntax: extra token after", notebook.cells[11]) end - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end @testset "Stack traces" begin @@ -361,7 +410,6 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @testset "$(wrapped ? "With" : "Without") function wrapping" for wrapped in [false, true] notebook = wrapped ? notebook1 : notebook2 - fakeclient.connected_notebook = notebook @test_nowarn update_run!(🍭, notebook, notebook.cells[1:5]) @@ -414,7 +462,7 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb @test occursin(escape_me, st[:msg]) end - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end end diff --git a/test/WorkspaceManager.jl b/test/WorkspaceManager.jl index c56954fc79..fc7138e4a9 100644 --- a/test/WorkspaceManager.jl +++ b/test/WorkspaceManager.jl @@ -2,30 +2,21 @@ using Test using Pluto.Configuration: CompilerOptions using Pluto.WorkspaceManager: _merge_notebook_compiler_options import Pluto: update_save_run!, update_run!, WorkspaceManager, ClientSession, ServerSession, Notebook, Cell, project_relative_path -import Distributed +import Malt @testset "Workspace manager" begin # basic functionality is already tested by the reactivity tests @testset "Multiple notebooks" begin - - fakeclientA = ClientSession(:fakeA, nothing) - fakeclientB = ClientSession(:fakeB, nothing) 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = true - 🍭.connected_clients[fakeclientA.id] = fakeclientA - 🍭.connected_clients[fakeclientB.id] = fakeclientB - notebookA = Notebook([ Cell("x = 3") ]) - fakeclientA.connected_notebook = notebookA - notebookB = Notebook([ Cell("x") ]) - fakeclientB.connected_notebook = notebookB @test notebookA.path != notebookB.path @@ -42,10 +33,8 @@ import Distributed WorkspaceManager.unmake_workspace((🍭, notebookB)) end @testset "Variables with secret names" begin - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - 🍭.connected_clients[fakeclient.id] = fakeclient notebook = Notebook([ Cell("result = 1"), @@ -53,7 +42,6 @@ import Distributed Cell("elapsed_ns = 3"), Cell("elapsed_ns"), ]) - fakeclient.connected_notebook = notebook update_save_run!(🍭, notebook, notebook.cells[1:4]) @test notebook.cells[1].output.body == "1" @@ -61,15 +49,13 @@ import Distributed @test notebook.cells[3].output.body == "3" @test notebook.cells[4].output.body == "3" - WorkspaceManager.unmake_workspace((🍭, notebook)) + WorkspaceManager.unmake_workspace((🍭, notebook); verbose=false) end - Sys.iswindows() || (VERSION < v"1.6.0-a") || @testset "Pluto inside Pluto" begin - - client = ClientSession(:fakeA, nothing) + Sys.iswindows() || @testset "Pluto inside Pluto" begin 🍭 = ServerSession() - 🍭.options.evaluation.workspace_use_distributed = true - 🍭.connected_clients[client.id] = client + 🍭.options.evaluation.capture_stdout = false + 🍭.options.evaluation.workspace_use_distributed_stdlib = false notebook = Notebook([ Cell("""begin @@ -80,38 +66,34 @@ import Distributed import Pluto end"""), Cell(""" - s = Pluto.ServerSession() + begin + s = Pluto.ServerSession() + s.options.evaluation.workspace_use_distributed_stdlib = false + end """), Cell(""" - nb = Pluto.SessionActions.open(s, Pluto.project_relative_path("sample", "Tower of Hanoi.jl"); run_async=false, as_sample=true)"""), + nb = Pluto.SessionActions.open(s, Pluto.project_relative_path("sample", "Tower of Hanoi.jl"); run_async=false, as_sample=true) + """), Cell("length(nb.cells)"), Cell(""), ]) - client.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) - @test notebook.cells[1].errored == false - @test notebook.cells[2].errored == false - @test notebook.cells[3].errored == false - @test notebook.cells[4].errored == false - @test notebook.cells[5].errored == false + @test notebook.cells[1] |> noerror + @test notebook.cells[2] |> noerror + @test notebook.cells[3] |> noerror + @test notebook.cells[4] |> noerror + @test notebook.cells[5] |> noerror - setcode(notebook.cells[5], "length(nb.cells)") + setcode!(notebook.cells[5], "length(nb.cells)") update_run!(🍭, notebook, notebook.cells[5]) - @test notebook.cells[5].errored == false + @test notebook.cells[5] |> noerror - - desired_nprocs = Distributed.nprocs() - 1 - setcode(notebook.cells[5], "Pluto.SessionActions.shutdown(s, nb)") + setcode!(notebook.cells[5], "Pluto.SessionActions.shutdown(s, nb)") update_run!(🍭, notebook, notebook.cells[5]) @test noerror(notebook.cells[5]) - while Distributed.nprocs() != desired_nprocs - sleep(.1) - end - sleep(.1) - WorkspaceManager.unmake_workspace((🍭, notebook)) end end diff --git a/test/cell_disabling.jl b/test/cell_disabling.jl index 7e1eb83a72..8865e57f6b 100644 --- a/test/cell_disabling.jl +++ b/test/cell_disabling.jl @@ -1,13 +1,251 @@ using Test using Pluto -using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook +using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook, set_disabled, is_disabled, WorkspaceManager + + + + @testset "Cell Disabling" begin 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = false - fakeclient = ClientSession(:fake, nothing) - 🍭.connected_clients[fakeclient.id] = fakeclient + notebook = Notebook([ + Cell("const a = 1") + Cell("const b = 2") + Cell("const c = 3") + Cell("const d = 4") + + Cell("const x = a") # 5 + # these cells will be uncommented later + Cell("# const x = b") # 6 + Cell("# const x = c") # 7 + + Cell("const z = x") # 8 + Cell("# const z = d") # 9 + + Cell("const y = z") # 10 + + Cell("things = []") # 11 + Cell("""begin + cool = 1 + push!(things, 1) + end""") # 12 + Cell("""begin + # cool = 2 + # push!(things, 2) + end""") # 13 + Cell("cool; length(things)") # 14 + ]) + update_run!(🍭, notebook, notebook.cells) + + # helper functions + id(i) = notebook.cells[i].cell_id + c(i) = notebook.cells[i] + get_indirectly_disabled_cells(notebook) = [i for (i, c) in pairs(notebook.cells) if c.depends_on_disabled_cells] + + + + @test !any(is_disabled, notebook.cells) + @test get_indirectly_disabled_cells(notebook) == [] + @test all(noerror, notebook.cells) + + ### + setcode!(c(6), "const x = b") + update_run!(🍭, notebook, c(6)) + + @test c(5).errored + @test c(6).errored + @test c(8).errored + @test c(10).errored + @test get_indirectly_disabled_cells(notebook) == [] + + ### + set_disabled(c(1), true) + update_run!(🍭, notebook, c(1)) + + @test noerror(c(1)) + @test noerror(c(6)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [1, 5] + + update_run!(🍭, notebook, c(5:6)) + @test noerror(c(1)) + @test noerror(c(6)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [1, 5] + + ### + set_disabled(c(1), false) + update_run!(🍭, notebook, c(1)) + + @test noerror(c(1)) + @test c(5).errored + @test c(6).errored + @test c(8).errored + @test c(10).errored + @test get_indirectly_disabled_cells(notebook) == [] + + ### + set_disabled(c(5), true) + update_run!(🍭, notebook, c(5)) + + @test noerror(c(1)) + @test noerror(c(6)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [5] + + ### + set_disabled(c(1), true) + update_run!(🍭, notebook, c(1)) + + @test noerror(c(1)) + @test noerror(c(6)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [1, 5] + + + ### + set_disabled(c(5), false) + setcode!(c(7), "const x = c") + update_run!(🍭, notebook, c([5,7])) + + @test c(5).errored + @test c(6).errored + @test c(7).errored + @test c(8).errored + @test c(10).errored + @test get_indirectly_disabled_cells(notebook) == [1, 5] + + ### + set_disabled(c(2), true) + update_run!(🍭, notebook, c(2)) + + @test noerror(c(3)) + @test noerror(c(7)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [1, 2, 5, 6] + + + ### + setcode!(c(9), "const z = d") + update_run!(🍭, notebook, c([9])) + + @test noerror(c(7)) + @test c(8).errored + @test c(9).errored + @test c(10).errored + @test get_indirectly_disabled_cells(notebook) == [1, 2, 5, 6] + + + ### + set_disabled(c(4), true) + update_run!(🍭, notebook, c(4)) + + @test noerror(c(3)) + @test noerror(c(4)) + @test noerror(c(7)) + @test noerror(c(8)) + @test noerror(c(10)) + @test get_indirectly_disabled_cells(notebook) == [1, 2, 4, 5, 6, 9] + + + ### + set_disabled(c(1), true) + set_disabled(c(2), false) + set_disabled(c(3), true) + set_disabled(c(4), false) + + set_disabled(c(5), true) + set_disabled(c(6), true) + set_disabled(c(7), false) + + set_disabled(c(8), false) + set_disabled(c(9), true) + + setcode!(c(10), "const x = 123123") + set_disabled(c(10), false) + + update_run!(🍭, notebook, c(1:10)) + + + @test noerror(c(1)) + @test noerror(c(2)) + @test noerror(c(3)) + @test noerror(c(4)) + + @test noerror(c(8)) + @test noerror(c(10)) + + @test get_indirectly_disabled_cells(notebook) == [1, 3, 5, 6, 7, 9] + + ### + set_disabled(c(3), false) + update_run!(🍭, notebook, c(3)) + + @test get_indirectly_disabled_cells(notebook) == [1, 5, 6, 9] + @test c(7).errored + @test c(8).errored + @test c(10).errored + + ### + set_disabled(c(10), true) + update_run!(🍭, notebook, c(10)) + + @test get_indirectly_disabled_cells(notebook) == [1, 5, 6, 9, 10] + @test noerror(c(7)) + @test noerror(c(8)) + + ### + set_disabled(c(7), true) + set_disabled(c(10), false) + update_run!(🍭, notebook, c([7,10])) + + @test get_indirectly_disabled_cells(notebook) == [1, 5, 6, 7, 9] + @test noerror(c(7)) + @test noerror(c(8)) + @test noerror(c(10)) + + + ### check that they really don't run when disabled + @test c(14).output.body == "1" + + setcode!(c(13), replace(c(13).code, "#" => "")) + update_run!(🍭, notebook, c([11,13])) + + + @test c(12).errored + @test c(13).errored + @test c(14).errored + + set_disabled(c(13), true) + update_run!(🍭, notebook, c([13])) + + @test noerror(c(12)) + @test noerror(c(14)) + + @test c(14).output.body == "1" + update_run!(🍭, notebook, c([11])) + @test c(14).output.body == "1" + update_run!(🍭, notebook, c([12])) + update_run!(🍭, notebook, c([12])) + @test c(14).output.body == "3" + + WorkspaceManager.unmake_workspace((🍭, notebook)) +end + + + + + +@testset "Cell Disabling 1" begin + 🍭 = ServerSession() + 🍭.options.evaluation.workspace_use_distributed = false notebook = Notebook([ Cell("""y = begin @@ -19,35 +257,38 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook Cell("w = z^5"), Cell(""), ]) - fakeclient.connected_notebook = notebook update_run!(🍭, notebook, notebook.cells) # helper functions id(i) = notebook.cells[i].cell_id get_disabled_cells(notebook) = [i for (i, c) in pairs(notebook.cells) if c.depends_on_disabled_cells] - @test !any(c.running_disabled for c in notebook.cells) + @test !any(get(c.metadata, "disabled", false) for c in notebook.cells) @test !any(c.depends_on_disabled_cells for c in notebook.cells) # disable first cell - notebook.cells[1].running_disabled = true - update_run!(🍭, notebook, notebook.cells) + notebook.cells[1].metadata["disabled"] = true + update_run!(🍭, notebook, notebook.cells[1]) should_be_disabled = [1, 3, 5] @test get_disabled_cells(notebook) == should_be_disabled + @test notebook.cells[1].metadata["disabled"] == true + + # metadatum will exists in memory, but not in the serialized form + @test all(haskey(notebook.cells[i].metadata , "disabled") for i=1:5) # change x, this change should not propagate through y original_y_output = notebook.cells[1].output.body original_z_output = notebook.cells[3].output.body original_a_output = notebook.cells[4].output.body original_w_output = notebook.cells[5].output.body - setcode(notebook.cells[2], "x = 123123") + setcode!(notebook.cells[2], "x = 123123") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[1].output.body == original_y_output @test notebook.cells[3].output.body == original_z_output @test notebook.cells[4].output.body != original_a_output @test notebook.cells[5].output.body == original_w_output - setcode(notebook.cells[2], "x = 2") + setcode!(notebook.cells[2], "x = 2") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[1].output.body == original_y_output @test notebook.cells[3].output.body == original_z_output @@ -55,25 +296,25 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook @test notebook.cells[5].output.body == original_w_output # disable root cell - notebook.cells[2].running_disabled = true + notebook.cells[2].metadata["disabled"] = true update_run!(🍭, notebook, notebook.cells) @test get_disabled_cells(notebook) == collect(1:5) original_6_output = notebook.cells[6].output.body - setcode(notebook.cells[6], "x + 6") + setcode!(notebook.cells[6], "x + 6") update_run!(🍭, notebook, notebook.cells[6]) @test notebook.cells[6].depends_on_disabled_cells @test notebook.cells[6].errored === false @test notebook.cells[6].output.body == original_6_output # reactivate first cell - still all cells should be running_disabled - notebook.cells[1].running_disabled = false + notebook.cells[1].metadata["disabled"] = false update_run!(🍭, notebook, notebook.cells) @test get_disabled_cells(notebook) == collect(1:6) # the x cell is disabled, so changing it should have no effect - setcode(notebook.cells[2], "x = 123123") + setcode!(notebook.cells[2], "x = 123123") update_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[1].output.body == original_y_output @test notebook.cells[3].output.body == original_z_output @@ -81,7 +322,7 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook @test notebook.cells[5].output.body == original_w_output # reactivate root cell - notebook.cells[2].running_disabled = false + notebook.cells[2].metadata["disabled"] = false update_run!(🍭, notebook, notebook.cells) @test get_disabled_cells(notebook) == [] @@ -92,14 +333,58 @@ using Pluto: update_run!, ServerSession, ClientSession, Cell, Notebook @test notebook.cells[5].output.body != original_w_output # disable first cell again - notebook.cells[1].running_disabled = true + notebook.cells[1].metadata["disabled"] = true update_run!(🍭, notebook, notebook.cells) should_be_disabled = [1, 3, 5] @test get_disabled_cells(notebook) == should_be_disabled # and reactivate it - notebook.cells[1].running_disabled = false + notebook.cells[1].metadata["disabled"] = false update_run!(🍭, notebook, notebook.cells) @test get_disabled_cells(notebook) == [] + WorkspaceManager.unmake_workspace((🍭, notebook)) +end + +@testset "Disabled cells should stay in the topology (#2676)" begin + 🍭 = ServerSession() + notebook = Notebook(Cell.([ + "using Dates", + "b = 2; December", + "b", + ])) + + disabled_cell = notebook.cells[end] + Pluto.set_disabled(disabled_cell, true) + @test is_disabled(disabled_cell) + + old_topo = notebook.topology + @test count(Pluto.is_disabled, notebook.cells) == 1 + order = update_run!(🍭, notebook, notebook.cells) + + # Disabled + @test length(order.input_topology.disabled_cells) == 1 + @test disabled_cell ∈ order.input_topology.disabled_cells + runned_cells = collect(order) + @test length(runned_cells) == 2 + @test disabled_cell ∉ runned_cells + + topo = notebook.topology + @test old_topo !== topo # topology was updated + + order = Pluto.topological_order(notebook) + + @test length(order.input_topology.disabled_cells) == 1 + @test disabled_cell ∈ order.input_topology.disabled_cells + saved_cells = collect(order) + @test length(saved_cells) == length(notebook.cells) + @test issetequal(saved_cells, notebook.cells) + + io = IOBuffer() + Pluto.save_notebook(io, notebook) + seekstart(io) + notebook2 = Pluto.load_notebook_nobackup(io, "mynotebook.jl") + @test length(notebook2.cells) == length(notebook.cells) + + WorkspaceManager.unmake_workspace((🍭, notebook)) end diff --git a/test/compiletimes.jl b/test/compiletimes.jl new file mode 100644 index 0000000000..eeddc1d5f3 --- /dev/null +++ b/test/compiletimes.jl @@ -0,0 +1,56 @@ +# Collect Time To First X (TTFX) +# +# A few notes about these compile times benchmarks. +# 1. These benchmarks are meant to show where the biggest problems are and to be able to trace back where some regression was introduced. +# 2. The benchmarks use `@eval` to avoid missing compile time, see the `@time` docstring for more info. +# 3. Only add benchmarks for methods which take more than 1 seconds on the first run to reduce noise. +# 4. Note that some benchmarks depend on disk and network speeds too, so focus on the number of allocations since those are more robust. + +module Foo end + +using UUIDs + +# setup required for run_exporession: +const test_notebook_id = uuid1() +let + channel = Channel{Any}(10) + Pluto.PlutoRunner.setup_plutologger( + test_notebook_id, + channel, + ) +end +@timeit TOUT "PlutoRunner.run_expression" @eval Pluto.PlutoRunner.run_expression(Foo, Expr(:toplevel, :(1 + 1)), test_notebook_id, uuid1(), nothing); + +function wait_for_ready(notebook::Pluto.Notebook) + while notebook.process_status != Pluto.ProcessStatus.ready + sleep(0.1) + end +end + +🍭 = Pluto.ServerSession() +🍭.options.server.disable_writing_notebook_files = true +🍭.options.evaluation.workspace_use_distributed = false + +path = joinpath(pkgdir(Pluto), "sample", "Basic.jl") + +@timeit TOUT "SessionActions.open" nb = @eval Pluto.SessionActions.open(🍭, path; run_async=false) + +wait_for_ready(nb) + +Pluto.SessionActions.shutdown(🍭, nb; async=false) + +# Compile HTTP get. Use no encoding since there seem to be an issue with Accept-Encoding: gzip +HTTP.get("http://github.com") + +@timeit TOUT "Pluto.run" server_task = @eval let + port = 13435 + options = Pluto.Configuration.from_flat_kwargs(; port, launch_browser=false, workspace_use_distributed=false, require_secret_for_access=false, require_secret_for_open_links=false) + 🍭 = Pluto.ServerSession(; options) + server_task = @async Pluto.run(🍭) + + # Give the async task time to start. + sleep(1) + + HTTP.get("http://localhost:$port/edit").status == 200 + server_task +end diff --git a/test/data structures.jl b/test/data structures.jl new file mode 100644 index 0000000000..4a532e9a9c --- /dev/null +++ b/test/data structures.jl @@ -0,0 +1,104 @@ +import Pluto: ImmutableVector, ImmutableSet, ImmutableDefaultDict, setdiffkeys + +@testset "ImmutableCollections" begin + + + + + +# ╔═╡ bd27d82e-62d6-422c-8fbe-61993dc4c268 +@test isempty(ImmutableVector{Int}()) + +# ╔═╡ d4f2016a-b093-4619-9ccb-3e99bf6fdc9b +@test ImmutableVector{Int32}([1,2,3]).c |> eltype == Int32 + +# ╔═╡ 055f21c0-3741-4762-ac4e-4c89633afbc4 +let + x = [1,2,3] + y = ImmutableVector(x) + push!(x,4) + @test y == [1,2,3] +end + +# ╔═╡ 52310ade-6e06-4ab8-8589-444c161cd93b +let + x = [1,2,3] + y = ImmutableVector{Int32}(x) + push!(x,4) + @test y == [1,2,3] +end + +# ╔═╡ d61600f0-2202-4228-8d35-380f732214e7 +ImmutableSet() + +# ╔═╡ d3871580-cd22-48c1-a1fd-d13a7f2f2135 +ImmutableSet{Int}() + +# ╔═╡ 2af00467-8bbf-49d8-bfe3-6f8d6307e900 +ImmutableSet{Int64}(Set([1,2]); skip_copy=true) + +# ╔═╡ 46836112-7c5c-4ffd-8d1e-93a2c8990b20 +@test ImmutableSet{Int64}(Set([1,2]); skip_copy=true) == Set([1,2]) + +# ╔═╡ fd687b2e-8bec-48b2-810e-38ef00bf567b +let + x = [1.1,2,3] + y = ImmutableVector(x; skip_copy=true) + push!(x,4) + @test y == [1.1,2,3,4] +end + +# ╔═╡ f4dddf0b-cf0a-41d0-880e-6a8fac7c60cb +let + x = [1.1,2,3] + y = ImmutableVector{Float64}(x; skip_copy=true) + push!(x,4) + @test y == [1.1,2,3,4] +end + +# ╔═╡ 25c78371-f12d-44ae-b180-32b88d3aa4f5 +@test eltype(ImmutableSet([2,3,4])) == Int + +# ╔═╡ 45115ac6-6586-458c-83e6-d661c2ce8db2 +let + x = Set([1,2,3]) + y = ImmutableSet(x) + push!(x,4) + @test y == Set([1,2,3]) +end + +# ╔═╡ 4f26640d-31d2-44c4-bbba-82c18d7497ae +let + x = Set([1.1,2,3]) + y = ImmutableSet(x; skip_copy=true) + push!(x,4) + @test y == Set([1.1,2,3,4]) +end + +# ╔═╡ eac9c95b-a2b6-4f1f-8cce-a2ad4c0972c5 +@test union(ImmutableSet([1,2]),[2,3]) == ImmutableSet([1,2,3]) + +# ╔═╡ bff65a2c-8654-4403-8e34-58aac8616729 +@test filter(x -> true, ImmutableVector([1,2,3])) == [1,2,3] + +# ╔═╡ ce3cdb24-e851-4cc3-9955-b34fe358b41a +@test ImmutableVector([1,2,3])[2:end] isa ImmutableVector + +# ╔═╡ c61196d6-f529-4883-b334-ed1b0f653acf + + +# ╔═╡ 5c2b3440-7231-42df-b4e5-619001d225a8 +ImmutableSet([123,234]) + + + +@test setdiffkeys(Dict(1=>2,3=>4),[3]) == Dict(1=>2) + +let + d = setdiffkeys(ImmutableDefaultDict(() -> 7, Dict(1=>2,3=>4)),[3]) + @test d[1] == 2 && d[3] == 7 +end + +@test setdiff(ImmutableSet([1,2]), [2]) isa ImmutableSet + +end \ No newline at end of file diff --git a/test/frontend/README.md b/test/frontend/README.md index 36c12d61c7..7d05333478 100644 --- a/test/frontend/README.md +++ b/test/frontend/README.md @@ -9,13 +9,13 @@ All commands here are executed in this folder (`Pluto.jl/test/frontend`). ## Run Pluto.jl server ``` -PLUTO_PORT=2345; julia --project=/path/to/PlutoDev -e "import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false, require_secret_for_open_links=false, launch_browser=false)" +PLUTO_PORT=2345; julia --project=/path/to/PlutoDev -e "import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false, launch_browser=false)" ``` or if Pluto is dev'ed in your global environment: ``` -PLUTO_PORT=2345; julia -e "import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false, require_secret_for_open_links=false, launch_browser=false)" +PLUTO_PORT=2345; julia -e "import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false, launch_browser=false)" ``` ## Run tests @@ -26,13 +26,13 @@ PLUTO_PORT=2345; julia -e "import Pluto; Pluto.run(port=$PLUTO_PORT, require_sec Add `HEADLESS=false` when running the test command. -`clear && HEADLESS=false PLUTO_PORT=2345 npm run test` +`clear && HEADLESS=false PLUTO_PORT=1234 npm run test` ## Run a particular suite of tests Add `-- -t=name of the suite` to the end of the test command. -`clear && PLUTO_PORT=2345 npm run test -- -t=PlutoAutocomplete` +`clear && HEADLESS=false PLUTO_PORT=1234 npm run test -- -t=PlutoAutocomplete` ## To make a test fail on a case that does not crash Pluto diff --git a/test/frontend/__tests__/autocomplete_test.js b/test/frontend/__tests__/autocomplete_test.js index c765f6db60..bef1588aac 100644 --- a/test/frontend/__tests__/autocomplete_test.js +++ b/test/frontend/__tests__/autocomplete_test.js @@ -1,6 +1,14 @@ import puppeteer from "puppeteer" -import { lastElement, saveScreenshot, getTestScreenshotPath, setupPage } from "../helpers/common" -import { getCellIds, importNotebook, waitForCellOutput, getPlutoUrl, prewarmPluto, writeSingleLineInPlutoInput, waitForNoUpdateOngoing } from "../helpers/pluto" +import { lastElement, saveScreenshot, createPage, waitForContentToBecome } from "../helpers/common" +import { + getCellIds, + importNotebook, + waitForCellOutput, + getPlutoUrl, + writeSingleLineInPlutoInput, + shutdownCurrentNotebook, + setupPlutoBrowser, +} from "../helpers/pluto" describe("PlutoAutocomplete", () => { /** @@ -13,26 +21,15 @@ describe("PlutoAutocomplete", () => { /** @type {puppeteer.Page} */ let page = null beforeAll(async () => { - browser = await puppeteer.launch({ - headless: process.env.HEADLESS !== "false", - args: ["--no-sandbox", "--disable-setuid-sandbox"], - devtools: false, - }) - - let page = await browser.newPage() - setupPage(page) - await prewarmPluto(browser, page) - await page.close() + browser = await setupPlutoBrowser() }) beforeEach(async () => { - page = await browser.newPage() - setupPage(page) + page = await createPage(browser) await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) }) afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()) - // @ts-ignore - await page.evaluate(() => window.shutdownNotebook?.()) + await saveScreenshot(page) + await shutdownCurrentNotebook(page) await page.close() page = null }) @@ -43,7 +40,6 @@ describe("PlutoAutocomplete", () => { it("should get the correct autocomplete suggestions", async () => { await importNotebook(page, "autocomplete_notebook.jl") - await waitForNoUpdateOngoing(page, { polling: 100 }) const importedCellIds = await getCellIds(page) await Promise.all(importedCellIds.map((cellId) => waitForCellOutput(page, cellId))) @@ -85,13 +81,7 @@ describe("PlutoAutocomplete", () => { // Trigger autocomplete await page.keyboard.press("Tab") - await page.waitForTimeout(5000) - // Get suggestions - const autocompletedInput = await page.evaluate( - (selector) => document.querySelector(selector).textContent.trim(), - `pluto-cell[id="${lastPlutoCellId}"] pluto-input .CodeMirror-line` - ) - expect(autocompletedInput).toEqual("my_subtract") + expect(await waitForContentToBecome(page, `pluto-cell[id="${lastPlutoCellId}"] pluto-input .CodeMirror-line`, "my_subtract")).toBe("my_subtract") }) }) diff --git a/test/frontend/__tests__/bond_rerun_test.js b/test/frontend/__tests__/bonds.js similarity index 63% rename from test/frontend/__tests__/bond_rerun_test.js rename to test/frontend/__tests__/bonds.js index a6aa215b87..af633a3400 100644 --- a/test/frontend/__tests__/bond_rerun_test.js +++ b/test/frontend/__tests__/bonds.js @@ -1,6 +1,6 @@ import puppeteer from "puppeteer" -import { saveScreenshot, getTestScreenshotPath, setupPage, paste } from "../helpers/common" -import { createNewNotebook, getPlutoUrl, prewarmPluto, waitForNoUpdateOngoing } from "../helpers/pluto" +import { saveScreenshot, createPage, paste } from "../helpers/common" +import { createNewNotebook, getPlutoUrl, runAllChanged, setupPlutoBrowser, shutdownCurrentNotebook, waitForPlutoToCalmDown } from "../helpers/pluto" // https://github.com/fonsp/Pluto.jl/issues/928 describe("Bonds should run once when refreshing page", () => { @@ -14,28 +14,15 @@ describe("Bonds should run once when refreshing page", () => { /** @type {puppeteer.Page} */ let page = null beforeAll(async () => { - browser = await puppeteer.launch({ - headless: process.env.HEADLESS !== "false", - args: ["--no-sandbox", "--disable-setuid-sandbox"], - devtools: false, - }) - - let page = await browser.newPage() - setupPage(page) - await prewarmPluto(browser, page) - await page.close() + browser = await setupPlutoBrowser() }) beforeEach(async () => { - page = await browser.newPage() - setupPage(page) + page = await createPage(browser) await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) - await createNewNotebook(page) - await page.waitForSelector("pluto-input", { visible: true }) }) afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()) - // @ts-ignore - await page.evaluate(() => window.shutdownNotebook?.()) + await saveScreenshot(page) + await shutdownCurrentNotebook(page) await page.close() page = null }) @@ -45,6 +32,8 @@ describe("Bonds should run once when refreshing page", () => { }) it("should not rerun bond values when refreshing page", async () => { + await createNewNotebook(page) + await paste( page, ` @@ -58,11 +47,7 @@ describe("Bonds should run once when refreshing page", () => { @bind z html"" ` ) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - - await page.waitForSelector(`pluto-cell.running`, { visible: true, timeout: 0 }) - await waitForNoUpdateOngoing(page) + await runAllChanged(page) await paste( page, @@ -75,11 +60,10 @@ numberoftimes = Ref(0) ` ) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) + await runAllChanged(page) await page.waitForFunction(() => Boolean(document.querySelector("pluto-cell:nth-of-type(5) pluto-output")?.textContent)) + await waitForPlutoToCalmDown(page) - await waitForNoUpdateOngoing(page) let output_after_running_bonds = await page.evaluate(() => { return document.querySelector("pluto-cell:nth-of-type(5) pluto-output")?.textContent }) @@ -88,7 +72,7 @@ numberoftimes = Ref(0) // Let's refresh and see await page.reload({ waitUntil: ["networkidle0", "domcontentloaded"] }) await page.waitForFunction(() => Boolean(document.querySelector("pluto-cell:nth-of-type(5) pluto-output")?.textContent)) - await waitForNoUpdateOngoing(page) + await waitForPlutoToCalmDown(page) let output_after_reload = await page.evaluate(() => { return document.querySelector("pluto-cell:nth-of-type(5) pluto-output")?.textContent }) diff --git a/test/frontend/__tests__/import_notebook_test.js b/test/frontend/__tests__/import_notebook_test.js index c293bd91fa..bf49cb81b1 100644 --- a/test/frontend/__tests__/import_notebook_test.js +++ b/test/frontend/__tests__/import_notebook_test.js @@ -1,6 +1,16 @@ import puppeteer from "puppeteer" -import { lastElement, saveScreenshot, getTestScreenshotPath, setupPage } from "../helpers/common" -import { getCellIds, waitForCellOutput, importNotebook, getPlutoUrl, prewarmPluto, writeSingleLineInPlutoInput } from "../helpers/pluto" +import { lastElement, saveScreenshot, createPage } from "../helpers/common" +import { + getCellIds, + waitForCellOutput, + importNotebook, + getPlutoUrl, + prewarmPluto, + writeSingleLineInPlutoInput, + shutdownCurrentNotebook, + setupPlutoBrowser, + runAllChanged, +} from "../helpers/pluto" describe("PlutoImportNotebook", () => { /** @@ -13,26 +23,15 @@ describe("PlutoImportNotebook", () => { /** @type {puppeteer.Page} */ let page = null beforeAll(async () => { - browser = await puppeteer.launch({ - headless: process.env.HEADLESS !== "false", - args: ["--no-sandbox", "--disable-setuid-sandbox"], - devtools: false, - }) - - let page = await browser.newPage() - setupPage(page) - await prewarmPluto(browser, page) - await page.close() + browser = await setupPlutoBrowser() }) beforeEach(async () => { - page = await browser.newPage() - setupPage(page) + page = await createPage(browser) await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) }) afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()) - // @ts-ignore - await page.evaluate(() => window.shutdownNotebook?.()) + await saveScreenshot(page) + await shutdownCurrentNotebook(page) await page.close() page = null }) @@ -63,11 +62,7 @@ describe("PlutoImportNotebook", () => { // Use the previously defined sum function in the new cell lastPlutoCellId = lastElement(await getCellIds(page)) await writeSingleLineInPlutoInput(page, `pluto-cell[id="${lastPlutoCellId}"] pluto-input`, "sum(2, 3)") - - // Run cells - - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(".runallchanged") + await runAllChanged(page) const lastCellContent = await waitForCellOutput(page, lastPlutoCellId) expect(lastCellContent).toBe("5") }) diff --git a/test/frontend/__tests__/javascript_api.js b/test/frontend/__tests__/javascript_api.js index 6fdefaaa30..252132f37d 100644 --- a/test/frontend/__tests__/javascript_api.js +++ b/test/frontend/__tests__/javascript_api.js @@ -1,145 +1,97 @@ -import puppeteer from "puppeteer"; +import puppeteer from "puppeteer" +import { saveScreenshot, waitForContentToBecome, createPage, paste } from "../helpers/common" import { - waitForContent, - lastElement, - saveScreenshot, - getTestScreenshotPath, - waitForContentToBecome, - setupPage, - paste, - countCells, -} from "../helpers/common"; -import { - createNewNotebook, - getCellIds, - waitForCellOutput, - waitForNoUpdateOngoing, - getPlutoUrl, - prewarmPluto, - waitForCellOutputToChange, - keyboardPressInPlutoInput, - writeSingleLineInPlutoInput, - manuallyEnterCells, -} from "../helpers/pluto"; + createNewNotebook, + waitForNoUpdateOngoing, + getPlutoUrl, + shutdownCurrentNotebook, + setupPlutoBrowser, + waitForPlutoToCalmDown, + runAllChanged, +} from "../helpers/pluto" describe("JavaScript API", () => { - /** - * Launch a shared browser instance for all tests. - * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, - * so I need to manually create the shared browser. - * @type {puppeteer.Browser} - */ - let browser = null; - /** @type {puppeteer.Page} */ - let page = null; - beforeAll(async () => { - browser = await puppeteer.launch({ - headless: process.env.HEADLESS !== "false", - args: ["--no-sandbox", "--disable-setuid-sandbox"], - devtools: false, - }); - - let page = await browser.newPage(); - setupPage(page); - await prewarmPluto(browser, page); - await page.close(); - }); - beforeEach(async () => { - page = await browser.newPage(); - setupPage(page); - await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }); - await createNewNotebook(page); - await page.waitForSelector("pluto-input", { visible: true }); - }); - afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()); - // @ts-ignore - await page.evaluate(() => window.shutdownNotebook?.()); - await page.close(); - page = null; - }); - afterAll(async () => { - await browser.close(); - browser = null; - }); + /** + * Launch a shared browser instance for all tests. + * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, + * so I need to manually create the shared browser. + * @type {puppeteer.Browser} + */ + let browser = null + /** @type {puppeteer.Page} */ + let page = null + beforeAll(async () => { + browser = await setupPlutoBrowser() + }) + beforeEach(async () => { + page = await createPage(browser) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + await createNewNotebook(page) + }) + afterEach(async () => { + await saveScreenshot(page) + await shutdownCurrentNotebook(page) + await page.close() + page = null + }) + afterAll(async () => { + await browser.close() + browser = null + }) - it("⭐️ If you return an HTML node, it will be displayed.", async () => { - const expected = "Success"; - paste( - page, - `html"""""" ` - ); - await page.waitForSelector(`.runallchanged`, { - visible: true, - polling: 200, - timeout: 0, - }); - await page.click(`.runallchanged`); - await waitForNoUpdateOngoing(page, { polling: 100 }); - const initialLastCellContent = await waitForContentToBecome( - page, - `pluto-cell:last-child pluto-output`, - expected - ); - expect(initialLastCellContent).toBe(expected); - }); + ) + await runAllChanged(page) + await waitForPlutoToCalmDown(page, { polling: 100 }) + const initialLastCellContent = await waitForContentToBecome(page, `pluto-cell:last-child pluto-output`, expected) + expect(initialLastCellContent).toBe(expected) + }) - it("⭐️ The observablehq/stdlib library is pre-imported, you can use DOM, html, Promises, etc.", async () => { - const expected = "Success"; - paste( - page, - `html"""""" ` - ); - await page.waitForSelector(`.runallchanged`, { - visible: true, - polling: 200, - timeout: 0, - }); - await page.click(`.runallchanged`); - await waitForNoUpdateOngoing(page, { polling: 100 }); - let initialLastCellContent = await waitForContentToBecome( - page, - `pluto-cell:last-child pluto-output`, - expected - ); - expect(initialLastCellContent).toBe(expected); + ) + await runAllChanged(page) + await waitForPlutoToCalmDown(page, { polling: 100 }) + let initialLastCellContent = await waitForContentToBecome(page, `pluto-cell:last-child pluto-output`, expected) + expect(initialLastCellContent).toBe(expected) - paste( - page, - `html"""""" ` - ); - await page.waitForSelector(`.runallchanged`, { - visible: true, - polling: 200, - timeout: 0, - }); - await page.click(`.runallchanged`); - await waitForNoUpdateOngoing(page, { polling: 100 }); - initialLastCellContent = await waitForContentToBecome( - page, - `pluto-cell:last-child pluto-output`, - expected - ); - expect(initialLastCellContent).toBe(expected); - }); + ) + await runAllChanged(page) + await waitForPlutoToCalmDown(page, { polling: 100 }) + initialLastCellContent = await waitForContentToBecome(page, `pluto-cell:last-child pluto-output`, expected) + expect(initialLastCellContent).toBe(expected) + }) - it("⭐️ When a cell re-runs reactively, this will be set to the previous output", async () => { - paste( - page, - ` + it("⭐️ When a cell re-runs reactively, this will be set to the previous output", async () => { + await paste( + page, + ` # ╔═╡ 90cfa9a0-114d-49bf-8dea-e97d58fa2442 @bind v html"""emitter""" @@ -157,69 +109,47 @@ describe("JavaScript API", () => { # ╔═╡ cdb22342-4b79-4efe-bc2e-9edc61a0fef9 v ` - ); - await page.waitForSelector(`.runallchanged`, { - visible: true, - polling: 200, - timeout: 0, - }); - await page.click(`.runallchanged`); - await waitForNoUpdateOngoing(page, { polling: 100 }); - await waitForContentToBecome( - page, - `pluto-cell:nth-child(2) pluto-output`, - "emitter" - ); - page.waitForTimeout(2000); + ) + await runAllChanged(page) + await waitForPlutoToCalmDown(page, { polling: 100 }) + await waitForContentToBecome(page, `pluto-cell:nth-child(2) pluto-output`, "emitter") + page.waitForTimeout(2000) - // Send a custom event to increment value - // Due to various optimizations this will take its time - const incrementT = async () => - await page.evaluate(() => { - const span = document.querySelector(`#emit-from-here`); - span.value = (span.value || 0) + 1; - span.dispatchEvent(new CustomEvent("input")); - return span.value; - }); - // Wait until you see the value. - // Only then you know reactivity reacted (and did not defer!) - const waitV = async (t) => - await waitForContentToBecome( - page, - `pluto-cell:last-child pluto-output`, - `${t}` - ); + // Send a custom event to increment value + // Due to various optimizations this will take its time + const incrementT = async () => + await page.evaluate(() => { + const span = document.querySelector(`#emit-from-here`) + span.value = (span.value || 0) + 1 + span.dispatchEvent(new CustomEvent("input")) + return span.value + }) + // Wait until you see the value. + // Only then you know reactivity reacted (and did not defer!) + const waitV = async (t) => await waitForContentToBecome(page, `pluto-cell:last-child pluto-output`, `${t}`) - let t = await incrementT(); - await waitV(t); + let t = await incrementT() + await waitV(t) - t = await incrementT(); - await waitV(t); + t = await incrementT() + await waitV(t) - t = await incrementT(); - await waitV(t); + t = await incrementT() + await waitV(t) - await waitForNoUpdateOngoing(page, { polling: 100 }); - await waitForContentToBecome( - page, - `pluto-cell:nth-child(2) pluto-output`, - "emitter" - ); + await waitForNoUpdateOngoing(page, { polling: 100 }) + await waitForContentToBecome(page, `pluto-cell:nth-child(2) pluto-output`, "emitter") - const result = await page.evaluate(() => { - // The script tag won't be in the DOM. The return'ed span will - const results = document.querySelector("#test-id-2")._results; - return ( - results[0] == null && - results[2] === results[1] && - results[1] === results[3] - ); - }); - expect(result).toBe(true); // else will timout - }); + const result = await page.evaluate(() => { + // The script tag won't be in the DOM. The return'ed span will + const results = document.querySelector("#test-id-2")._results + return results[0] == null && results[2] === results[1] && results[1] === results[3] + }) + expect(result).toBe(true) // else will timout + }) - // TODO - // it("⭐️The variable invalidation is a Promise that will get resolved when the cell output is changed or removed.", async () => { - // expect("this").toBe("implemented") - // }) -}); + // TODO + // it("⭐️The variable invalidation is a Promise that will get resolved when the cell output is changed or removed.", async () => { + // expect("this").toBe("implemented") + // }) +}) diff --git a/test/frontend/__tests__/new_notebook_test.js b/test/frontend/__tests__/new_notebook_test.js index 67c6556a61..87f0a6f935 100644 --- a/test/frontend/__tests__/new_notebook_test.js +++ b/test/frontend/__tests__/new_notebook_test.js @@ -1,31 +1,20 @@ import puppeteer from "puppeteer" -import { waitForContent, lastElement, saveScreenshot, getTestScreenshotPath, waitForContentToBecome, setupPage } from "../helpers/common" +import { waitForContent, lastElement, saveScreenshot, waitForContentToBecome, createPage } from "../helpers/common" import { createNewNotebook, getCellIds, - waitForCellOutput, - waitForNoUpdateOngoing, getPlutoUrl, - prewarmPluto, waitForCellOutputToChange, keyboardPressInPlutoInput, writeSingleLineInPlutoInput, + shutdownCurrentNotebook, + setupPlutoBrowser, + waitForPlutoToCalmDown, + manuallyEnterCells, + runAllChanged, + clearPlutoInput, } from "../helpers/pluto" -const manuallyEnterCells = async (page, cells) => { - const plutoCellIds = [] - for (const cell of cells) { - const plutoCellId = lastElement(await getCellIds(page)) - plutoCellIds.push(plutoCellId) - await page.waitForSelector(`pluto-cell[id="${plutoCellId}"] pluto-input .cm-content`) - await writeSingleLineInPlutoInput(page, `pluto-cell[id="${plutoCellId}"] pluto-input`, cell) - - await page.click(`pluto-cell[id="${plutoCellId}"] .add_cell.after`) - await page.waitForFunction((nCells) => document.querySelectorAll("pluto-cell").length === nCells, {}, plutoCellIds.length + 1) - } - return plutoCellIds -} - describe("PlutoNewNotebook", () => { /** * Launch a shared browser instance for all tests. @@ -37,28 +26,16 @@ describe("PlutoNewNotebook", () => { /** @type {puppeteer.Page} */ let page = null beforeAll(async () => { - browser = await puppeteer.launch({ - headless: process.env.HEADLESS !== "false", - args: ["--no-sandbox", "--disable-setuid-sandbox"], - devtools: false, - }) - - let page = await browser.newPage() - setupPage(page) - await prewarmPluto(browser, page) - await page.close() + browser = await setupPlutoBrowser() }) beforeEach(async () => { - page = await browser.newPage() - setupPage(page) + page = await createPage(browser) await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) await createNewNotebook(page) - await page.waitForSelector("pluto-input", { visible: true }) }) afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()) - // @ts-ignore - await page.evaluate(() => window.shutdownNotebook?.()) + await saveScreenshot(page) + await shutdownCurrentNotebook(page) await page.close() page = null }) @@ -67,12 +44,6 @@ describe("PlutoNewNotebook", () => { browser = null }) - it("should create new notebook", async () => { - // A pluto-input should exist in a new notebook - const plutoInput = await page.evaluate(() => document.querySelector("pluto-input")) - expect(plutoInput).not.toBeNull() - }) - it("should run a single cell", async () => { const cellInputSelector = "pluto-input .cm-content" await page.waitForSelector(cellInputSelector) @@ -84,24 +55,12 @@ describe("PlutoNewNotebook", () => { const content = await waitForContent(page, "pluto-output") expect(content).toBe("2") - }) - it("should run multiple cells", async () => { - const cells = ["a = 1", "b = 2", "c = 3", "a + b + c"] - const plutoCellIds = await manuallyEnterCells(page, cells) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - await waitForNoUpdateOngoing(page, { polling: 100 }) - const content = await waitForContentToBecome(page, `pluto-cell[id="${plutoCellIds[3]}"] pluto-output`, "6") - expect(content).toBe("6") - }) + await clearPlutoInput(page, "pluto-input") - it("should reactively re-evaluate dependent cells", async () => { const cells = ["a = 1", "b = 2", "c = 3", "a + b + c"] const plutoCellIds = await manuallyEnterCells(page, cells) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - await waitForNoUpdateOngoing(page, { polling: 100 }) + await runAllChanged(page) const initialLastCellContent = await waitForContentToBecome(page, `pluto-cell[id="${plutoCellIds[3]}"] pluto-output`, "6") expect(initialLastCellContent).toBe("6") diff --git a/test/frontend/__tests__/paste_test.disabled b/test/frontend/__tests__/paste_test.disabled index a61e600e36..5adde25082 100644 --- a/test/frontend/__tests__/paste_test.disabled +++ b/test/frontend/__tests__/paste_test.disabled @@ -14,13 +14,14 @@ import { createNewNotebook, getCellIds, waitForCellOutput, - waitForNoUpdateOngoing, + waitForPlutoToCalmDown, getPlutoUrl, prewarmPluto, waitForCellOutputToChange, keyboardPressInPlutoInput, writeSingleLineInPlutoInput, manuallyEnterCells, + shutdownCurrentNotebook, } from "../helpers/pluto" describe("Paste Functionality", () => { @@ -36,16 +37,14 @@ describe("Paste Functionality", () => { }) afterEach(async () => { - await saveScreenshot(page, getTestScreenshotPath()) - await page.evaluate(() => window.shutdownNotebook()) + await saveScreenshot(page) + await shutdownCurrentNotebook(page) }) it("should *not* create new cell when you paste code into cell", async () => { const cells = ["a = 1", "b = 2", "c = 3", "a + b + c"] const plutoCellIds = await manuallyEnterCells(page, cells) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - await waitForNoUpdateOngoing(page, { polling: 100 }) + await runAllChanged(page) const initialLastCellContent = await waitForContentToBecome(page, `pluto-cell[id="${plutoCellIds[3]}"] pluto-output`, "6") expect(initialLastCellContent).toBe("6") @@ -74,9 +73,7 @@ describe("Paste Functionality", () => { it("should create new cell when you paste cell into page", async () => { const cells = ["a = 1", "b = 2", "c = 3", "a + b + c"] const plutoCellIds = await manuallyEnterCells(page, cells) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - await waitForNoUpdateOngoing(page, { polling: 100 }) + await runAllChanged(page) const initialLastCellContent = await waitForContentToBecome(page, `pluto-cell[id="${plutoCellIds[3]}"] pluto-output`, "6") expect(initialLastCellContent).toBe("6") @@ -116,9 +113,7 @@ describe("Paste Functionality", () => { it("should create new cell when you paste cell into cell", async () => { const cells = ["a = 1", "b = 2", "c = 3", "a + b + c"] const plutoCellIds = await manuallyEnterCells(page, cells) - await page.waitForSelector(`.runallchanged`, { visible: true, polling: 200, timeout: 0 }) - await page.click(`.runallchanged`) - await waitForNoUpdateOngoing(page, { polling: 100 }) + await runAllChanged(page) const initialLastCellContent = await waitForContentToBecome(page, `pluto-cell[id="${plutoCellIds[3]}"] pluto-output`, "6") expect(initialLastCellContent).toBe("6") diff --git a/test/frontend/__tests__/published_to_js.js b/test/frontend/__tests__/published_to_js.js new file mode 100644 index 0000000000..7ab4940115 --- /dev/null +++ b/test/frontend/__tests__/published_to_js.js @@ -0,0 +1,48 @@ +import puppeteer from "puppeteer" +import { saveScreenshot, createPage } from "../helpers/common" +import { importNotebook, getPlutoUrl, shutdownCurrentNotebook, setupPlutoBrowser } from "../helpers/pluto" + +describe("published_to_js", () => { + /** + * Launch a shared browser instance for all tests. + * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, + * so I need to manually create the shared browser. + * @type {puppeteer.Browser} + */ + let browser = null + /** @type {puppeteer.Page} */ + let page = null + beforeAll(async () => { + browser = await setupPlutoBrowser() + }) + beforeEach(async () => { + page = await createPage(browser) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + }) + afterEach(async () => { + await saveScreenshot(page) + await shutdownCurrentNotebook(page) + await page.close() + page = null + }) + afterAll(async () => { + await browser.close() + browser = null + }) + + it("Should correctly show published_to_js in cell output, and in logs", async () => { + await importNotebook(page, "published_to_js.jl", { timeout: 120 * 1000 }) + + let output_of_published = await page.evaluate(() => { + return document.querySelector("#to_cell_output")?.textContent + }) + expect(output_of_published).toBe("[1,2,3] MAGIC!") + + // The log content is not shown, so #to_cell_log does not exist + let log_of_published = await page.evaluate(() => { + return document.querySelector("#to_cell_log")?.textContent + }) + // This test is currently broken, due to https://github.com/fonsp/Pluto.jl/issues/2092 + expect(log_of_published).toBe("[4,5,6] MAGIC!") + }) +}) diff --git a/test/frontend/__tests__/safe_preview.js b/test/frontend/__tests__/safe_preview.js new file mode 100644 index 0000000000..b6c8995371 --- /dev/null +++ b/test/frontend/__tests__/safe_preview.js @@ -0,0 +1,248 @@ +import puppeteer from "puppeteer" +import { saveScreenshot, createPage, paste, clickAndWaitForNavigation } from "../helpers/common" +import { + importNotebook, + getPlutoUrl, + shutdownCurrentNotebook, + setupPlutoBrowser, + waitForPlutoToCalmDown, + restartProcess, + getCellIds, + clearPlutoInput, + writeSingleLineInPlutoInput, + runAllChanged, + openPathOrURLNotebook, + getAllCellOutputs, +} from "../helpers/pluto" + +describe("safe_preview", () => { + /** + * Launch a shared browser instance for all tests. + * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, + * so I need to manually create the shared browser. + * @type {puppeteer.Browser} + */ + let browser = null + /** @type {puppeteer.Page} */ + let page = null + beforeAll(async () => { + browser = await setupPlutoBrowser() + }) + beforeEach(async () => { + page = await createPage(browser) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + }) + afterEach(async () => { + await saveScreenshot(page) + await shutdownCurrentNotebook(page) + await page.close() + page = null + }) + afterAll(async () => { + await browser.close() + browser = null + }) + + const expect_safe_preview = async (/** @type {puppeteer.Page} */ page) => { + await waitForPlutoToCalmDown(page) + expect(await page.evaluate(() => window.I_DID_SOMETHING_DANGEROUS)).toBeUndefined() + expect(await page.evaluate(() => [...document.body.classList])).toContain("process_waiting_for_permission") + expect(await page.evaluate(() => document.querySelector("a#restart-process-button"))).not.toBeNull() + expect(await page.evaluate(() => document.querySelector(".safe-preview-info"))).not.toBeNull() + } + + it("Pasting notebook contents should open in safe preview", async () => { + await Promise.all([ + page.waitForNavigation(), + paste( + page, + `### A Pluto.jl notebook ### +# v0.14.0 + +using Markdown +using InteractiveUtils + +# ╔═╡ b2d786ec-7f73-11ea-1a0c-f38d7b6bbc1e +md""" +Hello +""" + +# ╔═╡ b2d79330-7f73-11ea-0d1c-a9aad1efaae1 +1 + 2 + +# ╔═╡ Cell order: +# ╟─b2d786ec-7f73-11ea-1a0c-f38d7b6bbc1e +# ╠═b2d79330-7f73-11ea-0d1c-a9aad1efaae1 +` + ), + ]) + await expect_safe_preview(page) + }) + + it("Notebook from URL source", async () => { + const url = "https://raw.githubusercontent.com/fonsp/Pluto.jl/v0.14.5/sample/Basic.jl" + + await openPathOrURLNotebook(page, url, { permissionToRunCode: false }) + await expect_safe_preview(page) + + let expectWarningMessage = async () => { + await page.waitForSelector(`a#restart-process-button`) + const [dmsg, _] = await Promise.all([ + new Promise((res) => { + page.once("dialog", async (dialog) => { + let msg = dialog.message() + await dialog.dismiss() + res(msg) + }) + }), + page.click(`a#restart-process-button`), + ]) + + expect(dmsg).toContain(url) + expect(dmsg.toLowerCase()).toContain("danger") + expect(dmsg.toLowerCase()).toContain("are you sure") + + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page) + await expect_safe_preview(page) + } + + await expectWarningMessage() + + // Make some edits + expect((await getAllCellOutputs(page))[0]).toContain("Basel problem") + + let sel = `pluto-cell[id="${(await getCellIds(page))[0]}"]` + await page.click(`${sel} .foldcode`) + + await clearPlutoInput(page, sel) + await writeSingleLineInPlutoInput(page, sel, "1 + 1") + await runAllChanged(page) + + expect((await getAllCellOutputs(page))[0]).toBe("Code not executed in Safe preview") + await expect_safe_preview(page) + + ////////////////////////// + // Let's shut it down + // @ts-ignore + let path = await page.evaluate(() => window.editor_state.notebook.path.replaceAll("\\", "\\\\")) + let shutdown = async () => { + await shutdownCurrentNotebook(page) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + // Wait for it to be shut down + await page.waitForSelector(`li.recent a[title="${path}"]`) + } + await shutdown() + + // Run it again + await clickAndWaitForNavigation(page, `a[title="${path}"]`) + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page) + + await expect_safe_preview(page) + await expectWarningMessage() + + //////////////////// + await shutdown() + + // Now let's try to run the notebook in the background. This should start it in safe mode because of the risky source + await page.evaluate((path) => { + let a = document.querySelector(`a[title="${path}"]`) + let btn = a.previousElementSibling + btn.click() + }, path) + + await page.waitForSelector(`li.running a[title="${path}"]`) + await clickAndWaitForNavigation(page, `a[title="${path}"]`) + + await expect_safe_preview(page) + await expectWarningMessage() + + // Let's run it + await Promise.all([ + new Promise((res) => { + page.once("dialog", (dialog) => { + res(dialog.accept()) + }) + }), + page.click(`a#restart-process-button`), + ]) + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page) + + // Nice + expect((await getAllCellOutputs(page))[0]).toBe("2") + + //////////////////// + await shutdown() + + await clickAndWaitForNavigation(page, `a[title="${path}"]`) + + await expect_safe_preview(page) + expect((await getAllCellOutputs(page))[0]).toBe("Code not executed in Safe preview") + + // Since we ran the notebook once, there should be no warning message: + await page.waitForSelector(`a#restart-process-button`) + await page.click(`a#restart-process-button`) + + // If there was a dialog, we would stall right now and the test would fail. + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page) + expect((await getAllCellOutputs(page))[0]).toBe("2") + }) + + it("Importing notebook should open in safe preview", async () => { + await importNotebook(page, "safe_preview.jl", { permissionToRunCode: false }) + await expect_safe_preview(page) + + await waitForPlutoToCalmDown(page) + + let cell_contents = await getAllCellOutputs(page) + + expect(cell_contents[0]).toBe("one") + expect(cell_contents[1]).toBe("Scripts and styles not rendered in Safe preview\n\ni should not be red\n\n\n\ntwo\n\n\nsafe") + expect(cell_contents[2]).toBe("three") + expect(cell_contents[3]).toBe("Code not executed in Safe preview") + expect(cell_contents[4]).toBe("Code not executed in Safe preview") + expect(cell_contents[5]).toContain("yntax") + expect(cell_contents[6]).toBe("") + + expect(await page.evaluate(() => getComputedStyle(document.querySelector(`.zo`)).color)).not.toBe("rgb(255, 0, 0)") + + // Modifying should not execute code + const cellids = await getCellIds(page) + let sel = `pluto-cell[id="${cellids[0]}"] pluto-input` + + let expectNewOutput = async (contents) => { + await clearPlutoInput(page, sel) + await writeSingleLineInPlutoInput(page, sel, contents) + await runAllChanged(page) + return expect((await getAllCellOutputs(page))[0]) + } + + ;(await expectNewOutput(`md"een"`)).toBe("een") + ;(await expectNewOutput(`un`)).toBe("Code not executed in Safe preview") + ;(await expectNewOutput(`md"one"`)).toBe("one") + ;(await expectNewOutput(`a b c function`)).toContain("yntax") + ;(await expectNewOutput(`md"one"`)).toBe("one") + ;(await expectNewOutput(``)).toBe("") + ;(await expectNewOutput(`md"one"`)).toBe("one") + + await restartProcess(page) + await waitForPlutoToCalmDown(page) + + cell_contents = await getAllCellOutputs(page) + + expect(cell_contents[0]).toBe("one") + expect(cell_contents[1]).toBe("\ni should not be red\n\ntwo\nsafe\nDANGER") + expect(cell_contents[2]).toBe("three") + expect(cell_contents[3]).toBe("123") + expect(cell_contents[4]).toBe("") + expect(cell_contents[5]).toContain("yntax") + expect(cell_contents[6]).toBe("") + + expect(await page.evaluate(() => document.querySelector(`pluto-log-dot`).innerText)).toBe("four\nDANGER") + + expect(await page.evaluate(() => getComputedStyle(document.querySelector(`.zo`)).color)).toBe("rgb(255, 0, 0)") + }) +}) diff --git a/test/frontend/__tests__/slide_controls.js b/test/frontend/__tests__/slide_controls.js new file mode 100644 index 0000000000..15a50e07ea --- /dev/null +++ b/test/frontend/__tests__/slide_controls.js @@ -0,0 +1,73 @@ +import puppeteer from "puppeteer" +import { saveScreenshot, createPage, waitForContent } from "../helpers/common" +import { + createNewNotebook, + getCellIds, + getPlutoUrl, + importNotebook, + manuallyEnterCells, + runAllChanged, + setupPlutoBrowser, + shutdownCurrentNotebook, + waitForPlutoToCalmDown, +} from "../helpers/pluto" + +describe("slideControls", () => { + /** + * Launch a shared browser instance for all tests. + * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, + * so I need to manually create the shared browser. + * @type {puppeteer.Browser} + */ + let browser = null + /** @type {puppeteer.Page} */ + let page = null + + beforeAll(async () => { + browser = await setupPlutoBrowser() + }) + beforeEach(async () => { + page = await createPage(browser) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + }) + afterEach(async () => { + await saveScreenshot(page) + await shutdownCurrentNotebook(page) + await page.close() + page = null + }) + afterAll(async () => { + await browser.close() + browser = null + }) + + it("should create titles", async () => { + await importNotebook(page, "slides.jl", { permissionToRunCode: false }) + const plutoCellIds = await getCellIds(page) + const content = await waitForContent(page, `pluto-cell[id="${plutoCellIds[1]}"] pluto-output`) + expect(content).toBe("Slide 2") + + const slide_1_title = await page.$(`pluto-cell[id="${plutoCellIds[0]}"] pluto-output h1`) + const slide_2_title = await page.$(`pluto-cell[id="${plutoCellIds[1]}"] pluto-output h1`) + + expect(await slide_2_title.isIntersectingViewport()).toBe(true) + expect(await slide_1_title.isIntersectingViewport()).toBe(true) + + await page.click(`.toggle_export[title="Export..."]`) + await page.waitForTimeout(500) + await page.waitForSelector(".toggle_presentation", { visible: true }) + await page.click(".toggle_presentation") + + await page.click(".changeslide.next") + expect(await slide_1_title.isIntersectingViewport()).toBe(true) + expect(await slide_2_title.isIntersectingViewport()).toBe(false) + + await page.click(".changeslide.next") + expect(await slide_1_title.isIntersectingViewport()).toBe(false) + expect(await slide_2_title.isIntersectingViewport()).toBe(true) + + await page.click(".changeslide.prev") + expect(await slide_1_title.isIntersectingViewport()).toBe(true) + expect(await slide_2_title.isIntersectingViewport()).toBe(false) + }) +}) diff --git a/test/frontend/__tests__/wind_directions.js b/test/frontend/__tests__/wind_directions.js new file mode 100644 index 0000000000..b7a06bb688 --- /dev/null +++ b/test/frontend/__tests__/wind_directions.js @@ -0,0 +1,111 @@ +import puppeteer from "puppeteer" +import { saveScreenshot, waitForContentToBecome, createPage, paste } from "../helpers/common" +import { + createNewNotebook, + waitForNoUpdateOngoing, + getPlutoUrl, + shutdownCurrentNotebook, + setupPlutoBrowser, + waitForPlutoToCalmDown, + runAllChanged, + importNotebook, +} from "../helpers/pluto" + +describe("wind_directions", () => { + /** + * Launch a shared browser instance for all tests. + * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, + * so I need to manually create the shared browser. + * @type {puppeteer.Browser} + */ + let browser = null + /** @type {puppeteer.Page} */ + let page = null + beforeAll(async () => { + browser = await setupPlutoBrowser() + page = await createPage(browser) + await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) + + await importNotebook(page, "wind_directions.jl", { permissionToRunCode: true, timeout: 180 * 1000 }) + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page) + }) + beforeEach(async () => {}) + afterEach(async () => { + await saveScreenshot(page) + }) + afterAll(async () => { + await shutdownCurrentNotebook(page) + await page.close() + page = null + + await browser.close() + browser = null + }) + + const get_cell_id_that_defines = async (page, variable_name) => { + return await page.evaluate((variable_name) => { + return document.querySelector(`pluto-cell > #${variable_name}`).parentElement.id + }, variable_name) + } + + let button_selector = (variable_name, value) => `pluto-cell[id="${variable_name}"] button[data-value="${value}"]` + let slide_selector = (variable_name, value) => `pluto-cell[id="${variable_name}"] .carousel-slide:nth-child(${value})` + + it("🎠 You can move the carousel", async () => { + const xoxob = await get_cell_id_that_defines(page, "xoxob") + const xoxob_again = await get_cell_id_that_defines(page, "xoxob_again") + + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, -1))).toBe(true) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, 1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, -1))).toBe(true) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, 1))).toBe(false) + + await page.click(button_selector(xoxob, 1)) + await waitForPlutoToCalmDown(page) + + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, -1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, 1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, -1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, 1))).toBe(false) + + await page.click(button_selector(xoxob_again, 1)) + await page.click(button_selector(xoxob_again, 1)) + await waitForPlutoToCalmDown(page) + + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, -1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob, 1))).toBe(true) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, -1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(xoxob_again, 1))).toBe(true) + }) + + it("🎏 Wind directions UI", async () => { + const big_input = await get_cell_id_that_defines(page, "big_input") + + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(big_input, -1))).toBe(true) + expect(await page.evaluate((sel) => document.querySelector(sel).disabled, button_selector(big_input, 1))).toBe(false) + + let checkbox_selector = (i) => `${slide_selector(big_input, 1)} div:nth-child(${i + 1}) > input` + await page.click(checkbox_selector(0)) + await waitForPlutoToCalmDown(page) + + let expect_chosen_directions = async (expected) => { + expect( + await waitForContentToBecome(page, `pluto-cell[id="${await get_cell_id_that_defines(page, "chosen_directions_copy")}"] pluto-output`, expected) + ).toBe(expected) + } + + await expect_chosen_directions('chosen_directions_copy\n"North"') + + expect(await page.evaluate((sel) => document.querySelector(sel).checked, checkbox_selector(0))).toBe(true) + + await page.click(checkbox_selector(2)) + await waitForPlutoToCalmDown(page) + + await expect_chosen_directions('chosen_directions_copy\n"North"\n"South"') + + expect(await page.evaluate((sel) => document.querySelector(sel).checked, checkbox_selector(0))).toBe(true) + expect(await page.evaluate((sel) => document.querySelector(sel).checked, checkbox_selector(1))).toBe(false) + expect(await page.evaluate((sel) => document.querySelector(sel).checked, checkbox_selector(2))).toBe(true) + }) +}) diff --git a/test/frontend/fixtures/published_to_js.jl b/test/frontend/fixtures/published_to_js.jl new file mode 100644 index 0000000000..1e8356e57c --- /dev/null +++ b/test/frontend/fixtures/published_to_js.jl @@ -0,0 +1,50 @@ +### A Pluto.jl notebook ### +# v0.19.27 + +using Markdown +using InteractiveUtils + +# ╔═╡ 2d69377e-23f8-11ee-116b-fb6a8f328528 +begin + using Pkg + Pkg.activate(temp=true) + # the latest versions of these packages: + Pkg.add(url="https://github.com/JuliaPluto/AbstractPlutoDingetjes.jl", rev="main") + Pkg.add("HypertextLiteral") +end + +# ╔═╡ 2ea26a4b-2d1e-4bcb-8b7b-cace79f7926a +begin + using AbstractPlutoDingetjes.Display: published_to_js + using HypertextLiteral +end + +# ╔═╡ 043829fc-af3a-40b9-bb4f-f848ab50eb25 +a = [1,2,3]; + +# ╔═╡ 2f4609fd-7361-4048-985a-2cc74bb25606 +@htl """ + +""" + +# ╔═╡ 28eba9fd-0416-49b8-966e-03a381c19ca7 +b = [4,5,6]; + +# ╔═╡ 0a4e8a19-6d43-4161-bb8c-1ebf8f8f68ba +@info @htl """ + +""" + +# ╔═╡ Cell order: +# ╠═2d69377e-23f8-11ee-116b-fb6a8f328528 +# ╠═2ea26a4b-2d1e-4bcb-8b7b-cace79f7926a +# ╠═043829fc-af3a-40b9-bb4f-f848ab50eb25 +# ╠═2f4609fd-7361-4048-985a-2cc74bb25606 +# ╠═28eba9fd-0416-49b8-966e-03a381c19ca7 +# ╠═0a4e8a19-6d43-4161-bb8c-1ebf8f8f68ba diff --git a/test/frontend/fixtures/safe_preview.jl b/test/frontend/fixtures/safe_preview.jl new file mode 100644 index 0000000000..ffc7439aef --- /dev/null +++ b/test/frontend/fixtures/safe_preview.jl @@ -0,0 +1,65 @@ +### A Pluto.jl notebook ### +# v0.19.29 + +using Markdown +using InteractiveUtils + +# ╔═╡ e28131d9-9877-4b44-8213-9e6c041b5da5 +md""" +one +""" + +# ╔═╡ ef63b97e-700d-11ee-2997-7bf929019c2d +[[html""" +
+i should not be red +
+ +two + +
safe
+ + + + + + +"""]] + +# ╔═╡ 99e2bfea-4e5d-4d94-bd96-77be7b04811d +html"three" + +# ╔═╡ 76e68adf-16ab-4e88-a601-3177f34db6ec +122 + 1 + +# ╔═╡ 873d58c2-8590-4bb3-bf9c-596b1cdbe402 +let + stuff = html""" +four +""" + @info stuff +end + +# ╔═╡ 55c74b79-41a6-461e-99c4-a61994673824 +modify me to make me safe + +# ╔═╡ f5209e95-761d-4861-a00d-b7e33a1b3d69 + + +# ╔═╡ Cell order: +# ╠═e28131d9-9877-4b44-8213-9e6c041b5da5 +# ╠═ef63b97e-700d-11ee-2997-7bf929019c2d +# ╠═99e2bfea-4e5d-4d94-bd96-77be7b04811d +# ╠═76e68adf-16ab-4e88-a601-3177f34db6ec +# ╠═873d58c2-8590-4bb3-bf9c-596b1cdbe402 +# ╠═55c74b79-41a6-461e-99c4-a61994673824 +# ╠═f5209e95-761d-4861-a00d-b7e33a1b3d69 diff --git a/test/frontend/fixtures/slides.jl b/test/frontend/fixtures/slides.jl new file mode 100644 index 0000000000..d903c7dce1 --- /dev/null +++ b/test/frontend/fixtures/slides.jl @@ -0,0 +1,23 @@ +### A Pluto.jl notebook ### +# v0.11.14 + +using Markdown +using InteractiveUtils + +# ╔═╡ cbcf36de-f360-11ea-0c7f-719e93324b27 +md"# Slide 1" + +# ╔═╡ d71c5ee2-f360-11ea-2753-a132fa41871a +md"# Slide 2" + +# ╔═╡ d8f5a4f6-f360-11ea-043d-47667f6a7e76 + + +# ╔═╡ dcd9ebb8-f360-11ea-2050-fd2e11d27c6d + + +# ╔═╡ Cell order: +# ╠═cbcf36de-f360-11ea-0c7f-719e93324b27 +# ╠═d71c5ee2-f360-11ea-2753-a132fa41871a +# ╠═d8f5a4f6-f360-11ea-043d-47667f6a7e76 +# ╠═dcd9ebb8-f360-11ea-2050-fd2e11d27c6d diff --git a/test/frontend/fixtures/wind_directions.jl b/test/frontend/fixtures/wind_directions.jl new file mode 100644 index 0000000000..7f3d48f700 --- /dev/null +++ b/test/frontend/fixtures/wind_directions.jl @@ -0,0 +1,936 @@ +### A Pluto.jl notebook ### +# v0.19.31 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═╡ 2e54b8fc-7852-11ec-27d7-df0bfe7f344a +using PlutoUI + +# ╔═╡ 257ee9b0-d955-43d2-9c94-245716708a2d +using HypertextLiteral + +# ╔═╡ 82c316c7-a279-4728-b16a-921d7fc52886 + + +# ╔═╡ 0b19e53d-eb7a-42b6-a7db-d95bc8c63eae +import MarkdownLiteral: @mdx + +# ╔═╡ 0c0bab41-a020-41a0-83ad-0c57b4699ffa +const Layout = PlutoUI.ExperimentalLayout + +# ╔═╡ c097b477-e154-47eb-b7d9-a4d2981dcf0e +padded(x) = Layout.Div([x]; style=Dict("padding" => "0em 1em")) + +# ╔═╡ ddccf592-0d0f-475c-81ae-067c37ba3f7e +const all_directions = ["North", "East", "South", "West"] + +# ╔═╡ d441b495-a00c-4de3-a232-7c75f55fc95b +function Carousel2( + elementsList; + wraparound::Bool=false, + peek::Bool=true, + ) + + @assert peek + + carouselHTML = map(elementsList) do element + Layout.Div([element]; class="carousel-slide") + end + + h = Layout.Div([ + @htl(""" + + """), + + Layout.Div([ + Layout.Div(carouselHTML; class="carousel-container") + ]; class="carousel-box"), + @htl(""" + + """), + @htl(""" + + """), + ]; class="carousel-wrapper") + + # BondDefault(h,1) + h +end + +# ╔═╡ fa0b6647-6911-4c27-a1a6-240d215331d1 +function Carousel( + elementsList; + wraparound::Bool=false, + peek::Bool=true, + ) + + @assert peek + + carouselHTML = map(elementsList) do element + @htl("""""") + end + + h = @htl(""" +
+ + + + + + + +
+ """) + + # BondDefault(h,1) + h +end + +# ╔═╡ 6c84a84f-9ead-4091-819e-0de088e2dd4d +function wind_speeds(directions) + PlutoUI.combine() do Child + @htl(""" +
Wind speeds
+
    + $([ + @htl("
  • $(name): $(Child(name, Slider(1:100)))
  • ") + for name in directions + ]) +
+ """) + end +end + + +# ╔═╡ e866282e-7c63-4364-b344-46f4c6ad165c +dogscats() = PlutoUI.combine() do Child + md""" + # Hi there! + + I have $( + Child(Slider(1:10)) + ) dogs and $( + Child(Slider(5:100)) + ) cats. + + Would you like to see them? $(Child(CheckBox(true))) + """ +end + +# ╔═╡ cd3b9ad1-8efc-4f92-96d0-b9b038d8cfae +md""" +## MultiCheckBox copy + +This is a version of MultiCheckBox from PlutoUI that did not support synchronizing multiple bonds, i.e. it doesn't have `Object.defineProperty(wrapper, "input", {get, set})`. + +This means that this won't work be synced: + +```julia +bond = @bind value MultiCheckbox([1,2]) +``` + +```julia +bond +``` + +We need this for the test to be extra sensitive. +""" + +# ╔═╡ 79b6ac0f-4d0b-485f-8fb0-9849932dc34e +import AbstractPlutoDingetjes.Bonds + +# ╔═╡ eaad4fed-ea22-4132-a84a-429f486ddce2 +subarrays(x) = ( + x[collect(I)] + for I in Iterators.product(Iterators.repeated([true,false],length(x))...) |> collect |> vec +) + +# ╔═╡ 146474b5-9aa6-4000-867d-ba91e4061d9b +begin + local result = begin + """ + ```julia + MultiCheckBox(options::Vector; [default::Vector], [orientation ∈ [:row, :column]], [select_all::Bool]) + ``` + + A group of checkboxes - the user can choose which of the `options` to return. + The value returned via `@bind` is a list containing the currently checked items. + + See also: [`MultiSelect`](@ref). + + `options` can also be an array of pairs `key::Any => value::String`. The `key` is returned via `@bind`; the `value` is shown. + + # Keyword arguments + - `defaults` specifies which options should be checked initally. + - `orientation` specifies whether the options should be arranged in `:row`'s `:column`'s. + - `select_all` specifies whether or not to include a "Select All" checkbox. + + # Examples + ```julia + @bind snacks MultiCheckBox(["🥕", "🐟", "🍌"])) + + if "🥕" ∈ snacks + "Yum yum!" + end + ``` + + ```julia + @bind functions MultiCheckBox([sin, cos, tan]) + + [f(0.5) for f in functions] + ``` + + ```julia + @bind snacks MultiCheckBox(["🥕" => "🐰", "🐟" => "🐱", "🍌" => "🐵"]; default=["🥕", "🍌"]) + ``` + + ```julia + @bind animals MultiCheckBox(["🐰", "🐱" , "🐵", "🐘", "🦝", "🐿️" , "🐝", "🐪"]; orientation=:column, select_all=true) + ``` + """ + struct MultiCheckBox{BT,DT} + options::AbstractVector{Pair{BT,DT}} + default::Union{Missing,AbstractVector{BT}} + orientation::Symbol + select_all::Bool + end + end + + MultiCheckBox(options::AbstractVector{<:Pair{BT,DT}}; default=missing, orientation=:row, select_all=false) where {BT,DT} = MultiCheckBox(options, default, orientation, select_all) + + MultiCheckBox(options::AbstractVector{BT}; default=missing, orientation=:row, select_all=false) where BT = MultiCheckBox{BT,BT}(Pair{BT,BT}[o => o for o in options], default, orientation, select_all) + + function Base.show(io::IO, m::MIME"text/html", mc::MultiCheckBox) + @assert mc.orientation == :column || mc.orientation == :row "Invalid orientation $(mc.orientation). Orientation should be :row or :column" + + defaults = coalesce(mc.default, []) + + # Old: + # checked = [k in defaults for (k,v) in mc.options] + # + # More complicated to fix https://github.com/JuliaPluto/PlutoUI.jl/issues/106 + defaults_copy = copy(defaults) + checked = [ + let + i = findfirst(isequal(k), defaults_copy) + if i === nothing + false + else + deleteat!(defaults_copy, i) + true + end + end + for (k,v) in mc.options] + + show(io, m, @htl(""" + + + + """)) + end + + Base.get(select::MultiCheckBox) = Bonds.initial_value(select) + Bonds.initial_value(select::MultiCheckBox{BT,DT}) where {BT,DT} = + ismissing(select.default) ? BT[] : select.default + Bonds.possible_values(select::MultiCheckBox) = + subarrays(map(string, 1:length(select.options))) + + function Bonds.transform_value(select::MultiCheckBox{BT,DT}, val_from_js) where {BT,DT} + # val_from_js will be a vector of Strings, but let's allow Integers as well, there's no harm in that + @assert val_from_js isa Vector + + val_nums = ( + v isa Integer ? v : tryparse(Int64, v) + for v in val_from_js + ) + + BT[select.options[v].first for v in val_nums] + end + + function Bonds.validate_value(select::MultiCheckBox, val) + val isa Vector && all(val_from_js) do v + val_num = v isa Integer ? v : tryparse(Int64, v) + 1 ≤ val_num ≤ length(select.options) + end + end + result +end + +# ╔═╡ 67e2cb97-e224-47ca-96ba-2e89d94959e7 +ppp = @bind opop Slider(1:10); + +# ╔═╡ b1c0d12c-f383-44fb-bcfe-4157a2801b9a +Layout.Div([ + ppp, + @htl("""$(opop)""") +]) + +# ╔═╡ a060f034-b540-4b1e-a87f-7e6185e15646 +directions_bond = @bind chosen_directions MultiCheckBox(all_directions); + +# ╔═╡ 466bf852-144c-47df-98e1-89935754f5f1 +chosen_directions_copy = chosen_directions + +# ╔═╡ 6e26a930-1b49-4ff5-8704-9149d3cab7e9 +speeds_bond = @bind speeds wind_speeds(chosen_directions); + +# ╔═╡ ede20024-1aea-4d80-a19a-8a5ec88a00ac +data = map(speeds) do s + rand(50) .+ s +end + +# ╔═╡ acb08d1f-30f9-4e01-8216-3440c82714c7 +pairs(speeds) |> collect + +# ╔═╡ fffd6402-d508-48a6-abc6-3de333497787 +big_input = Carousel2([ + md""" + ## Step 1: *directions* + $(directions_bond) + """ |> identity, + + md""" + ## Step 2: *speeds* + $(speeds_bond) + """ |> identity, + + md""" + ## Step 3: 🎉 + $(embed_display( + data + )) + """ |> identity, + + # md""" + # ## Step 4: 📉 + # $(embed_display( + # let + # p = plot() + + # for (n,v) in pairs(data) + # plot!(p, v; label=string(n)) + # end + # p + # end + # )) + # """ |> padded, +]) + +# ╔═╡ 0cb7b599-cec5-4391-9485-4e1c63cd9ff2 +speeds_copy = speeds + +# ╔═╡ ab108b97-4dd5-49e4-845c-2f0fab131f8a +Layout.vbox([ + directions_bond, + speeds_bond, + speeds +]) + +# ╔═╡ 596dbead-63ce-432a-8a0b-b3ea361e279e +xoxob = @bind xoxo Carousel2([md"# a",md"# b",3,rand(4)]) + +# ╔═╡ 8c96934c-3e23-45ed-b945-dce344bfb6eb +xoxob_again = xoxob + +# ╔═╡ af1ad32b-af53-4865-9807-ba8d0fba2a8c +xoxo + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150" +HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +MarkdownLiteral = "736d6165-7244-6769-4267-6b50796e6954" +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" + +[compat] +AbstractPlutoDingetjes = "~1.2.0" +HypertextLiteral = "~0.9.4" +MarkdownLiteral = "~0.1.1" +PlutoUI = "~0.7.52" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "91bd53c39b9cbfb5ef4b015e8b582d344532bd0a" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.2.0" + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.4" + +[[CommonMark]] +deps = ["Crayons", "JSON", "PrecompileTools", "URIs"] +git-tree-sha1 = "532c4185d3c9037c0237546d817858b23cf9e071" +uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +version = "0.8.12" + +[[Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[Downloads]] +deps = ["ArgTools", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" + +[[FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.4" + +[[HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.4" + +[[IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.3" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" + +[[LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[LinearAlgebra]] +deps = ["Libdl"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[MIMEs]] +git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" +uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +version = "0.1.4" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MarkdownLiteral]] +deps = ["CommonMark", "HypertextLiteral"] +git-tree-sha1 = "0d3fa2dd374934b62ee16a4721fe68c418b92899" +uuid = "736d6165-7244-6769-4267-6b50796e6954" +version = "0.1.1" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + +[[Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "716e24b21538abc91f6205fd1d8363f39b442851" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.7.2" + +[[Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] +git-tree-sha1 = "e47cd150dbe0443c3a3651bc5b9cbd5576ab75b7" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.52" + +[[PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.0" + +[[Preferences]] +deps = ["TOML"] +git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.1" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[[Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" + +[[Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[Tricks]] +git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.8" + +[[URIs]] +git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.5.1" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" + +[[p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +""" + +# ╔═╡ Cell order: +# ╠═67e2cb97-e224-47ca-96ba-2e89d94959e7 +# ╠═b1c0d12c-f383-44fb-bcfe-4157a2801b9a +# ╠═82c316c7-a279-4728-b16a-921d7fc52886 +# ╠═ede20024-1aea-4d80-a19a-8a5ec88a00ac +# ╠═acb08d1f-30f9-4e01-8216-3440c82714c7 +# ╠═c097b477-e154-47eb-b7d9-a4d2981dcf0e +# ╠═0b19e53d-eb7a-42b6-a7db-d95bc8c63eae +# ╠═2e54b8fc-7852-11ec-27d7-df0bfe7f344a +# ╠═0c0bab41-a020-41a0-83ad-0c57b4699ffa +# ╠═257ee9b0-d955-43d2-9c94-245716708a2d +# ╟─ddccf592-0d0f-475c-81ae-067c37ba3f7e +# ╠═fffd6402-d508-48a6-abc6-3de333497787 +# ╠═a060f034-b540-4b1e-a87f-7e6185e15646 +# ╠═466bf852-144c-47df-98e1-89935754f5f1 +# ╠═6e26a930-1b49-4ff5-8704-9149d3cab7e9 +# ╠═0cb7b599-cec5-4391-9485-4e1c63cd9ff2 +# ╠═ab108b97-4dd5-49e4-845c-2f0fab131f8a +# ╠═596dbead-63ce-432a-8a0b-b3ea361e279e +# ╠═8c96934c-3e23-45ed-b945-dce344bfb6eb +# ╠═af1ad32b-af53-4865-9807-ba8d0fba2a8c +# ╠═d441b495-a00c-4de3-a232-7c75f55fc95b +# ╟─fa0b6647-6911-4c27-a1a6-240d215331d1 +# ╟─6c84a84f-9ead-4091-819e-0de088e2dd4d +# ╟─e866282e-7c63-4364-b344-46f4c6ad165c +# ╟─cd3b9ad1-8efc-4f92-96d0-b9b038d8cfae +# ╠═79b6ac0f-4d0b-485f-8fb0-9849932dc34e +# ╟─eaad4fed-ea22-4132-a84a-429f486ddce2 +# ╟─146474b5-9aa6-4000-867d-ba91e4061d9b +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/test/frontend/helpers/common.js b/test/frontend/helpers/common.js index 3e45ea4ac8..c0578974b4 100644 --- a/test/frontend/helpers/common.js +++ b/test/frontend/helpers/common.js @@ -1,7 +1,68 @@ +import puppeteer from "puppeteer" import path from "path"; import mkdirp from "mkdirp"; import * as process from "process"; +// from https://github.com/puppeteer/puppeteer/issues/1908#issuecomment-380308269 +class InflightRequests { + constructor(page) { + this._page = page; + this._requests = new Map(); + this._history = []; + this._onStarted = this._onStarted.bind(this); + this._onFinished = this._onFinished.bind(this); + this._page.on('request', this._onStarted); + this._page.on('requestfinished', this._onFinished); + this._page.on('requestfailed', this._onFinished); + } + + _onStarted(request) { + // if(request.url().includes("data")) { + // console.log('Start', request.url()) + // }; + this._history.push(["started", request.url()]); + this._requests.set( + request.url(), + 1 + (this._requests.get(request.url()) ?? 0) + ); + } + _onFinished(request) { + // if(request.url().includes("data")) { + // console.log('Finish', request.url()) + // }; + this._history.push(["finished", request.url()]); + this._requests.set( + request.url(), + -1 + + /* Multiple requests starts can have a single finish event. */ + Math.min(1, this._requests.get(request.url()) ?? 0) + ); + } + + inflightRequests() { return Array.from([...this._requests.entries()].flatMap(([k,v]) => v > 0 ? [k] : [])); } + + dispose() { + this._page.removeListener('request', this._onStarted); + this._page.removeListener('requestfinished', this._onFinished); + this._page.removeListener('requestfailed', this._onFinished); + } +} + +const with_connections_debug = (page, action) => { + const tracker = new InflightRequests(page); + return action().finally(() => { + tracker.dispose(); + const inflight = tracker.inflightRequests(); + if(inflight.length > 0) { + console.warn("Open connections: ", inflight, tracker._history.filter(([n,u]) => inflight.includes(u))); + // console.warn([...tracker._requests.entries()]) + } + }).catch(e => { + + throw e + }) +} + export const getTextContent = (page, selector) => { // https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext return page.evaluate( @@ -81,11 +142,13 @@ export const waitForContentToBecome = async (page, selector, targetContent) => { return getTextContent(page, selector); }; -export const clickAndWaitForNavigation = (page, selector) => - Promise.all([ - page.waitForNavigation({ waitUntil: "networkidle0" }), - page.click(selector), - ]); +export const clickAndWaitForNavigation = async (page, selector) => { + let t = with_connections_debug(page, () => page.waitForNavigation({ waitUntil: "networkidle0" })).catch(e => { + console.warn("Network idle never happened after navigation... weird!", e) + }) + await page.click(selector) + await t +} const dismissBeforeUnloadDialogs = (page) => { page.on("dialog", async (dialog) => { @@ -121,7 +184,13 @@ let should_be_offline_input = process.env["PLUTO_TEST_OFFLINE"]?.toLowerCase() ? let should_be_offline = [true, 1, "true", "1"].includes(should_be_offline_input) console.log(`Offline mode enabled: ${should_be_offline}`) -export const setupPage = (page) => { +const blocked_domains = ["cdn.jsdelivr.net", "unpkg.com", "cdn.skypack.dev", "esm.sh", "firebase.google.com"] +const hide_warning = url => url.includes("mathjax") + +export const createPage = async (browser) => { + /** @type {puppeteer.Page} */ + const page = await browser.newPage() + failOnError(page); dismissBeforeUnloadDialogs(page); dismissVersionDialogs(page); @@ -129,23 +198,26 @@ export const setupPage = (page) => { if(should_be_offline) { page.setRequestInterception(true); page.on("request", (request) => { - if(["cdn.jsdelivr.net", "unpkg.com", "cdn.skypack.dev", "esm.sh", "firebase.google.com"].some(domain => request.url().includes(domain))) { - console.error(`Blocking request to ${request.url()}`) + if(blocked_domains.some(domain => request.url().includes(domain))) { + if(!hide_warning(request.url())) + console.info(`Blocking request to ${request.url()}`) request.abort(); } else { request.continue(); } }); } + + return page }; -let testname = () => expect.getState().currentTestName.replace(/ /g, "_"); +let testname = () => expect.getState()?.currentTestName?.replace(/ /g, "_") ?? "unnkown"; export const lastElement = (arr) => arr[arr.length - 1]; const getFixturesDir = () => path.join(__dirname, "..", "fixtures"); -const getArtifactsDir = () => path.join(__dirname, "..", "artifacts"); +export const getArtifactsDir = () => path.join(__dirname, "..", "artifacts"); export const getFixtureNotebookPath = (name) => path.join(getFixturesDir(), name); @@ -163,7 +235,7 @@ export const getTestScreenshotPath = () => { ); }; -export const saveScreenshot = async (page, screenshot_path) => { +export const saveScreenshot = async (page, screenshot_path=getTestScreenshotPath()) => { let dirname = path.dirname(screenshot_path); await mkdirp(dirname); // Because some of our tests contain /'s 🤷‍♀️ await page.screenshot({ path: screenshot_path }); diff --git a/test/frontend/helpers/pluto.js b/test/frontend/helpers/pluto.js index 65aaea0bb9..6a92bd9d32 100644 --- a/test/frontend/helpers/pluto.js +++ b/test/frontend/helpers/pluto.js @@ -1,6 +1,7 @@ -import fs from "fs" +import puppeteer from "puppeteer" +import fs, { existsSync, writeFile, writeFileSync } from "fs" import { platform } from "process" -import { Page } from "puppeteer" +import { Browser, Page } from "puppeteer" import { clickAndWaitForNavigation, getFixtureNotebookPath, @@ -9,17 +10,31 @@ import { waitForContentToChange, getTextContent, lastElement, + createPage, + getArtifactsDir, + waitForContentToBecome, } from "./common" +import path from "path" // if (!process.env.PLUTO_PORT) { // throw new Error("You didn't set the PLUTO_PORT environment variable") // } export const getPlutoUrl = () => `http://localhost:${process.env.PLUTO_PORT}` +// we use a file to keep track of whether we already prewarmed pluto or not +const pluto_is_warm_path = path.join(getArtifactsDir(), `pluto_is_warm.txt`) + /** - * @param {Page} page + * @param {Browser} browser */ -export const prewarmPluto = async (browser, page) => { +export const prewarmPluto = async (browser) => { + if (existsSync(pluto_is_warm_path)) { + return + } + writeFileSync(pluto_is_warm_path, "yes") + + let page = await createPage(browser) + await browser.defaultBrowserContext().overridePermissions(getPlutoUrl(), ["clipboard-read", "clipboard-write"]) await page.goto(getPlutoUrl(), { waitUntil: "networkidle0" }) await createNewNotebook(page) @@ -31,10 +46,31 @@ export const prewarmPluto = async (browser, page) => { await page.waitForSelector(runSelector, { visible: true }) await page.click(runSelector) await waitForContent(page, "pluto-output") - await page.evaluate(() => { - // @ts-ignore - shutdownNotebook() + await shutdownCurrentNotebook(page) + + await page.close() +} + +/** + * @param {Page} page + */ +export const shutdownCurrentNotebook = async (page) => { + await page.evaluate( + //@ts-ignore + () => window.shutdownNotebook?.() + ) +} + +export const setupPlutoBrowser = async () => { + const browser = await puppeteer.launch({ + headless: process.env.HEADLESS !== "false", + args: ["--no-sandbox", "--disable-setuid-sandbox"], + devtools: false, }) + + await prewarmPluto(browser) + + return browser } /** @@ -44,25 +80,40 @@ export const createNewNotebook = async (page) => { const newNotebookSelector = 'a[href="new"]' await page.waitForSelector(newNotebookSelector) await clickAndWaitForNavigation(page, newNotebookSelector) + await page.waitForTimeout(1000) await waitForPlutoToCalmDown(page) + await page.waitForSelector("pluto-input", { visible: true }) } /** * @param {Page} page * @param {string} notebookName` */ -export const importNotebook = async (page, notebookName) => { +export const importNotebook = async (page, notebookName, { permissionToRunCode = true, timeout = 60000 } = {}) => { // Copy notebook before using it, so we don't mess it up with test changes const notebookPath = getFixtureNotebookPath(notebookName) - // const artifactsPath = getTemporaryNotebookPath() - // fs.copyFileSync(notebookPath, artifactsPath) + const artifactsPath = getTemporaryNotebookPath() + fs.copyFileSync(notebookPath, artifactsPath) + await openPathOrURLNotebook(page, artifactsPath, { permissionToRunCode, timeout }) +} + +/** + * @param {Page} page + * @param {string} path_or_url + */ +export const openPathOrURLNotebook = async (page, path_or_url, { permissionToRunCode = true, timeout = 60000 } = {}) => { + await page.waitForFunction(() => document.querySelector(`.not_yet_ready`) == null) + const openFileInputSelector = "pluto-filepicker" - // writeSingleLineInPlutoInput(page, openFileInputSelector, artifactsPath) - await writeSingleLineInPlutoInput(page, openFileInputSelector, notebookPath) + await writeSingleLineInPlutoInput(page, openFileInputSelector, path_or_url) + // await writeSingleLineInPlutoInput(page, openFileInputSelector, notebookPath) const openFileButton = "pluto-filepicker button" await clickAndWaitForNavigation(page, openFileButton) - await waitForPlutoToCalmDown(page) + // Give permission to run code in this notebook + if (permissionToRunCode) await restartProcess(page) + await page.waitForTimeout(1000) + await waitForPlutoToCalmDown(page, { polling: "raf", timeout }) } /** @@ -73,9 +124,38 @@ export const getCellIds = (page) => page.evaluate(() => Array.from(document.quer /** * @param {Page} page */ -export const waitForPlutoToCalmDown = async (page) => { - await page.waitForTimeout(1000) - await page.waitForFunction(() => document.body._update_is_ongoing === false && document.querySelector(`pluto-cell.running, pluto-cell.queued`) === null) +export const restartProcess = async (page) => { + await page.waitForSelector(`a#restart-process-button`) + await page.click(`a#restart-process-button`) + // page.once("dialog", async (dialog) => { + // await dialog.accept() + // }) + await page.waitForFunction(() => document?.querySelector(`a#restart-process-button`) == null) + await page.waitForSelector(`#process-status-tab-button.something_is_happening`) +} + +const waitForPlutoBusy = async (page, iWantBusiness, options) => { + await page.waitForTimeout(1) + await page.waitForFunction( + (iWantBusiness) => { + let quiet = //@ts-ignore + document?.body?._update_is_ongoing === false && + //@ts-ignore + document?.body?._js_init_set?.size === 0 && + document?.body?.classList?.contains("loading") === false && + document?.querySelector(`#process-status-tab-button.something_is_happening`) == null && + document?.querySelector(`pluto-cell.running, pluto-cell.queued, pluto-cell.internal_test_queued`) == null + + return iWantBusiness ? !quiet : quiet + }, + options, + iWantBusiness + ) + await page.waitForTimeout(1) +} + +export const waitForPlutoToCalmDown = async (/** @type {puppeteer.Page} */ page, /** @type {{ polling: string | number; timeout?: number; }} */ options) => { + await waitForPlutoBusy(page, false, options) } /** @@ -87,6 +167,11 @@ export const waitForCellOutput = (page, cellId) => { return waitForContent(page, cellOutputSelector) } +/** + * @param {Page} page + */ +export const getAllCellOutputs = (page) => page.evaluate(() => Array.from(document.querySelectorAll(`pluto-cell > pluto-output`)).map((c) => c.innerText)) + /** * @param {Page} page * @param {string} cellId @@ -99,7 +184,24 @@ export const waitForCellOutputToChange = (page, cellId, currentOutput) => { export const waitForNoUpdateOngoing = async (page, options = {}) => { await page.waitForTimeout(1000) - return await page.waitForFunction(() => document.body._update_is_ongoing === false, options) + return await page.waitForFunction( + () => + //@ts-ignore + document.body?._update_is_ongoing === false, + options + ) +} + +/** + * @param {Page} page + */ +export const runAllChanged = async (page) => { + await page.waitForSelector(`.runallchanged`, { + visible: true, + }) + await page.click(`.runallchanged`) + await waitForPlutoBusy(page, true) + await waitForPlutoBusy(page, false) } /** @@ -141,6 +243,26 @@ export const keyboardPressInPlutoInput = async (page, plutoInputSelector, key) = return waitForContentToChange(page, `${plutoInputSelector} .cm-line`, currentLineText) } +/** + * @param {Page} page + * @param {string} plutoInputSelector + */ +export const clearPlutoInput = async (page, plutoInputSelector) => { + await page.waitForSelector(`${plutoInputSelector} .cm-editor`) + if ((await page.$(`${plutoInputSelector} .cm-placeholder`)) == null) { + await page.focus(`${plutoInputSelector} .cm-content`) + await page.waitForTimeout(500) + // Move to end of the input + await page.keyboard.down(platform === "darwin" ? "Meta" : "Control") + await page.keyboard.press("KeyA") + await page.keyboard.up(platform === "darwin" ? "Meta" : "Control") + // Press the key we care about + await page.keyboard.press("Delete") + // Wait for CodeMirror to process the input and display the text + await page.waitForSelector(`${plutoInputSelector} .cm-placeholder`) + } +} + /** * @param {Page} page * @param {string[]} cells diff --git a/test/frontend/package-lock.json b/test/frontend/package-lock.json index b8c21cfdbc..2e2862d5a8 100644 --- a/test/frontend/package-lock.json +++ b/test/frontend/package-lock.json @@ -18,46 +18,65 @@ "babel-jest": "^26.6.3", "jest": "^26.6.3", "lodash": "^4.17.21", - "puppeteer": "^10.2.0" + "puppeteer": "^14.1.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", - "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", - "dev": true + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/core": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", - "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helpers": "^7.13.0", - "@babel/parser": "^7.13.4", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", + "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.12", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.12", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.12", + "@babel/types": "^7.17.12", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.1", + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" @@ -67,392 +86,384 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@babel/generator/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": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/core/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/core/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz", + "integrity": "sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/core/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/core/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/core/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" } }, - "node_modules/@babel/core/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/types": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/core/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/core/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, + "@babel/types": "^7.22.5" + }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, + "dependencies": { + "@babel/types": "^7.17.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/types": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", + "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.12", + "@babel/types": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/generator/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", - "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", - "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", + "node_modules/@babel/helper-simple-access": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", - "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" + "@babel/types": "^7.22.5" }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.8.tgz", - "integrity": "sha512-qioaRrKHQbn4hkRKDHbnuQ6kAxmmOF+kzKGnIfxPK4j2rckSJCpKzr/SSTlohSCiE3uAQpNDJ9FIh4baeE8W+w==", + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/helper-wrap-function": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@babel/helpers": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -461,1627 +472,2091 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "node": ">=6.9.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", "dev": true, "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.12.tgz", + "integrity": "sha512-8ILyDG6eL14F8iub97dVc8q35Md0PJYAnA5Kz9NACFOkt6ffCcr0FISyUPKHsvuAy36fkpIitxZ9bVYPFMGQHA==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", - "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "regexpu-core": "^4.7.1" + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz", + "integrity": "sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.17.12" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", - "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-explode-assignable-expression/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-explode-assignable-expression/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-function-name/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-get-function-arity/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-get-function-arity/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", - "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz", + "integrity": "sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz", + "integrity": "sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz", + "integrity": "sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/helper-hoist-variables/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz", + "integrity": "sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", - "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", - "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.17.12.tgz", + "integrity": "sha512-p5rt9tB5Ndcc2Za7CeNxVf7YAjRcUMR6yi8o8tKjb9KhRkEvXwa+C0hj6DA5bVDkKRxB0NYhMUGbVKoFu4+zEA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz", + "integrity": "sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.17.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", - "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.12.tgz", + "integrity": "sha512-NVhDb0q00hqZcuLduUf/kMzbOQHiocmPbIxIvk23HLiEqaTKC/l4eRxeC7lO63M72BmACoiKOcb9AkOAJRerpw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "lodash": "^4.17.19" + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-identifier": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.17.12.tgz", + "integrity": "sha512-BnsPkrUHsjzZGpnrmJeDFkOMMljWFHPjDc9xDcz71/C+ybF3lfC3V4m3dwXPLZrE5b3bgd4V+3/Pj+3620d7IA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", + "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz", + "integrity": "sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw==", "dev": true, "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/helper-module-transforms/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, + "@babel/helper-plugin-utils": "^7.17.12" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "node_modules/@babel/preset-env": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.12.tgz", + "integrity": "sha512-Kke30Rj3Lmcx97bVs71LO0s8M6FmJ7tUAQI9fNId62rf0cYG1UAWwdNO9/sE0/pLEahAw1MqMorymoD12bj5Fg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.17.12", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.12", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.17.12", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.17.12", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.17.12", + "@babel/plugin-transform-modules-commonjs": "^7.17.12", + "@babel/plugin-transform-modules-systemjs": "^7.17.12", + "@babel/plugin-transform-modules-umd": "^7.17.12", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", + "@babel/plugin-transform-reserved-words": "^7.17.12", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.17.12", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.17.12", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", - "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", + "node_modules/@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-wrap-function": "^7.13.0", - "@babel/types": "^7.13.0" + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", - "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@jest/console": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/@jest/console/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, - "bin": { - "parser": "bin/babel-parser.js" + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@jest/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-replace-supers/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-replace-supers/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/helper-replace-supers/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@babel/helper-replace-supers/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@babel/helper-replace-supers/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@jest/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" }, "engines": { - "node": ">=4" + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", - "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", + "node_modules/@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "node_modules/@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "node-notifier": "^8.0.0" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", - "dev": true + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", - "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", "dev": true, "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/@jest/transform/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, - "bin": { - "parser": "bin/babel-parser.js" + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/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, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">= 10.14.2" } }, - "node_modules/@babel/helper-wrap-function/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-wrap-function/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/helper-wrap-function/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/helper-wrap-function/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/@babel/helper-wrap-function/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/@babel/helpers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", - "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, "dependencies": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "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==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true, - "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "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.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@babel/helpers/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "type-detect": "4.0.8" } }, - "node_modules/@babel/helpers/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } }, - "node_modules/@babel/helpers/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@babel/helpers/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@babel/types": "^7.0.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "@babel/types": "^7.3.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@types/node": "*" } }, - "node_modules/@babel/helpers/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/@babel/helpers/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "@types/istanbul-lib-report": "*" } }, - "node_modules/@babel/helpers/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@types/jest": { + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" } }, - "node_modules/@babel/helpers/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/@types/node": { + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.34.tgz", + "integrity": "sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==", "dev": true }, - "node_modules/@babel/helpers/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=4" + "node": ">=0.4.0" } }, - "node_modules/@babel/helpers/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/@babel/helpers/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "debug": "4" }, "engines": { - "node": ">=4" + "node": ">= 6.0.0" } }, - "node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@babel/highlight/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { + "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", @@ -2093,2728 +2568,2471 @@ "node": ">=4" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "sprintf-js": "~1.0.2" } }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", - "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", - "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" + "bin": { + "atob": "bin/atob.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">= 4.5.0" } }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", - "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", + "node_modules/babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-dynamic-import/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", - "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "color-convert": "^2.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", - "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@babel/plugin-proposal-json-strings/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", - "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "color-name": "~1.1.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", - "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", + "node_modules/babel-jest/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, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", - "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "has-flag": "^4.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-proposal-numeric-separator/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "object.assign": "^4.1.0" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", - "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-proposal-optional-catch-binding/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.8.tgz", - "integrity": "sha512-hpbBwbTgd7Cz1QryvwJZRo1U0k1q8uyBmeXOSQUjdg/A2TASkhR/rz7AyqZ/kS8kbpsNA80rOYbxySBJAqmhhQ==", + "node_modules/babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/plugin-proposal-optional-chaining/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", - "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-private-methods/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", - "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "engines": { - "node": ">=4" + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-define-polyfill-provider": "^0.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-class-properties/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "is-descriptor": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "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/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "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": { - "@babel/helper-plugin-utils": "^7.10.4" + "fill-range": "^7.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node-int64": "^0.4.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "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": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "*" } }, - "node_modules/@babel/plugin-syntax-top-level-await/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "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/@babel/plugin-transform-arrow-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", - "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-arrow-functions/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", - "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@babel/plugin-transform-async-to-generator/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", - "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", - "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6" } }, - "node_modules/@babel/plugin-transform-block-scoping/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", - "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", + "node_modules/caniuse-lite": { + "version": "1.0.30001341", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", + "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13", - "globals": "^11.1.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" + "engines": { + "node": ">=10" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "node_modules/cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", "dev": true }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "dependencies": { + "is-descriptor": "^0.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/plugin-transform-classes/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", - "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", - "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-destructuring/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", - "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "color-name": "1.1.3" } }, - "node_modules/@babel/plugin-transform-dotall-regex/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", - "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "delayed-stream": "~1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">= 0.8" } }, - "node_modules/@babel/plugin-transform-duplicate-keys/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", - "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", - "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "safe-buffer": "~5.1.1" } }, - "node_modules/@babel/plugin-transform-for-of/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", - "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", + "node_modules/core-js-compat": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", + "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "browserslist": "^4.20.3", + "semver": "7.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "node-fetch": "2.6.7" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "@babel/types": "^7.12.13" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "cssom": "~0.3.6" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "node": ">=8" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true }, - "node_modules/@babel/plugin-transform-function-name/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ms": "2.1.2" }, "engines": { - "node": ">=4" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true, - "dependencies": { - "color-name": "1.1.3" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, - "node_modules/@babel/plugin-transform-function-name/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10" } }, - "node_modules/@babel/plugin-transform-function-name/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", - "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", - "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "engines": { + "node": ">= 0.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@babel/plugin-transform-member-expression-literals/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", - "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "babel-plugin-dynamic-import-node": "^2.3.3" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-modules-amd/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", - "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", - "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.13.0", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-identifier": "^7.12.11", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-transform-modules-systemjs/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-modules-systemjs/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "node_modules/devtools-protocol": { + "version": "0.0.982423", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.982423.tgz", + "integrity": "sha512-FnVW2nDbjGNw1uD/JRC+9U5768W7e1TfUwqbDTcSsAu1jXFjITSX8w3rkW5FEpHRMPPGpvNSmO1pOpqByiWscA==", "dev": true }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", - "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", + "node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/plugin-transform-modules-umd/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", - "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13" + "webidl-conversions": "^5.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", - "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@babel/plugin-transform-new-target/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/electron-to-chromium": { + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", "dev": true }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", - "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", + "node_modules/emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-replace-supers": "^7.12.13" + "engines": { + "node": ">=10" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/@babel/plugin-transform-object-super/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", - "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "once": "^1.4.0" } }, - "node_modules/@babel/plugin-transform-parameters/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", - "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "is-arrayish": "^0.2.1" } }, - "node_modules/@babel/plugin-transform-property-literals/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", - "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", - "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.8.0" } }, - "node_modules/@babel/plugin-transform-reserved-words/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", - "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", - "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/@babel/plugin-transform-spread/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", - "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=4" } }, - "node_modules/@babel/plugin-transform-sticky-regex/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", - "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", + "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, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-template-literals/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "node_modules/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", - "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/@babel/plugin-transform-typeof-symbol/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", - "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", - "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "ms": "2.0.0" } }, - "node_modules/@babel/plugin-transform-unicode-regex/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/preset-env": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.9.tgz", - "integrity": "sha512-mcsHUlh2rIhViqMG823JpscLMesRt3QbMsv1+jhopXEb3W2wXvQ9QoiOlZI9ZbR3XqPtaFpZwEZKYqGJnGMZTQ==", + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-option": "^7.12.17", - "@babel/plugin-proposal-async-generator-functions": "^7.13.8", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-dynamic-import": "^7.13.8", - "@babel/plugin-proposal-export-namespace-from": "^7.12.13", - "@babel/plugin-proposal-json-strings": "^7.13.8", - "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", - "@babel/plugin-proposal-numeric-separator": "^7.12.13", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", - "@babel/plugin-proposal-optional-chaining": "^7.13.8", - "@babel/plugin-proposal-private-methods": "^7.13.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.12.13", - "@babel/plugin-transform-arrow-functions": "^7.13.0", - "@babel/plugin-transform-async-to-generator": "^7.13.0", - "@babel/plugin-transform-block-scoped-functions": "^7.12.13", - "@babel/plugin-transform-block-scoping": "^7.12.13", - "@babel/plugin-transform-classes": "^7.13.0", - "@babel/plugin-transform-computed-properties": "^7.13.0", - "@babel/plugin-transform-destructuring": "^7.13.0", - "@babel/plugin-transform-dotall-regex": "^7.12.13", - "@babel/plugin-transform-duplicate-keys": "^7.12.13", - "@babel/plugin-transform-exponentiation-operator": "^7.12.13", - "@babel/plugin-transform-for-of": "^7.13.0", - "@babel/plugin-transform-function-name": "^7.12.13", - "@babel/plugin-transform-literals": "^7.12.13", - "@babel/plugin-transform-member-expression-literals": "^7.12.13", - "@babel/plugin-transform-modules-amd": "^7.13.0", - "@babel/plugin-transform-modules-commonjs": "^7.13.8", - "@babel/plugin-transform-modules-systemjs": "^7.13.8", - "@babel/plugin-transform-modules-umd": "^7.13.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", - "@babel/plugin-transform-new-target": "^7.12.13", - "@babel/plugin-transform-object-super": "^7.12.13", - "@babel/plugin-transform-parameters": "^7.13.0", - "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.12.13", - "@babel/plugin-transform-reserved-words": "^7.12.13", - "@babel/plugin-transform-shorthand-properties": "^7.12.13", - "@babel/plugin-transform-spread": "^7.13.0", - "@babel/plugin-transform-sticky-regex": "^7.12.13", - "@babel/plugin-transform-template-literals": "^7.13.0", - "@babel/plugin-transform-typeof-symbol": "^7.12.13", - "@babel/plugin-transform-unicode-escapes": "^7.12.13", - "@babel/plugin-transform-unicode-regex": "^7.12.13", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.13.0", - "babel-plugin-polyfill-corejs2": "^0.1.4", - "babel-plugin-polyfill-corejs3": "^0.1.3", - "babel-plugin-polyfill-regenerator": "^0.1.2", - "core-js-compat": "^3.9.0", - "semver": "^6.3.0" + "is-descriptor": "^0.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "is-extendable": "^0.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/preset-modules": { + "node_modules/expand-brackets/node_modules/is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "kind-of": "^3.0.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/runtime": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", - "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.4" + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "node_modules/@babel/traverse/node_modules/@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "node_modules/expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@babel/types": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", - "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.1.95" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/expect/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" + "is-descriptor": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 10.17.0" }, "optionalDependencies": { - "node-notifier": "^8.0.0" + "@types/yauzl": "^2.9.1" } }, - "node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" + "bser": "2.1.1" } }, - "node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "pend": "~1.2.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "dependencies": { - "type-detect": "4.0.8" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true }, - "node_modules/@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", - "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/@types/color-name": { + "node_modules/get-intrinsic": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "dependencies": { - "@types/node": "*" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "*" + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/jest": { - "version": "26.0.20", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", - "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", + "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": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "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/@types/node": { - "version": "14.14.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", - "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } }, - "node_modules/@types/prettier": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.2.tgz", - "integrity": "sha512-i99hy7Ki19EqVOl77WplDrvgNugHnsSjECVR/wUrzw2TJXz1zlUfT2ngGckR6xN7yFYaijsMAqPkOLx9HgUqHg==", + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true, + "optional": true }, - "node_modules/@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "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": { - "@types/yargs-parser": "*" + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" } }, - "node_modules/@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true - }, - "node_modules/@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" + "engines": { + "node": ">=4" } }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "get-intrinsic": "^1.1.1" }, - "engines": { - "node": ">=0.4.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "dependencies": { - "debug": "4" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "engines": { - "node": ">= 6.0.0" + "node": ">=0.10.0" } }, - "node_modules/ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "dependencies": { - "type-fest": "^0.11.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "is-buffer": "^1.1.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "whatwg-encoding": "^1.0.5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=10" } }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">= 8" + "node": ">= 6" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { - "sprintf-js": "~1.0.2" + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8.12.0" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/arr-union": { + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/import-local": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.8.19" } }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "dependencies": { - "safer-buffer": "~2.1.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } + "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/assign-symbols": { + "node_modules/is-accessor-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, "bin": { - "atob": "bin/atob.js" + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" }, - "engines": { - "node": ">= 4.5.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/aws4": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", - "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "dependencies": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" }, "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" + "node": ">=0.10.0" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" + "optional": true, + "bin": { + "is-docker": "cli.js" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", - "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "@babel/compat-data": "^7.13.0", - "@babel/helper-define-polyfill-provider": "^0.1.5", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=6" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "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, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.1.5", - "core-js-compat": "^3.8.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.12.0" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", - "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.1.5" + "isobject": "^3.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/babel-preset-current-node-syntax": { + "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "engines": { + "node": ">=8" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "optional": true, "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "is-docker": "^2.0.0" }, "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=8" } }, - "node_modules/balanced-match": { + "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.0" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "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": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "node_modules/jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", "dev": true, "dependencies": { - "tweetnacl": "^0.14.3" + "@jest/core": "^26.6.3", + "import-local": "^3.0.2", + "jest-cli": "^26.6.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", "dev": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "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==", + "node_modules/jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "bin": { - "browserslist": "cli.js" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/browserslist/node_modules/caniuse-lite": { - "version": "1.0.30001230", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", - "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/browserslist/node_modules/electron-to-chromium": { - "version": "1.3.739", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.739.tgz", - "integrity": "sha512-+LPJVRsN7hGZ9EIUUiWCpO7l4E3qBYHNadazlucBfsXBbccDFNKUBAgzE68FnkWGJPwD/AfKhSzL+G+Iqb8A4A==", + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/jest-cli/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, - "dependencies": { - "node-int64": "^0.4.0" + "engines": { + "node": ">=8" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "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": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "node_modules/jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, "engines": { - "node": "*" + "node": ">= 10.14.2" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } } }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "rsvp": "^4.8.4" + "has-flag": "^4.0.0" }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "node_modules/jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -4827,101 +5045,105 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/chownr": { + "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/jest-docblock": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", "dev": true, "dependencies": { - "is-descriptor": "^0.1.0" + "detect-newline": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/color-convert": { + "node_modules/jest-each/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -4933,1344 +5155,1363 @@ "node": ">=7.0.0" } }, - "node_modules/color-name": { + "node_modules/jest-each/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/jest-each/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, - "dependencies": { - "delayed-stream": "~1.0.0" - }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.1" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "node_modules/jest-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/core-js-compat": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.1.tgz", - "integrity": "sha512-jXAirMQxrkbiiLsCx9bQPJFA6llDadKMpYrBJQJ3/c4/vsPP/fAf29h24tviRlvwUL6AmY5CHLu2GvjuYviQqA==", + "node_modules/jest-environment-node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", "dev": true, "dependencies": { - "browserslist": "^4.16.3", - "semver": "7.0.0" + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "node_modules/jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", "dev": true, "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" }, "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "fsevents": "^2.1.2" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", "dev": true, "dependencies": { - "cssom": "~0.3.6" + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "assert-plus": "^1.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "color-name": "~1.1.4" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.10" + "node": ">=8" } }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/jest-leak-detector": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">= 0.4" + "node": ">= 10.14.2" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/devtools-protocol": { - "version": "0.0.901419", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz", - "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==", - "dev": true - }, - "node_modules/diff-sequences": { + "node_modules/jest-message-util": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + }, "engines": { "node": ">= 10.14.2" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "webidl-conversions": "^5.0.0" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": ">=8" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/jest-mock": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*" }, "engines": { - "node": ">=4" + "node": ">= 10.14.2" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "node_modules/jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", "dev": true, "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" + "node": ">= 10.14.2" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", "dev": true, "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "ms": "2.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "is-descriptor": "^0.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { + "node_modules/jest-resolve/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "node_modules/jest-resolve/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, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/jest-runner": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.4" + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/extglob/node_modules/extend-shallow": { + "node_modules/jest-runner/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/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, - "dependencies": { - "kind-of": "^6.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/jest-runtime": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "bin": { + "jest-runtime": "bin/jest-runtime.js" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 10.17.0" + "node": ">=8" }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "pump": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fb-watchman": { + "node_modules/jest-runtime/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "bser": "2.1.1" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/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/jest-runtime/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, - "dependencies": { - "to-regex-range": "^5.0.1" - }, "engines": { "node": ">=8" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/jest-snapshot": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" }, "engines": { - "node": ">= 0.12" + "node": ">= 10.14.2" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "map-cache": "^0.2.2" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/jest-snapshot/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, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6.9.0" + "node": ">=7.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" } }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "engines": { - "node": ">=8.0.0" + "node": ">=10" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "pump": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "node_modules/jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "assert-plus": "^1.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/jest-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 10.14.2" } }, - "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==", + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/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, - "dependencies": { - "kind-of": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "node_modules/jest-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.5" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "agent-base": "6", - "debug": "4" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 6" + "node": ">=7.0.0" } }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=8.12.0" + "node": ">=8" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">= 10.13.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.8.19" + "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "dependencies": { - "kind-of": "^3.0.2" + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, "bin": { - "is-ci": "bin.js" + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "node_modules/is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "optional": true, - "bin": { - "is-docker": "cli.js" + "dependencies": { + "semver": "^6.0.0" }, "engines": { "node": ">=8" @@ -6279,2332 +6520,1892 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, "engines": { - "node": ">=6" + "node": ">=8.6" } }, - "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==", + "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.12.0" + "node": ">= 0.6" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "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": { - "isobject": "^3.0.1" + "mime-db": "1.52.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", - "dev": true + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "dependencies": { - "is-docker": "^2.0.0" + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, - "engines": { + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { "node": ">=0.10.0" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "whatwg-url": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "dev": true, "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, + "optional": true, "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8" + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" } }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "node_modules/node-notifier/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, + "optional": true, "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "node_modules/node-releases": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, "bin": { - "jest": "bin/jest.js" - }, + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "path-key": "^3.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-changed-files/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==", + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "is-descriptor": "^0.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "pump": "^3.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/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==", + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/jest-changed-files/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "isobject": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" }, "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "isobject": "^3.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "wrappy": "1" } }, - "node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.8.0" } }, - "node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "node_modules/p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=4" } }, - "node_modules/jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" + "p-try": "^2.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" }, - "optionalDependencies": { - "fsevents": "^2.1.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true }, - "node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "node": ">=8" } }, - "node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "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, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "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/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-resolve/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 6" } }, - "node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "find-up": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.8.0" } }, - "node_modules/jest-snapshot": { + "node_modules/pretty-format": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "dependencies": { - "@babel/types": "^7.0.0", "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 10" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 10.14.2" + "node": ">=7.0.0" } }, - "node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 6" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/jest/node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/puppeteer": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-14.1.0.tgz", + "integrity": "sha512-T3eB4f6k9HVttYvyy8drGIKb04M+vxhepqM7qqcVCBTNT3T6M9cUaJT4k7P+a6wSonObJSJUP98JkPDQG+3fJw==", "dev": true, + "hasInstallScript": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.982423", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "pkg-dir": "4.2.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.6.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=14.1.0" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "node_modules/puppeteer/node_modules/ws": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz", + "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==", "dev": true, - "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=10.0.0" }, "peerDependencies": { - "canvas": "^2.5.0" + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { - "canvas": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { "optional": true } } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, - "engines": [ - "node >=0.6.0" - ], "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 6" } }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "regenerate": "^1.4.2" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "@babel/runtime": "^7.8.4" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "dependencies": { - "tmpl": "1.0.x" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/regexpu-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "dependencies": { - "object-visit": "^1.0.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "node_modules/regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, - "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "node_modules/regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "jsesc": "~0.5.0" }, - "engines": { - "node": ">=8" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true, - "engines": { - "node": ">= 0.6" + "bin": { + "jsesc": "bin/jsesc" } }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, - "dependencies": { - "mime-db": "1.44.0" - }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true, "engines": { - "node": ">=6" + "node": ">=0.10" } }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.4" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "bin": { - "mkdirp": "bin/cmd.js" + "resolve": "bin/resolve" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "engines": { - "node": "4.x || >=6.0.0" + "node": ">=8" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", - "dev": true, - "optional": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" + "node": ">=0.12" } }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "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, - "optional": true, "dependencies": { - "lru-cache": "^6.0.0" + "glob": "^7.1.3" }, "bin": { - "semver": "bin/semver.js" + "rimraf": "bin.js" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-notifier/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true, - "optional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, "engines": { - "node": ">= 8" + "node": "6.* || >= 7.*" } }, - "node_modules/node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "ret": "~0.1.10" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", "dev": true, "dependencies": { - "path-key": "^2.0.0" + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "bin": { + "sane": "src/cli.js" }, "engines": { - "node": ">=4" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "node_modules/sane/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, - "engines": { - "node": "*" + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "node_modules/sane/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "is-descriptor": "^0.1.0" + "is-extendable": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/sane/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.8" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/sane/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "node_modules/sane/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "dependencies": { - "isobject": "^3.0.0" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/sane/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "dependencies": { - "isobject": "^3.0.1" + "pump": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "node_modules/sane/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, - "dependencies": { - "wrappy": "1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/sane/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "node_modules/sane/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/sane/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "remove-trailing-separator": "^1.0.1" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/sane/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "path-key": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/sane/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/sane/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/sane/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "shebang-regex": "^1.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "node_modules/sane/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/sane/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "node_modules/sane/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "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/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "dependencies": { - "node-modules-regexp": "^1.0.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "find-up": "^4.0.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/posix-character-classes": { + "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/prompts": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", - "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.4" - }, - "engines": { - "node": ">= 6" - } + "optional": true }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, - "node_modules/pump": { + "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/puppeteer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-10.2.0.tgz", - "integrity": "sha512-OR2CCHRashF+f30+LBOtAjK6sNtz2HEyTr5FqAvhf8lR/qB3uBRoIZOwQKgwoyZnMBsxX7ZdazlyBgGjpnkiMw==", + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, - "hasInstallScript": true, "dependencies": { - "debug": "4.3.1", - "devtools-protocol": "0.0.901419", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "node-fetch": "2.6.1", - "pkg-dir": "4.2.0", - "progress": "2.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.0.0", - "unbzip2-stream": "1.3.3", - "ws": "7.4.6" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "engines": { - "node": ">=10.18.1" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "engines": { - "node": ">=0.6" + "node": ">=0.10.0" } }, - "node_modules/react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" + "is-descriptor": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "kind-of": "^3.2.0" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "regenerate": "^1.4.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.8.4" + "ms": "2.0.0" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.7.tgz", - "integrity": "sha512-ib77G0uxsA2ovgiYbCVGx4Pv3PSttAx2vIwidqQzbL2U5S4Q+j00HdSAneSBuyVcMvEnTXMjiGgB+DlXozVhpQ==", + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "jsesc": "~0.5.0" + "kind-of": "^3.0.2" }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "lodash": "^4.17.19" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" } }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" + "node": ">=0.10.0" } }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=0.8" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { - "node": ">=0.8" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, - "bin": { - "uuid": "bin/uuid" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { + "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "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, - "dependencies": { - "resolve-from": "^5.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "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, - "engines": { - "node": ">=0.12" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.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==", + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "engines": { - "node": "6.* || >= 7.*" + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", "dev": true }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "dependencies": { - "ret": "~0.1.10" + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" + "escape-string-regexp": "^2.0.0" }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=10" } }, - "node_modules/sane/node_modules/anymatch": { + "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "engines": { + "node": ">=8" } }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -8613,7 +8414,7 @@ "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", @@ -8625,254 +8426,286 @@ "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" + "safe-buffer": "~5.2.0" } }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "node_modules/string_decoder/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, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "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/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/shebang-regex": { + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "optional": true + "engines": { + "node": ">=6" + } }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/snapdragon-node": { + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/tar-fs": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" } }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.0" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "dependencies": { - "kind-of": "^3.2.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-util/node_modules/kind-of": { + "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", @@ -8884,3202 +8717,1077 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "dependencies": { - "is-descriptor": "^0.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "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-extendable": "^0.1.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "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==", + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "engines": { + "node": ">=4" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "is-typedarray": "^1.0.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "buffer": "^5.2.1", + "through": "^2.3.8" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "dependencies": { - "escape-string-regexp": "^2.0.0" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { + "node_modules/unicode-match-property-value-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "dependencies": { - "is-descriptor": "^0.1.0" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" + "engines": { + "node": ">= 4.0.0" } }, - "node_modules/string_decoder/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/string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "isarray": "1.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "node_modules/v8-to-istanbul": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", "dev": true, "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" }, "engines": { - "node": ">=8" + "node": ">=10.10.0" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/tar-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", - "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp": "^0.5.1", - "pump": "^3.0.0", - "tar-stream": "^2.0.0" + "engines": { + "node": ">= 8" } }, - "node_modules/tar-fs/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", "dev": true, "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" + "browser-process-hrtime": "^1.0.0" } }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dev": true, "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "xml-name-validator": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" + "makeerror": "1.0.12" } }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true, "engines": { - "node": ">=4" + "node": ">=10.4" } }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "dev": true, "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "iconv-lite": "0.4.24" } }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "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==", + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, "engines": { - "node": ">=8.0" + "node": ">=0.10.0" } }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "punycode": "^2.1.1" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "safe-buffer": "^5.0.1" + "color-name": "~1.1.4" }, "engines": { - "node": "*" + "node": ">=7.0.0" } }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, "engines": { "node": ">=8" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "dependencies": { - "is-typedarray": "^1.0.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/unbzip2-stream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - }, - "engines": { - "node": ">=4" + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", - "dev": true, - "engines": { - "node": ">=4" - } + "@babel/compat-data": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "dev": true }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "dev": true, - "engines": { - "node": ">=4" + "@babel/core": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", + "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.12", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.12", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.12", + "@babel/types": "^7.17.12", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" } }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "requires": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@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, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/types": "^7.16.7" } }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "@babel/helper-compilation-targets": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" } }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "@babel/helper-create-class-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz", + "integrity": "sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, - "node_modules/uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "@babel/helper-create-regexp-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" + "requires": { + "@babel/types": "^7.16.7" } }, - "node_modules/v8-to-istanbul": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", - "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "dependencies": { - "makeerror": "1.0.x" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/compat-data": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", - "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", - "dev": true - }, - "@babel/core": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", - "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helpers": "^7.13.0", - "@babel/parser": "^7.13.4", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", - "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", - "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", - "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.8.tgz", - "integrity": "sha512-qioaRrKHQbn4hkRKDHbnuQ6kAxmmOF+kzKGnIfxPK4j2rckSJCpKzr/SSTlohSCiE3uAQpNDJ9FIh4baeE8W+w==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", - "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "regexpu-core": "^4.7.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", - "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-hoist-variables": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", - "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", - "dev": true, - "requires": { - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", - "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "requires": { - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", - "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", - "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", + "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.12", + "@babel/types": "^7.17.12" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", - "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-wrap-function": "^7.13.0", - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", - "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", - "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.17.0" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "requires": { - "@babel/types": "^7.12.1" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", - "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", - "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dev": true, "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.17.12" + } + }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", - "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-class-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", - "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.12.tgz", + "integrity": "sha512-8ILyDG6eL14F8iub97dVc8q35Md0PJYAnA5Kz9NACFOkt6ffCcr0FISyUPKHsvuAy36fkpIitxZ9bVYPFMGQHA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", - "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", - "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-json-strings": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", - "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", - "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", - "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", - "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz", + "integrity": "sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/plugin-transform-parameters": "^7.17.12" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", - "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.8.tgz", - "integrity": "sha512-hpbBwbTgd7Cz1QryvwJZRo1U0k1q8uyBmeXOSQUjdg/A2TASkhR/rz7AyqZ/kS8kbpsNA80rOYbxySBJAqmhhQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-proposal-private-methods": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", - "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", - "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-syntax-async-generators": { @@ -12107,14 +9815,15 @@ "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-dynamic-import": { @@ -12207,863 +9916,369 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", - "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", - "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", - "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", - "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz", + "integrity": "sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-classes": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", - "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz", + "integrity": "sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/plugin-transform-computed-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", - "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-destructuring": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", - "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz", + "integrity": "sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", - "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", - "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", - "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", - "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz", + "integrity": "sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", - "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", - "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", - "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", - "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.17.12.tgz", + "integrity": "sha512-p5rt9tB5Ndcc2Za7CeNxVf7YAjRcUMR6yi8o8tKjb9KhRkEvXwa+C0hj6DA5bVDkKRxB0NYhMUGbVKoFu4+zEA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", - "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz", + "integrity": "sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", - "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.12.tgz", + "integrity": "sha512-NVhDb0q00hqZcuLduUf/kMzbOQHiocmPbIxIvk23HLiEqaTKC/l4eRxeC7lO63M72BmACoiKOcb9AkOAJRerpw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.13.0", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - } } }, "@babel/plugin-transform-modules-umd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", - "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.17.12.tgz", + "integrity": "sha512-BnsPkrUHsjzZGpnrmJeDFkOMMljWFHPjDc9xDcz71/C+ybF3lfC3V4m3dwXPLZrE5b3bgd4V+3/Pj+3620d7IA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-module-transforms": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", - "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-new-target": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", - "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", + "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-object-super": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", - "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-replace-supers": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", - "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-property-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", - "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", - "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "dev": true, "requires": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", - "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", - "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", - "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", - "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", - "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz", + "integrity": "sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", - "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", - "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", - "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - } + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.9.tgz", - "integrity": "sha512-mcsHUlh2rIhViqMG823JpscLMesRt3QbMsv1+jhopXEb3W2wXvQ9QoiOlZI9ZbR3XqPtaFpZwEZKYqGJnGMZTQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-option": "^7.12.17", - "@babel/plugin-proposal-async-generator-functions": "^7.13.8", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-dynamic-import": "^7.13.8", - "@babel/plugin-proposal-export-namespace-from": "^7.12.13", - "@babel/plugin-proposal-json-strings": "^7.13.8", - "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", - "@babel/plugin-proposal-numeric-separator": "^7.12.13", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", - "@babel/plugin-proposal-optional-chaining": "^7.13.8", - "@babel/plugin-proposal-private-methods": "^7.13.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.12.tgz", + "integrity": "sha512-Kke30Rj3Lmcx97bVs71LO0s8M6FmJ7tUAQI9fNId62rf0cYG1UAWwdNO9/sE0/pLEahAw1MqMorymoD12bj5Fg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.17.12", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.12", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", "@babel/plugin-syntax-json-strings": "^7.8.3", @@ -13073,92 +10288,53 @@ "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.12.13", - "@babel/plugin-transform-arrow-functions": "^7.13.0", - "@babel/plugin-transform-async-to-generator": "^7.13.0", - "@babel/plugin-transform-block-scoped-functions": "^7.12.13", - "@babel/plugin-transform-block-scoping": "^7.12.13", - "@babel/plugin-transform-classes": "^7.13.0", - "@babel/plugin-transform-computed-properties": "^7.13.0", - "@babel/plugin-transform-destructuring": "^7.13.0", - "@babel/plugin-transform-dotall-regex": "^7.12.13", - "@babel/plugin-transform-duplicate-keys": "^7.12.13", - "@babel/plugin-transform-exponentiation-operator": "^7.12.13", - "@babel/plugin-transform-for-of": "^7.13.0", - "@babel/plugin-transform-function-name": "^7.12.13", - "@babel/plugin-transform-literals": "^7.12.13", - "@babel/plugin-transform-member-expression-literals": "^7.12.13", - "@babel/plugin-transform-modules-amd": "^7.13.0", - "@babel/plugin-transform-modules-commonjs": "^7.13.8", - "@babel/plugin-transform-modules-systemjs": "^7.13.8", - "@babel/plugin-transform-modules-umd": "^7.13.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", - "@babel/plugin-transform-new-target": "^7.12.13", - "@babel/plugin-transform-object-super": "^7.12.13", - "@babel/plugin-transform-parameters": "^7.13.0", - "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.12.13", - "@babel/plugin-transform-reserved-words": "^7.12.13", - "@babel/plugin-transform-shorthand-properties": "^7.12.13", - "@babel/plugin-transform-spread": "^7.13.0", - "@babel/plugin-transform-sticky-regex": "^7.12.13", - "@babel/plugin-transform-template-literals": "^7.13.0", - "@babel/plugin-transform-typeof-symbol": "^7.12.13", - "@babel/plugin-transform-unicode-escapes": "^7.12.13", - "@babel/plugin-transform-unicode-regex": "^7.12.13", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.13.0", - "babel-plugin-polyfill-corejs2": "^0.1.4", - "babel-plugin-polyfill-corejs3": "^0.1.3", - "babel-plugin-polyfill-regenerator": "^0.1.2", - "core-js-compat": "^3.9.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.17.12", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.17.12", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.17.12", + "@babel/plugin-transform-modules-commonjs": "^7.17.12", + "@babel/plugin-transform-modules-systemjs": "^7.17.12", + "@babel/plugin-transform-modules-umd": "^7.17.12", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", + "@babel/plugin-transform-reserved-words": "^7.17.12", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.17.12", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.17.12", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -13169,88 +10345,51 @@ } }, "@babel/runtime": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", - "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", - "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -13301,6 +10440,57 @@ "jest-message-util": "^26.6.2", "jest-util": "^26.6.2", "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/core": { @@ -13337,6 +10527,57 @@ "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/environment": { @@ -13407,6 +10648,69 @@ "string-length": "^4.0.1", "terminal-link": "^2.0.0", "v8-to-istanbul": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/source-map": { @@ -13466,25 +10770,165 @@ "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@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==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "dev": true + }, + "@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 + }, + "@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -13499,10 +10943,16 @@ "@sinonjs/commons": "^1.7.0" } }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -13513,18 +10963,18 @@ } }, "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -13532,20 +10982,14 @@ } }, "@types/babel__traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", - "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -13556,9 +11000,9 @@ } }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "@types/istanbul-lib-report": { @@ -13571,18 +11015,18 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "26.0.20", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", - "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "dev": true, "requires": { "jest-diff": "^26.0.0", @@ -13590,48 +11034,48 @@ } }, "@types/node": { - "version": "14.14.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", - "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.34.tgz", + "integrity": "sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==", "dev": true }, "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, "@types/prettier": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.2.tgz", - "integrity": "sha512-i99hy7Ki19EqVOl77WplDrvgNugHnsSjECVR/wUrzw2TJXz1zlUfT2ngGckR6xN7yFYaijsMAqPkOLx9HgUqHg==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==", "dev": true }, "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "requires": { @@ -13639,15 +11083,15 @@ } }, "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true }, "acorn-globals": { @@ -13658,6 +11102,14 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, "acorn-walk": { @@ -13675,55 +11127,34 @@ "debug": "4" } }, - "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } + "type-fest": "^0.21.3" } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -13742,7 +11173,7 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true }, "arr-flatten": { @@ -13754,40 +11185,25 @@ "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "atob": { @@ -13796,18 +11212,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", - "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==", - "dev": true - }, "babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -13822,6 +11226,57 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "babel-plugin-dynamic-import-node": { @@ -13834,15 +11289,15 @@ } }, "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" } }, @@ -13859,41 +11314,33 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", - "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.0", - "@babel/helper-define-polyfill-provider": "^0.1.5", + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.1.5", - "core-js-compat": "^3.8.1" + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", - "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.1.5" + "@babel/helper-define-polyfill-provider": "^0.3.1" } }, "babel-preset-current-node-syntax": { @@ -13927,9 +11374,9 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base": { @@ -13955,35 +11402,6 @@ "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -13993,15 +11411,6 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -14039,30 +11448,16 @@ "dev": true }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001230", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", - "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.739", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.739.tgz", - "integrity": "sha512-+LPJVRsN7hGZ9EIUUiWCpO7l4E3qBYHNadazlucBfsXBbccDFNKUBAgzE68FnkWGJPwD/AfKhSzL+G+Iqb8A4A==", - "dev": true - } + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" } }, "bser": { @@ -14087,13 +11482,13 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "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 }, "cache-base": { @@ -14135,6 +11530,12 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30001341", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", + "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", + "dev": true + }, "capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -14144,20 +11545,15 @@ "rsvp": "^4.8.4" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "char-regex": { @@ -14204,6 +11600,63 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, @@ -14241,24 +11694,18 @@ } }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "combined-stream": { @@ -14283,9 +11730,9 @@ "dev": true }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" @@ -14298,12 +11745,12 @@ "dev": true }, "core-js-compat": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.1.tgz", - "integrity": "sha512-jXAirMQxrkbiiLsCx9bQPJFA6llDadKMpYrBJQJ3/c4/vsPP/fAf29h24tviRlvwUL6AmY5CHLu2GvjuYviQqA==", + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", + "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", "dev": true, "requires": { - "browserslist": "^4.16.3", + "browserslist": "^4.20.3", "semver": "7.0.0" }, "dependencies": { @@ -14315,31 +11762,24 @@ } } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "node-fetch": "2.6.7" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "cssom": { @@ -14365,15 +11805,6 @@ } } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -14386,9 +11817,9 @@ } }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -14401,21 +11832,21 @@ "dev": true }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "deepmerge": { @@ -14425,12 +11856,13 @@ "dev": true }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "define-property": { @@ -14441,37 +11873,6 @@ "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } } }, "delayed-stream": { @@ -14487,9 +11888,9 @@ "dev": true }, "devtools-protocol": { - "version": "0.0.901419", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz", - "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==", + "version": "0.0.982423", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.982423.tgz", + "integrity": "sha512-FnVW2nDbjGNw1uD/JRC+9U5768W7e1TfUwqbDTcSsAu1jXFjITSX8w3rkW5FEpHRMPPGpvNSmO1pOpqByiWscA==", "dev": true }, "diff-sequences": { @@ -14515,15 +11916,11 @@ } } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } + "electron-to-chromium": { + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "dev": true }, "emittery": { "version": "0.7.2", @@ -14564,17 +11961,17 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" @@ -14587,9 +11984,9 @@ "dev": true }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -14599,24 +11996,26 @@ "dev": true }, "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" } }, "exit": { @@ -14667,6 +12066,69 @@ "is-extendable": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -14687,14 +12149,34 @@ "jest-matcher-utils": "^26.6.2", "jest-message-util": "^26.6.2", "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -14703,17 +12185,6 @@ "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "extglob": { @@ -14750,34 +12221,11 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true } } }, @@ -14791,31 +12239,8 @@ "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -14871,20 +12296,14 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, @@ -14952,9 +12371,9 @@ "dev": true }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -14966,25 +12385,16 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -14996,9 +12406,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "growly": { @@ -15008,22 +12418,6 @@ "dev": true, "optional": true }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -15034,15 +12428,24 @@ } }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "has-value": { @@ -15118,21 +12521,21 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" } }, "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "requires": { "agent-base": "6", @@ -15161,9 +12564,9 @@ "dev": true }, "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -15192,30 +12595,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.0" } }, "is-arrayish": { @@ -15240,65 +12626,49 @@ } }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" } }, "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.0" } }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "optional": true }, "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -15328,15 +12698,15 @@ } }, "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "is-typedarray": { @@ -15379,27 +12749,22 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "requires": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, @@ -15412,12 +12777,29 @@ "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -15426,9 +12808,9 @@ } }, "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -15444,29 +12826,6 @@ "@jest/core": "^26.6.3", "import-local": "^3.0.2", "jest-cli": "^26.6.3" - }, - "dependencies": { - "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - } - } } }, "jest-changed-files": { @@ -15478,88 +12837,76 @@ "@jest/types": "^26.6.2", "execa": "^4.0.0", "throat": "^5.0.0" + } + }, + "jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "dev": true, + "requires": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" }, "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "color-convert": "^2.0.1" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "pump": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "path-key": "^3.0.0" + "color-name": "~1.1.4" } }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "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 }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "isexe": "^2.0.0" + "has-flag": "^4.0.0" } } } @@ -15588,6 +12935,57 @@ "jest-validate": "^26.6.2", "micromatch": "^4.0.2", "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-diff": { @@ -15600,6 +12998,57 @@ "diff-sequences": "^26.6.2", "jest-get-type": "^26.3.0", "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-docblock": { @@ -15622,6 +13071,57 @@ "jest-get-type": "^26.3.0", "jest-util": "^26.6.2", "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-environment-jsdom": { @@ -15705,6 +13205,57 @@ "jest-util": "^26.6.2", "pretty-format": "^26.6.2", "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-leak-detector": { @@ -15727,6 +13278,57 @@ "jest-diff": "^26.6.2", "jest-get-type": "^26.3.0", "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-message-util": { @@ -15744,6 +13346,57 @@ "pretty-format": "^26.6.2", "slash": "^3.0.0", "stack-utils": "^2.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-mock": { @@ -15785,14 +13438,53 @@ "slash": "^3.0.0" }, "dependencies": { - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "has-flag": "^4.0.0" } } } @@ -15834,6 +13526,57 @@ "jest-worker": "^26.6.2", "source-map-support": "^0.5.6", "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-runtime": { @@ -15869,6 +13612,57 @@ "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^15.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-serializer": { @@ -15905,14 +13699,63 @@ "semver": "^7.3.2" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -15928,6 +13771,57 @@ "graceful-fs": "^4.2.4", "is-ci": "^2.0.0", "micromatch": "^4.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-validate": { @@ -15944,29 +13838,129 @@ "pretty-format": "^26.6.2" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "dev": true, + "requires": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, - "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - } - }, "jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -15976,6 +13970,23 @@ "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^7.0.0" + }, + "dependencies": { + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "js-tokens": { @@ -15994,43 +14005,38 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" } }, @@ -16046,44 +14052,11 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true }, "kind-of": { "version": "6.0.3", @@ -16114,9 +14087,9 @@ } }, "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, "locate-path": { @@ -16140,12 +14113,6 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -16165,12 +14132,12 @@ } }, "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "requires": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, "map-cache": { @@ -16195,28 +14162,28 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -16226,18 +14193,18 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mixin-deep": { @@ -16248,17 +14215,6 @@ "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "mkdirp": { @@ -16266,6 +14222,12 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -16304,10 +14266,37 @@ "dev": true }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-int64": { "version": "0.4.0", @@ -16315,16 +14304,10 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, "node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, "optional": true, "requires": { @@ -16337,31 +14320,21 @@ }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "optional": true, "requires": { "lru-cache": "^6.0.0" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } } } }, "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "dev": true }, "normalize-package-data": { @@ -16391,12 +14364,12 @@ "dev": true }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" } }, "nwsapi": { @@ -16405,12 +14378,6 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -16431,6 +14398,43 @@ "is-descriptor": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -16559,9 +14563,9 @@ } }, "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "pascalcase": { @@ -16583,9 +14587,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { @@ -16600,26 +14604,23 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true }, "pkg-dir": { "version": "4.2.0", @@ -16652,22 +14653,48 @@ "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "prompts": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", - "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "requires": { "kleur": "^3.0.3", - "sisteransi": "^1.0.4" + "sisteransi": "^1.0.5" } }, "proxy-from-env": { @@ -16699,35 +14726,44 @@ "dev": true }, "puppeteer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-10.2.0.tgz", - "integrity": "sha512-OR2CCHRashF+f30+LBOtAjK6sNtz2HEyTr5FqAvhf8lR/qB3uBRoIZOwQKgwoyZnMBsxX7ZdazlyBgGjpnkiMw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-14.1.0.tgz", + "integrity": "sha512-T3eB4f6k9HVttYvyy8drGIKb04M+vxhepqM7qqcVCBTNT3T6M9cUaJT4k7P+a6wSonObJSJUP98JkPDQG+3fJw==", "dev": true, "requires": { - "debug": "4.3.1", - "devtools-protocol": "0.0.901419", + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.982423", "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "node-fetch": "2.6.1", + "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", - "progress": "2.0.1", + "progress": "2.0.3", "proxy-from-env": "1.1.0", "rimraf": "3.0.2", - "tar-fs": "2.0.0", - "unbzip2-stream": "1.3.3", - "ws": "7.4.6" + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.6.0" + }, + "dependencies": { + "ws": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz", + "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==", + "dev": true, + "requires": {} + } } }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, "read-pkg": { @@ -16759,6 +14795,14 @@ "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "readable-stream": { @@ -16779,24 +14823,24 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, "requires": { "@babel/runtime": "^7.8.4" @@ -16813,29 +14857,29 @@ } }, "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, "regjsparser": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.7.tgz", - "integrity": "sha512-ib77G0uxsA2ovgiYbCVGx4Pv3PSttAx2vIwidqQzbL2U5S4Q+j00HdSAneSBuyVcMvEnTXMjiGgB+DlXozVhpQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -16856,9 +14900,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -16867,84 +14911,6 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16957,13 +14923,21 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -17085,6 +15059,34 @@ } } }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -17108,6 +15110,21 @@ } } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -17128,6 +15145,12 @@ } } }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -17158,6 +15181,42 @@ "remove-trailing-separator": "^1.0.1" } }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", @@ -17167,6 +15226,15 @@ "is-number": "^3.0.0", "repeat-string": "^1.6.1" } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -17211,22 +15279,28 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true } } }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "shellwords": { @@ -17237,9 +15311,9 @@ "optional": true }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "sisteransi": { @@ -17297,6 +15371,69 @@ "is-extendable": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -17330,35 +15467,6 @@ "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -17402,9 +15510,9 @@ } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "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, "requires": { "buffer-from": "^1.0.0", @@ -17444,9 +15552,9 @@ } }, "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", "dev": true }, "split-string": { @@ -17464,27 +15572,10 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -17516,15 +15607,66 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -17543,9 +15685,9 @@ } }, "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "requires": { "char-regex": "^1.0.2", @@ -17553,23 +15695,23 @@ } }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-bom": { @@ -17591,24 +15733,47 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" + }, + "dependencies": { + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -17616,26 +15781,15 @@ "dev": true }, "tar-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", - "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "requires": { "chownr": "^1.1.1", - "mkdirp": "^0.5.1", + "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", - "tar-stream": "^2.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - } + "tar-stream": "^2.1.4" } }, "tar-stream": { @@ -17685,9 +15839,9 @@ "dev": true }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { @@ -17738,40 +15892,26 @@ } }, "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -17788,9 +15928,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, "typedarray-to-buffer": { @@ -17803,9 +15943,9 @@ } }, "unbzip2-stream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, "requires": { "buffer": "^5.2.1", @@ -17813,31 +15953,31 @@ } }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "union-value": { @@ -17850,8 +15990,22 @@ "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + } } }, + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -17892,21 +16046,22 @@ } } }, - "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -17927,9 +16082,9 @@ "optional": true }, "v8-to-istanbul": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", - "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -17955,17 +16110,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -17985,12 +16129,12 @@ } }, "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "webidl-conversions": { @@ -18015,20 +16159,20 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", + "lodash": "^4.7.0", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -18041,9 +16185,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "wrap-ansi": { @@ -18055,6 +16199,32 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "wrappy": { @@ -18076,9 +16246,9 @@ } }, "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true, "requires": {} }, @@ -18095,9 +16265,9 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yallist": { diff --git a/test/frontend/package.json b/test/frontend/package.json index 3ee59f9655..ca42a09d96 100644 --- a/test/frontend/package.json +++ b/test/frontend/package.json @@ -9,7 +9,7 @@ "babel-jest": "^26.6.3", "jest": "^26.6.3", "lodash": "^4.17.21", - "puppeteer": "^10.2.0" + "puppeteer": "^14.1.0" }, "scripts": { "test": "jest --verbose --runInBand" diff --git a/test/helpers.jl b/test/helpers.jl index c259e5d232..ff7406b42d 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -1,119 +1,37 @@ -import Pluto -import Pluto.ExpressionExplorer -import Pluto.ExpressionExplorer: SymbolsState, compute_symbolreferences, FunctionNameSignaturePair, UsingsImports, compute_usings_imports -using Test -import Distributed - -function Base.show(io::IO, s::SymbolsState) - print(io, "SymbolsState([") - join(io, s.references, ", ") - print(io, "], [") - join(io, s.assignments, ", ") - print(io, "], [") - join(io, s.funccalls, ", ") - print(io, "], [") - if isempty(s.funcdefs) - print(io, "]") - else - println(io) - for (k, v) in s.funcdefs - print(io, " ", k, ": ", v) - println(io) - end - print(io, "]") - end - if !isempty(s.macrocalls) - print(io, "], [") - print(io, s.macrocalls) - print(io, "])") - else - print(io, ")") - end +# Collect timing and allocations information; this is printed later. +using TimerOutputs: TimerOutput, @timeit +const TOUT = TimerOutput() +macro timeit_include(path::AbstractString) :(@timeit TOUT $path include($path)) end +function print_timeroutput() + # Sleep to avoid old logs getting tangled up in the output. + sleep(6) + println() + show(TOUT; compact=true, sortby=:firstexec) + println() end -"Calls `ExpressionExplorer.compute_symbolreferences` on the given `expr` and test the found SymbolsState against a given one, with convient syntax. - -# Example - -```jldoctest -julia> @test testee(:( - begin - a = b + 1 - f(x) = x / z - end), - [:b, :+], # 1st: expected references - [:a, :f], # 2nd: expected definitions - [:+], # 3rd: expected function calls - [ - :f => ([:z, :/], [], [:/], []) - ]) # 4th: expected function definitions, with inner symstate using the same syntax -true -``` -" -function testee(expr, expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = []; verbose::Bool=true) - expected = easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls) - - original_hash = Pluto.PlutoRunner.expr_hash(expr) - result = compute_symbolreferences(expr) - new_hash = Pluto.PlutoRunner.expr_hash(expr) - if original_hash != new_hash - error("\n== The expression explorer modified the expression. Don't do that! ==\n") - end +@timeit TOUT "import Pluto" import Pluto +using ExpressionExplorer +using Sockets +using Test +using HTTP +import Pkg +import Malt +import Malt.Distributed - # Anonymous function are given a random name, which looks like anon67387237861123 - # To make testing easier, we rename all such functions to anon - new_name(sym) = startswith(string(sym), "anon") ? :anon : sym - result.assignments = Set(new_name.(result.assignments)) - result.funcdefs = let - newfuncdefs = Dict{FunctionNameSignaturePair,SymbolsState}() - for (k, v) in result.funcdefs - union!(newfuncdefs, Dict(FunctionNameSignaturePair(new_name.(k.name), "hello") => v)) - end - newfuncdefs - end - if verbose && expected != result - println() - println("FAILED TEST") - println(expr) - println() - dump(expr, maxdepth=20) - println() - @show expected - resulted = result - @show resulted - println() - end - return expected == result +function insert_cell!(notebook, cell) + notebook.cells_dict[cell.cell_id] = cell + push!(notebook.cell_order, cell.cell_id) end -""" -Like `testee` but actually a convenient syntax -""" -function test_expression_explorer(; expr, references=[], definitions=[], funccalls=[], funcdefs=[], macrocalls=[]) - testee(expr, references, definitions, funccalls, funcdefs, macrocalls) +function delete_cell!(notebook, cell) + deleteat!(notebook.cell_order, findfirst(==(cell.cell_id), notebook.cell_order)) + delete!(notebook.cells_dict, cell.cell_id) end -function easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = []) - array_to_set(array) = map(array) do k - new_k = k isa Symbol ? [k] : k - return new_k - end |> Set - new_expected_funccalls = array_to_set(expected_funccalls) - - new_expected_funcdefs = map(expected_funcdefs) do (k, v) - new_k = k isa Symbol ? [k] : k - new_v = v isa SymbolsState ? v : easy_symstate(v...) - return FunctionNameSignaturePair(new_k, "hello") => new_v - end |> Dict - - new_expected_macrocalls = array_to_set(expected_macrocalls) - - SymbolsState(Set(expected_references), Set(expected_definitions), new_expected_funccalls, new_expected_funcdefs, new_expected_macrocalls) -end - -function setcode(cell, newcode) +function setcode!(cell, newcode) cell.code = newcode end @@ -128,14 +46,34 @@ function occursinerror(needle, haystack::Pluto.Cell) haystack.errored && occursin(needle, haystack.output.body[:msg]) end -"Test notebook equality, ignoring cell UUIDs and such." -function notebook_inputs_equal(nbA, nbB; check_paths_equality=true) - x = !check_paths_equality || (normpath(nbA.path) == normpath(nbB.path)) +function expecterror(err, cell; strict=true) + cell.errored || return false + io = IOBuffer() + showerror(io, err) + msg = String(take!(io)) + if strict + return cell.output.body[:msg] == msg + else + return occursin(msg, cell.output.body[:msg]) + end +end - to_compare(cell) = (cell.cell_id, cell.code_folded, cell.code) - y = to_compare.(nbA.cells) == to_compare.(nbB.cells) - - x && y +"Test notebook equality, ignoring cell UUIDs and such." +macro test_notebook_inputs_equal(nbA, nbB, check_paths_equality::Bool=true) + quote + nbA = $(esc(nbA)) + nbB = $(esc(nbB)) + if $(check_paths_equality) + @test normpath(nbA.path) == normpath(nbB.path) + end + + @test length(nbA.cells) == length(nbB.cells) + @test getproperty.(nbA.cells, :cell_id) == getproperty.(nbB.cells, :cell_id) + @test getproperty.(nbA.cells, :code_folded) == getproperty.(nbB.cells, :code_folded) + @test getproperty.(nbA.cells, :code) == getproperty.(nbB.cells, :code) + @test get_metadata_no_default.(nbA.cells) == get_metadata_no_default.(nbB.cells) + + end |> Base.remove_linenums! end "Whether the given .jl file can be run without any errors. While notebooks cells can be in arbitrary order, their order in the save file must be topological. @@ -198,7 +136,16 @@ has_embedded_pkgfiles(nb::Pluto.Notebook) = Log an error message if there are any running processes created by Distrubted, that were not shut down. """ function verify_no_running_processes() - if length(Distributed.procs()) != 1 - @error "Not all notebook processes were closed during tests!" Distributed.procs() + if length(Distributed.procs()) != 1 || !isempty(Malt.__iNtErNaL_get_running_procs()) + @error "Not all notebook processes were closed during tests!" Distributed.procs() Malt.__iNtErNaL_get_running_procs() end -end \ No newline at end of file +end + +# We have our own registry for these test! Take a look at https://github.com/JuliaPluto/PlutoPkgTestRegistry#readme for more info about the test packages and their dependencies. + +const pluto_test_registry_spec = Pkg.RegistrySpec(; + url="https://github.com/JuliaPluto/PlutoPkgTestRegistry", + uuid=Base.UUID("96d04d5f-8721-475f-89c4-5ee455d3eda0"), + name="PlutoPkgTestRegistry", +) + diff --git a/test/packages/Basic.jl b/test/packages/Basic.jl index b87dea6f02..1a6fc93926 100644 --- a/test/packages/Basic.jl +++ b/test/packages/Basic.jl @@ -2,28 +2,20 @@ import Pkg using Test using Pluto.Configuration: CompilerOptions -using Pluto.WorkspaceManager: _merge_notebook_compiler_options import Pluto: update_save_run!, update_run!, WorkspaceManager, ClientSession, ServerSession, Notebook, Cell, project_relative_path, SessionActions, load_notebook import Pluto.PkgUtils import Pluto.PkgCompat -import Distributed +import Malt -const pluto_test_registry_spec = Pkg.RegistrySpec(; - url="https://github.com/JuliaPluto/PlutoPkgTestRegistry", - uuid=Base.UUID("96d04d5f-8721-475f-89c4-5ee455d3eda0"), - name="PlutoPkgTestRegistry", -) @testset "Built-in Pkg" begin - # Pkg.Registry.rm("General") + # We have our own registry for these test! Take a look at https://github.com/JuliaPluto/PlutoPkgTestRegistry#readme for more info about the test packages and their dependencies. Pkg.Registry.add(pluto_test_registry_spec) - - @testset "Basic" begin - fakeclient = ClientSession(:fake, nothing) + @testset "Basic $(use_distributed_stdlib ? "Distributed" : "Malt")" for use_distributed_stdlib in (false, true) 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient + 🍭.options.evaluation.workspace_use_distributed_stdlib = use_distributed_stdlib # See https://github.com/JuliaPluto/PlutoPkgTestRegistry @@ -41,7 +33,6 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; Cell("eval(:(import DataFrames))"), Cell("import HelloWorldC_jll"), ]) - fakeclient.connected_notebook = notebook @test !notebook.nbpkg_ctx_instantiated @@ -55,7 +46,9 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test notebook.nbpkg_restart_recommended_msg === nothing @test notebook.nbpkg_restart_required_msg === nothing @test notebook.nbpkg_ctx_instantiated + @test notebook.nbpkg_install_time_ns > 0 @test notebook.nbpkg_busy_packages |> isempty + last_install_time = notebook.nbpkg_install_time_ns terminals = notebook.nbpkg_terminal_outputs @@ -63,7 +56,8 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test haskey(terminals, "PlutoPkgTestD") # they were installed in one batch, so their terminal outputs should be the same @test terminals["PlutoPkgTestA"] == terminals["PlutoPkgTestD"] - + # " [9e88b42a] PackageName" should be present in terminal output + @test !isnothing(match(r"\[........\] ", terminals["PlutoPkgTestA"])) @test notebook.cells[2].output.body == "0.3.1" # A @test notebook.cells[8].output.body == "0.1.0" # D @@ -73,7 +67,7 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; old_A_terminal = deepcopy(terminals["PlutoPkgTestA"]) - @show old_A_terminal + # @show old_A_terminal update_save_run!(🍭, notebook, notebook.cells[[3, 4]]) # import B @@ -83,6 +77,10 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test notebook.nbpkg_ctx !== nothing @test notebook.nbpkg_restart_recommended_msg === nothing @test notebook.nbpkg_restart_required_msg === nothing + @test notebook.nbpkg_ctx_instantiated + @test notebook.nbpkg_install_time_ns > last_install_time + @test notebook.nbpkg_busy_packages |> isempty + last_install_time = notebook.nbpkg_install_time_ns @test haskey(terminals, "PlutoPkgTestB") @test terminals["PlutoPkgTestA"] == terminals["PlutoPkgTestD"] == old_A_terminal @@ -103,6 +101,7 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; notebook.nbpkg_restart_recommended_msg !== nothing || notebook.nbpkg_restart_required_msg !== nothing ) @test notebook.nbpkg_restart_required_msg !== nothing + @test notebook.nbpkg_install_time_ns > last_install_time # running cells again should persist the restart message @@ -182,7 +181,7 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; end ## remove `import Dates` - setcode(notebook.cells[9], "") + setcode!(notebook.cells[9], "") update_save_run!(🍭, notebook, notebook.cells[9]) # removing a stdlib does not require a restart @@ -195,13 +194,14 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; ## remove `import PlutoPkgTestD` - setcode(notebook.cells[7], "") + setcode!(notebook.cells[7], "") update_save_run!(🍭, notebook, notebook.cells[7]) @test noerror(notebook.cells[7]) @test notebook.nbpkg_ctx !== nothing @test notebook.nbpkg_restart_recommended_msg !== nothing # recommend restart @test notebook.nbpkg_restart_required_msg === nothing + @test notebook.nbpkg_install_time_ns === nothing # removing a package means that we lose our estimate @test count("PlutoPkgTestD", ptoml_contents()) == 0 @@ -213,16 +213,13 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; simple_import_notebook = read(simple_import_path, String) @testset "Manifest loading" begin - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient dir = mktempdir() path = joinpath(dir, "hello.jl") write(path, simple_import_notebook) notebook = SessionActions.open(🍭, path; run_async=false) - fakeclient.connected_notebook = notebook @test num_backups_in(dir) == 0 @@ -238,13 +235,60 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; WorkspaceManager.unmake_workspace((🍭, notebook)) end + + @testset "Package added by url" begin + url_notebook = read(joinpath(@__DIR__, "url_import.jl"), String) + 🍭 = ServerSession() - @testset "Pkg cell -- dynamically added" begin - fakeclient = ClientSession(:fake, nothing) + dir = mktempdir() + path = joinpath(dir, "hello.jl") + write(path, url_notebook) + + notebook = SessionActions.open(🍭, path; run_async=false) + + @test num_backups_in(dir) == 0 + + @test notebook.nbpkg_ctx !== nothing + @test notebook.nbpkg_restart_recommended_msg === nothing + @test notebook.nbpkg_restart_required_msg === nothing + + @test noerror(notebook.cells[1]) + @test noerror(notebook.cells[2]) + + @test notebook.cells[2].output.body == "1.0.0" + + WorkspaceManager.unmake_workspace((🍭, notebook)) + end + + future_notebook = read(joinpath(@__DIR__, "future_nonexisting_version.jl"), String) + @testset "Recovery from unavailable versions" begin 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient + dir = mktempdir() + path = joinpath(dir, "hello.jl") + write(path, future_notebook) + + notebook = SessionActions.open(🍭, path; run_async=false) + + @test num_backups_in(dir) == 0 + + + @test notebook.nbpkg_ctx !== nothing + @test notebook.nbpkg_restart_recommended_msg === nothing + @test notebook.nbpkg_restart_required_msg === nothing + + @test noerror(notebook.cells[1]) + @test noerror(notebook.cells[2]) + + @test notebook.cells[2].output.body == "0.3.1" + + WorkspaceManager.unmake_workspace((🍭, notebook)) + end + + + @testset "Pkg cell -- dynamically added" begin + 🍭 = ServerSession() notebook = Notebook([ Cell("1"), @@ -254,16 +298,15 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; Cell("5"), Cell("6"), ]) - fakeclient.connected_notebook = notebook update_save_run!(🍭, notebook, notebook.cells) # not necessary since there are no packages: # @test has_embedded_pkgfiles(notebook) - setcode(notebook.cells[1], "import Pkg") + setcode!(notebook.cells[1], "import Pkg") update_save_run!(🍭, notebook, notebook.cells[1]) - setcode(notebook.cells[2], "Pkg.activate(mktempdir())") + setcode!(notebook.cells[2], "Pkg.activate(mktempdir())") update_save_run!(🍭, notebook, notebook.cells[2]) @test noerror(notebook.cells[1]) @@ -273,21 +316,21 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test notebook.nbpkg_restart_required_msg === nothing @test !has_embedded_pkgfiles(notebook) - setcode(notebook.cells[3], "Pkg.add(\"JSON\")") + setcode!(notebook.cells[3], "Pkg.add(\"JSON\")") update_save_run!(🍭, notebook, notebook.cells[3]) - setcode(notebook.cells[4], "using JSON") + setcode!(notebook.cells[4], "using JSON") update_save_run!(🍭, notebook, notebook.cells[4]) - setcode(notebook.cells[5], "using Dates") + setcode!(notebook.cells[5], "using Dates") update_save_run!(🍭, notebook, notebook.cells[5]) @test noerror(notebook.cells[3]) @test noerror(notebook.cells[4]) - @test notebook.cells[5].errored == false + @test notebook.cells[5] |> noerror @test !has_embedded_pkgfiles(notebook) - setcode(notebook.cells[2], "2") - setcode(notebook.cells[3], "3") + setcode!(notebook.cells[2], "2") + setcode!(notebook.cells[3], "3") update_save_run!(🍭, notebook, notebook.cells[2:3]) @test notebook.nbpkg_ctx !== nothing @@ -298,11 +341,8 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; end pkg_cell_notebook = read(joinpath(@__DIR__, "pkg_cell.jl"), String) - @testset "Pkg cell -- loaded from file" begin - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient dir = mktempdir() for n in ["Project.toml", "Manifest.toml"] @@ -315,7 +355,6 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test num_backups_in(dir) == 0 notebook = SessionActions.open(🍭, path; run_async=false) - fakeclient.connected_notebook = notebook nb_contents() = read(notebook.path, String) @test num_backups_in(dir) == 0 @@ -357,19 +396,15 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; end @testset "DrWatson cell" begin - fakeclient = ClientSession(:fake, nothing) - 🍭 = ServerSession() - 🍭.options.evaluation.workspace_use_distributed = false - 🍭.connected_clients[fakeclient.id] = fakeclient + 🍭 = ServerSession() notebook = Notebook([ Cell("using Plots"), Cell("@quickactivate"), Cell("using DrWatson"), ]) - fakeclient.connected_notebook = notebook - notebook.topology = Pluto.updated_topology(Pluto.NotebookTopology(), notebook, notebook.cells) |> Pluto.static_resolve_topology + notebook.topology = Pluto.updated_topology(Pluto.NotebookTopology(cell_order=Pluto.ImmutableVector(notebook.cells)), notebook, notebook.cells) |> Pluto.static_resolve_topology @test !Pluto.use_plutopkg(notebook.topology) order = collect(Pluto.topological_order(notebook)) @@ -381,13 +416,10 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; end pre_pkg_notebook = read(joinpath(@__DIR__, "old_import.jl"), String) - local post_pkg_notebook = nothing @testset "File format -- Backwards compat" begin - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient dir = mktempdir() path = joinpath(dir, "hello.jl") @@ -396,7 +428,6 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test num_backups_in(dir) == 0 notebook = SessionActions.open(🍭, path; run_async=false) - fakeclient.connected_notebook = notebook nb_contents() = read(notebook.path, String) @test num_backups_in(dir) == 0 @@ -415,50 +446,55 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; WorkspaceManager.unmake_workspace((🍭, notebook)) end - @testset "File format -- Forwards compat" begin - # Using Distributed, we will create a new Julia process in which we install Pluto 0.14.7 (before PlutoPkg). We run the new notebook file on the old Pluto. - p = Distributed.addprocs(1) |> first - - @test post_pkg_notebook isa String - - Distributed.remotecall_eval(Main, p, quote - path = tempname() - write(path, $(post_pkg_notebook)) - import Pkg - # optimization: - if isdefined(Pkg, :UPDATED_REGISTRY_THIS_SESSION) - Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true - end - - Pkg.activate(mktempdir()) - Pkg.add(Pkg.PackageSpec(;name="Pluto",version=v"0.14.7")) - import Pluto - @assert Pluto.PLUTO_VERSION == v"0.14.7" - - s = Pluto.ServerSession() - s.options.evaluation.workspace_use_distributed = false - - nb = Pluto.SessionActions.open(s, path; run_async=false) - - nothing - end) - - # Cells that use Example will error because the package is not installed. - - # @test Distributed.remotecall_eval(Main, p, quote - # nb.cells[1].errored == false - # end) - @test Distributed.remotecall_eval(Main, p, quote - nb.cells[2].errored == false - end) - # @test Distributed.remotecall_eval(Main, p, quote - # nb.cells[3].errored == false - # end) - # @test Distributed.remotecall_eval(Main, p, quote - # nb.cells[3].output.body == "25" - # end) - - Distributed.rmprocs([p]) + @static if VERSION < v"1.10.0-0" # see https://github.com/fonsp/Pluto.jl/pull/2626#issuecomment-1671244510 + @testset "File format -- Forwards compat" begin + # Using Distributed, we will create a new Julia process in which we install Pluto 0.14.7 (before PlutoPkg). We run the new notebook file on the old Pluto. + test_worker = Malt.Worker() + + @test post_pkg_notebook isa String + + Malt.remote_eval_wait(Main, test_worker, quote + path = tempname() + write(path, $(post_pkg_notebook)) + import Pkg + # optimization: + if isdefined(Pkg, :UPDATED_REGISTRY_THIS_SESSION) + Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true + end + + Pkg.activate(;temp=true) + Pkg.add(Pkg.PackageSpec(;name="Pluto",version=v"0.14.7")) + # Distributed is required for old Pluto to work! + Pkg.add("Distributed") + + import Pluto + @info Pluto.PLUTO_VERSION + @assert Pluto.PLUTO_VERSION == v"0.14.7" + end) + + @test Malt.remote_eval_fetch(Main, test_worker, quote + s = Pluto.ServerSession() + nb = Pluto.SessionActions.open(s, path; run_async=false) + nb.cells[2].errored == false + end) + + # Cells that use Example will error because the package is not installed. + + # @test Malt.remote_eval_fetch(Main, test_worker, quote + # nb.cells[1].errored == false + # end) + @test Malt.remote_eval_fetch(Main, test_worker, quote + nb.cells[2].errored == false + end) + # @test Malt.remote_eval_fetch(Main, test_worker, quote + # nb.cells[3].errored == false + # end) + # @test Malt.remote_eval_fetch(Main, test_worker, quote + # nb.cells[3].output.body == "25" + # end) + + Malt.stop(test_worker) + end end @testset "PkgUtils -- reset" begin @@ -480,7 +516,7 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; write(f, simple_import_notebook) @test !occursin("0.3.1", read(f, String)) - + @test num_backups_in(dir) == 0 Pluto.update_notebook_environment(f) @@ -499,9 +535,7 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; original_path = joinpath(@__DIR__, "$(name).jl") original_contents = read(original_path, String) - fakeclient = ClientSession(:fake, nothing) 🍭 = ServerSession() - 🍭.connected_clients[fakeclient.id] = fakeclient dir = mktempdir() path = joinpath(dir, "hello.jl") @@ -510,7 +544,6 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test num_backups_in(dir) == 0 notebook = SessionActions.open(🍭, path; run_async=false) - fakeclient.connected_notebook = notebook nb_contents() = read(notebook.path, String) should_restart = ( @@ -547,12 +580,12 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; @test notebook.nbpkg_restart_recommended_msg === nothing @test notebook.nbpkg_restart_required_msg === nothing - setcode(notebook.cells[2], "1 + 1") + setcode!(notebook.cells[2], "1 + 1") update_save_run!(🍭, notebook, notebook.cells[2]) @test notebook.cells[2].output.body == "2" - setcode(notebook.cells[2], """ + setcode!(notebook.cells[2], """ begin import PlutoPkgTestD PlutoPkgTestD.MY_VERSION |> Text @@ -568,33 +601,180 @@ const pluto_test_registry_spec = Pkg.RegistrySpec(; end - # @test false + @testset "Race conditions" begin + 🍭 = ServerSession() + lag = 0.2 + 🍭.options.server.simulated_pkg_lag = lag + + # See https://github.com/JuliaPluto/PlutoPkgTestRegistry + + notebook = Notebook([ + Cell("import PlutoPkgTestA"), # cell 1 + Cell("PlutoPkgTestA.MY_VERSION |> Text"), + Cell("import PlutoPkgTestB"), # cell 3 + Cell("PlutoPkgTestB.MY_VERSION |> Text"), + Cell("import PlutoPkgTestC"), # cell 5 + Cell("PlutoPkgTestC.MY_VERSION |> Text"), + Cell("import PlutoPkgTestD"), # cell 7 + Cell("PlutoPkgTestD.MY_VERSION |> Text"), + Cell("import PlutoPkgTestE"), # cell 9 + Cell("PlutoPkgTestE.MY_VERSION |> Text"), + ]) + + @test !notebook.nbpkg_ctx_instantiated + + running_tasks = Task[] + remember(t) = push!(running_tasks, t) + + update_save_run!(🍭, notebook, notebook.cells[[7, 8]]; run_async=false) # import D (not async) + update_save_run!(🍭, notebook, notebook.cells[[1, 2]]; run_async=true) |> remember # import A + + for _ in 1:5 + sleep(lag / 2) + setcode!(notebook.cells[9], "import PlutoPkgTestE") + update_save_run!(🍭, notebook, notebook.cells[[9]]; run_async=true) |> remember # import E + + sleep(lag / 2) + setcode!(notebook.cells[9], "") + update_save_run!(🍭, notebook, notebook.cells[[9]]; run_async=true) |> remember # don't import E + end + + while !all(istaskdone, running_tasks) + @test all(noerror, notebook.cells) + + sleep(lag / 3) + end + + @test all(istaskdone, running_tasks) + wait.(running_tasks) + empty!(running_tasks) + + WorkspaceManager.unmake_workspace((🍭, notebook)) + end + + @testset "PlutoRunner Syntax Error" begin + 🍭 = ServerSession() - # @testset "File format" begin - # notebook = Notebook([ - # Cell("import PlutoPkgTestA"), # cell 1 - # Cell("PlutoPkgTestA.MY_VERSION |> Text"), - # Cell("import PlutoPkgTestB"), # cell 3 - # Cell("PlutoPkgTestB.MY_VERSION |> Text"), - # Cell("import PlutoPkgTestC"), # cell 5 - # Cell("PlutoPkgTestC.MY_VERSION |> Text"), - # Cell("import PlutoPkgTestD"), # cell 7 - # Cell("PlutoPkgTestD.MY_VERSION |> Text"), - # Cell("import PlutoPkgTestE"), # cell 9 - # Cell("PlutoPkgTestE.MY_VERSION |> Text"), - # Cell("eval(:(import DataFrames))") - # ]) + notebook = Notebook([ + Cell("1 +"), + Cell("PlutoRunner.throw_syntax_error"), + Cell("PlutoRunner.throw_syntax_error(1)"), + ]) - # file1 = tempname() - # notebook.path = file1 + update_run!(🍭, notebook, notebook.cells) - # save_notebook() + @test notebook.cells[1].errored + @test noerror(notebook.cells[2]) + @test notebook.cells[3].errored + @test Pluto.is_just_text(notebook.topology, notebook.cells[1]) + @test !Pluto.is_just_text(notebook.topology, notebook.cells[2]) # Not a syntax error form + @test Pluto.is_just_text(notebook.topology, notebook.cells[3]) - # save_notebook - # end + WorkspaceManager.unmake_workspace((🍭, notebook)) + end - + @testset "Precompilation" begin + compilation_dir = joinpath(DEPOT_PATH[1], "compiled", "v$(VERSION.major).$(VERSION.minor)") + @assert isdir(compilation_dir) + compilation_dir_testA = joinpath(compilation_dir, "PlutoPkgTestA") + precomp_entries() = readdir(mkpath(compilation_dir_testA)) + + # clear cache + let + # sleep workaround for julia issue 34700. + sleep(3) + isdir(compilation_dir_testA) && rm(compilation_dir_testA; force=true, recursive=true) + end + @test precomp_entries() == [] + + @testset "Match compiler options: $(match)" for match in [true, false] + + before_sync = precomp_entries() + + 🍭 = ServerSession() + # make compiler settings of the worker (not) match the server settings + let + # you can find out which settings are relevant for cache validation by running JULIA_DEBUG="loading" julia and then missing a cache. Example output on julia1.9.0-rc1: + # ┌ Debug: Rejecting cache file /Applications/Julia-1.9.0-beta4 ARM.app/Contents/Resources/julia/share/julia/compiled/v1.9/SuiteSparse_jll/ME9At_bvckq.ji for [top-level] since the flags are mismatched + # │ current session: use_pkgimages = true, debug_level = 1, check_bounds = 0, inline = true, opt_level = 2 + # │ cache file: use_pkgimages = true, debug_level = 1, check_bounds = 1, inline = true, opt_level = 2 + # └ @ Base loading.jl:2668 + flip = !match + if VERSION >= v"1.9.0-aaa" + 🍭.options.compiler.pkgimages = (flip ⊻ Base.JLOptions().use_pkgimages == 1) ? "yes" : "no" + end + 🍭.options.compiler.check_bounds = (flip ⊻ Base.JLOptions().check_bounds == 1) ? "yes" : "no" + 🍭.options.compiler.inline = (flip ⊻ Base.JLOptions().can_inline == 1) ? "yes" : "no" + 🍭.options.compiler.optimize = match ? Base.JLOptions().opt_level : 3 - Base.JLOptions().opt_level + # cant set the debug level but whatevs + end + + + notebook = Notebook([ + # An import for Pluto to recognize, but don't actually run it. When you run an import, Julia will precompile the package if necessary, which would skew our results. + Cell("false && import PlutoPkgTestA"), + ]) + + @test !notebook.nbpkg_ctx_instantiated + update_save_run!(🍭, notebook, notebook.cells) + @test notebook.nbpkg_ctx_instantiated + + after_sync = precomp_entries() + + # syncing should have called Pkg.precompile(), which should have generated new precompile caches. + # If `match == false`, then this is the second run, and the precompile caches should be different. + # These new caches use the same filename (weird...), EXCEPT when the pkgimages flag changed, then you get a new filename. + if match == true || VERSION >= v"1.9.0-aaa" + @test before_sync != after_sync + @test length(before_sync) < length(after_sync) + end + + + + # Now actually run the import. + setcode!(notebook.cells[1], """begin + ENV["JULIA_DEBUG"] = "loading" + + PlutoRunner.Logging.shouldlog(logger::PlutoRunner.PlutoCellLogger, level, _module, _...) = true # https://github.com/fonsp/Pluto.jl/issues/2487 + + import PlutoPkgTestA + end""") + update_save_run!(🍭, notebook, notebook.cells[1]) + @test noerror(notebook.cells[1]) + + after_run = precomp_entries() + + + # There should be a log message about loading the cache. + VERSION >= v"1.8.0-aaa" && @test any(notebook.cells[1].logs) do log + occursin(r"Loading.*cache"i, log["msg"][1]) + end + # There should NOT be a log message about rejecting the cache. + @test !any(notebook.cells[1].logs) do log + occursin(r"reject.*cache"i, log["msg"][1]) + end + + # Running the import should not have triggered additional precompilation, everything should have been precompiled during Pkg.precompile() (in sync_nbpkg). + @test after_sync == after_run + + WorkspaceManager.unmake_workspace((🍭, notebook)) + end + end + + @testset "Inherit load path" begin + notebook = Notebook([ + Cell("import Pkg; Pkg.activate()"), + Cell("LOAD_PATH[begin]"), + Cell("LOAD_PATH[end]"), + ]) + 🍭 = ServerSession() + update_run!(🍭, notebook, notebook.cells) + @test isnothing(notebook.nbpkg_ctx) + @test notebook.cells[2].output.body == sprint(Base.show, LOAD_PATH[begin]) + @test notebook.cells[3].output.body == sprint(Base.show, LOAD_PATH[end]) + WorkspaceManager.unmake_workspace((🍭, notebook)) + end Pkg.Registry.rm(pluto_test_registry_spec) # Pkg.Registry.add("General") @@ -605,4 +785,3 @@ end # LibGit2.checkout!(repo, "aef26d37e1d0e8f8387c011ccb7c4a38398a18f6") - diff --git a/test/packages/PkgCompat.jl b/test/packages/PkgCompat.jl index 9ca319b6fb..c30efc27bd 100644 --- a/test/packages/PkgCompat.jl +++ b/test/packages/PkgCompat.jl @@ -6,6 +6,7 @@ import Pkg @testset "PkgCompat" begin + PkgCompat.refresh_registry_cache() @testset "Available versions" begin vs = PkgCompat.package_versions("HTTP") @@ -28,6 +29,29 @@ import Pkg @test isempty(vs) @test !PkgCompat.package_exists("Dateskjashdfkjahsdfkjh") + + end + + @testset "Registry queries" begin + Pkg.Registry.add(pluto_test_registry_spec) + PkgCompat.refresh_registry_cache() + + es = PkgCompat._registry_entries("PlutoPkgTestA") + @test length(es) == 1 + @test occursin("P/PlutoPkgTestA", only(es)) + @test occursin("PlutoPkgTestRegistry", only(es)) + + es = PkgCompat._registry_entries("Pluto") + @test length(es) == 1 + @test occursin("P/Pluto", only(es)) + @test occursin("General", only(es)) + + es = PkgCompat._registry_entries("HelloWorldC_jll") + @test length(es) == 1 + @test occursin("H/HelloWorldC_jll", only(es)) + @test occursin("General", only(es)) + + Pkg.Registry.rm(pluto_test_registry_spec) end @testset "Installed versions" begin @@ -79,7 +103,7 @@ import Pkg @test haskey(ptoml["compat"], "PlutoPkgTestA") @test haskey(ptoml["compat"], "Artifacts") - notebook.nbpkg_ctx = PkgCompat.clear_stdlib_compat_entries(notebook.nbpkg_ctx) + PkgCompat.clear_stdlib_compat_entries!(notebook.nbpkg_ctx) ptoml = Pkg.TOML.parse(ptoml_contents()) @test haskey(ptoml["deps"], "PlutoPkgTestA") @@ -90,7 +114,7 @@ import Pkg end old_a_compat_entry = ptoml["compat"]["PlutoPkgTestA"] - notebook.nbpkg_ctx = PkgCompat.clear_auto_compat_entries(notebook.nbpkg_ctx) + PkgCompat.clear_auto_compat_entries!(notebook.nbpkg_ctx) ptoml = Pkg.TOML.parse(ptoml_contents()) @test haskey(ptoml["deps"], "PlutoPkgTestA") @@ -100,7 +124,7 @@ import Pkg @test !haskey(compat, "PlutoPkgTestA") @test !haskey(compat, "Artifacts") - notebook.nbpkg_ctx = PkgCompat.write_auto_compat_entries(notebook.nbpkg_ctx) + PkgCompat.write_auto_compat_entries!(notebook.nbpkg_ctx) ptoml = Pkg.TOML.parse(ptoml_contents()) @test haskey(ptoml["deps"], "PlutoPkgTestA") diff --git a/test/packages/future_nonexisting_version.jl b/test/packages/future_nonexisting_version.jl new file mode 100644 index 0000000000..8b2093e210 --- /dev/null +++ b/test/packages/future_nonexisting_version.jl @@ -0,0 +1,98 @@ +### A Pluto.jl notebook ### +# v0.15.0 + +using Markdown +using InteractiveUtils + +# ╔═╡ c581d17a-c965-11eb-1607-bbeb44933d25 +# This file imports a future version of PlutoPkgTestA: 99.99.99, which does not actually exist. + +# It is generated by modifying the simple_import.jl file by hand. + +import PlutoPkgTestA + +# ╔═╡ aef57966-ea36-478f-8724-e71430f10be9 +PlutoPkgTestA.MY_VERSION |> Text + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +PlutoPkgTestA = "419c6f8d-b8cd-4309-abdc-cee491252f94" + +[compat] +PlutoPkgTestA = "~99.99.99" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[LibGit2]] +deps = ["Printf"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Pkg]] +deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[PlutoPkgTestA]] +deps = ["Pkg"] +git-tree-sha1 = "6c9aa67135641123c559d59ba88e8cb938999999" +uuid = "419c6f8d-b8cd-4309-abdc-cee491252f94" +version = "99.99.99" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +""" + +# ╔═╡ Cell order: +# ╠═c581d17a-c965-11eb-1607-bbeb44933d25 +# ╠═aef57966-ea36-478f-8724-e71430f10be9 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/test/packages/old_artifacts_import.jl b/test/packages/old_artifacts_import.jl index 0d8a613d9b..993ce61b2a 100644 --- a/test/packages/old_artifacts_import.jl +++ b/test/packages/old_artifacts_import.jl @@ -7,7 +7,7 @@ using InteractiveUtils # ╔═╡ c581d17a-c965-11eb-1607-bbeb44933d25 # This file imports an outdated version of PlutoPkgTestA: 0.2.1 (which is stored in the embedded Manifest file) and Artifacts, which is now a standard library (as of Julia 1.6), but it used to be a registered package (https://github.com/JuliaPackaging/Artifacts.jl). This notebook was generated on Julia 1.5, so the Manifest will be very very confusing for Julia 1.6 and up. -# It is generated on Julia 1.5 (our oldest supported Julia version, Manifest.toml is not backwards-compatible): +# It is generated on Julia 1.5 (our oldest supported Julia version (at the time of writing), Manifest.toml is not backwards-compatible): # 1. add our test registry: # pkg> registry add https://github.com/JuliaPluto/PlutoPkgTestRegistry diff --git a/test/packages/simple_import.jl b/test/packages/simple_import.jl index c741ae26a3..65893283da 100644 --- a/test/packages/simple_import.jl +++ b/test/packages/simple_import.jl @@ -7,7 +7,7 @@ using InteractiveUtils # ╔═╡ c581d17a-c965-11eb-1607-bbeb44933d25 # This file imports an outdated version of PlutoPkgTestA: 0.2.2 (which is stored in the embedded Manifest file). -# It is generated on Julia 1.5 (our oldest supported Julia version, Manifest.toml is not backwards-compatible): +# It is generated on Julia 1.5 (our oldest supported Julia version (at the time of writing), Manifest.toml is not backwards-compatible): # 1. add our test registry: # pkg> registry add https://github.com/JuliaPluto/PlutoPkgTestRegistry diff --git a/test/packages/url_import.jl b/test/packages/url_import.jl new file mode 100644 index 0000000000..8b05d5d1d3 --- /dev/null +++ b/test/packages/url_import.jl @@ -0,0 +1,151 @@ +### A Pluto.jl notebook ### +# v0.19.18 + +using Markdown +using InteractiveUtils + +# ╔═╡ 3717ac9c-821f-11ed-14bc-d3b0f9fd1efe +import PlutoPkgTestF + +# ╔═╡ f6d8e48e-f400-4e27-8a83-f7bf2e72e992 +PlutoPkgTestF.MY_VERSION |> Text + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +PlutoPkgTestF = "7007ab80-a928-4ddc-1332-8dd20f5a112f" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[Downloads]] +deps = ["ArgTools", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" + +[[LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + +[[Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[PlutoPkgTestA]] +deps = ["Pkg"] +git-tree-sha1 = "9615c7f69a1780f70fe32890ac370728afbcb2f6" +uuid = "419c6f8d-b8cd-4309-abdc-cee491252f94" +version = "0.3.1" + +[[PlutoPkgTestF]] +deps = ["Pkg", "PlutoPkgTestA"] +git-tree-sha1 = "f486ebc1188475df900413cbd570ff7fabed738f" +repo-rev = "main" +repo-url = "https://github.com/JuliaPluto/PlutoPkgTestF.jl" +uuid = "7007ab80-a928-4ddc-1332-8dd20f5a112f" +version = "1.0.0" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[[Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" + +[[p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +""" + +# ╔═╡ Cell order: +# ╠═3717ac9c-821f-11ed-14bc-d3b0f9fd1efe +# ╠═f6d8e48e-f400-4e27-8a83-f7bf2e72e992 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/test/runtests.jl b/test/runtests.jl index 554de40c76..bbd8215e86 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,44 +1,55 @@ -include("./helpers.jl") +include("helpers.jl") # tests that start new processes: -include("./Events.jl") +@timeit_include("compiletimes.jl") verify_no_running_processes() -include("./WorkspaceManager.jl") +if get(ENV, "PLUTO_TEST_ONLY_COMPILETIMES", nothing) == "true" + print_timeroutput() + exit(0) +end +@timeit_include("Events.jl") verify_no_running_processes() -include("./packages/Basic.jl") +@timeit_include("Configuration.jl") verify_no_running_processes() -include("./Bonds.jl") +@timeit_include("packages/Basic.jl") verify_no_running_processes() -include("./RichOutput.jl") +@timeit_include("Bonds.jl") verify_no_running_processes() -include("./React.jl") +@timeit_include("RichOutput.jl") verify_no_running_processes() -include("./Dynamic.jl") +@timeit_include("React.jl") verify_no_running_processes() -include("./MacroAnalysis.jl") +@timeit_include("Dynamic.jl") verify_no_running_processes() -include("./webserver.jl") +@timeit_include("MacroAnalysis.jl") verify_no_running_processes() -include("./Notebook.jl") +@timeit_include("Logging.jl") verify_no_running_processes() -include("./Configuration.jl") +@timeit_include("webserver.jl") +verify_no_running_processes() +@timeit_include("Notebook.jl") +verify_no_running_processes() +@timeit_include("WorkspaceManager.jl") verify_no_running_processes() # tests that don't start new processes: -include("./ReloadFromFile.jl") -include("./packages/PkgCompat.jl") -include("./ExpressionExplorer.jl") -include("./MethodSignatures.jl") -include("./MoreAnalysis.jl") -include("./Analysis.jl") -include("./webserver_utils.jl") -include("./DependencyCache.jl") -include("./Throttled.jl") -include("./cell_disabling.jl") +@timeit_include("ReloadFromFile.jl") +@timeit_include("packages/PkgCompat.jl") +@timeit_include("MethodSignatures.jl") +@timeit_include("MoreAnalysis.jl") +@timeit_include("Analysis.jl") +@timeit_include("webserver_utils.jl") +@timeit_include("data structures.jl") +@timeit_include("DependencyCache.jl") +@timeit_include("Throttled.jl") +@timeit_include("cell_disabling.jl") verify_no_running_processes() +print_timeroutput() +@timeit_include("ExpressionExplorer.jl") + # TODO: test PlutoRunner functions like: # - from_this_notebook diff --git a/test/webserver.jl b/test/webserver.jl index 6d8a26d2af..401df2ace0 100644 --- a/test/webserver.jl +++ b/test/webserver.jl @@ -1,53 +1,129 @@ using HTTP using Test using Pluto -using Pluto: ServerSession, ClientSession, SessionActions +using Pluto: ServerSession, ClientSession, SessionActions, WorkspaceManager using Pluto.Configuration using Pluto.Configuration: notebook_path_suggestion, from_flat_kwargs, _convert_to_flags using Pluto.WorkspaceManager: WorkspaceManager, poll @testset "Web server" begin +@testset "base_url" begin + port = 13433 + host = "localhost" + + n_components = rand(2:6) + base_url = "/" + for _ in 1:n_components + base_url *= String(rand(collect('a':'z') ∪ collect('0':'9'), rand(5:10))) * "/" + end + local_url(suffix) = "http://$host:$port$base_url$suffix" + + @show local_url("favicon.ico") + server_running() = HTTP.get(local_url("favicon.ico")).status == 200 && HTTP.get(local_url("edit")).status == 200 + + # without notebook at startup + options = Pluto.Configuration.from_flat_kwargs(; + port, + launch_browser=false, + workspace_use_distributed=true, + require_secret_for_access=false, + require_secret_for_open_links=false, + base_url, + ) + 🍭 = Pluto.ServerSession(; options) + server = Pluto.run!(🍭) + + @test server_running() + + sleep(3) + @test poll(20) do + # should not exist because of the base url setting + HTTP.get("http://$host:$port/edit"; status_exception=false).status == 404 + end + + for notebook in values(🍭.notebooks) + SessionActions.shutdown(🍭, notebook; keep_in_session=false) + end + + close(server) +end + +@testset "UTF-8 to Codemirror UTF-16 byte mapping" begin + # range ends are non inclusives + tests = [ + (" aaaa", (2, 4), (1, 3)), # cm is zero based + (" 🍕🍕", (2, 6), (1, 3)), # a 🍕 is two UTF16 codeunits + (" 🍕🍕", (6, 10), (3, 5)), # a 🍕 is two UTF16 codeunits + ] + for (s, (start_byte, end_byte), (from, to)) in tests + @test PlutoRunner.map_byte_range_to_utf16_codepoints(s, start_byte, end_byte) == (from, to) + end +end + @testset "Exports" begin + port, socket = + @inferred Pluto.port_serversocket(Sockets.ip"0.0.0.0", nothing, 5543) + + close(socket) + @test 5543 <= port < 5600 + port = 13432 host = "localhost" local_url(suffix) = "http://$host:$port/$suffix" - + server_running() = HTTP.get(local_url("favicon.ico")).status == 200 && HTTP.get(local_url("edit")).status == 200 - + # without notebook at startup - options = Pluto.Configuration.from_flat_kwargs(; port=port, launch_browser=false, workspace_use_distributed=false, require_secret_for_access=false, require_secret_for_open_links=false) - 🍭 = Pluto.ServerSession(; options=options) - server_task = @async Pluto.run(🍭) - @test poll(5) do - server_running() - end + options = Pluto.Configuration.from_flat_kwargs(; + port, launch_browser=false, + workspace_use_distributed=true, + require_secret_for_access=false, + require_secret_for_open_links=false + ) + 🍭 = Pluto.ServerSession(; options) + server = Pluto.run!(🍭) + + @test server_running() @test isempty(🍭.notebooks) - download(local_url("sample/JavaScript.jl")) + HTTP.get(local_url("sample/JavaScript.jl"); retry=false) - @test poll(5) do + # wait for the notebook to be added to the session + @test poll(10) do length(🍭.notebooks) == 1 end notebook = only(values(🍭.notebooks)) - file_contents = read(download(local_url("notebookfile?id=$(notebook.notebook_id)")), String) + # right now, the notebook was only added to the session and assigned an ID. Let's wait for it to get a process: + @test poll(60) do + haskey(WorkspaceManager.active_workspaces, notebook.notebook_id) + end + sleep(1) - @assert file_contents == sprint(Pluto.save_notebook, notebook) + # Note that the notebook is running async right now! It's not finished yet. But we can already run these tests: + + fileA = download(local_url("notebookfile?id=$(notebook.notebook_id)")) + fileB = tempname() + write(fileB, sprint(Pluto.save_notebook, notebook)) + + @test Pluto.only_versions_or_lineorder_differ(fileA, fileB) export_contents = read(download(local_url("notebookexport?id=$(notebook.notebook_id)")), String) - @assert occursin(string(Pluto.PLUTO_VERSION), export_contents) - @assert occursin("", export_contents) + @test occursin(string(Pluto.PLUTO_VERSION), export_contents) + @test occursin("", export_contents) - WorkspaceManager.unmake_workspace((🍭, notebook)) + for notebook in values(🍭.notebooks) + SessionActions.shutdown(🍭, notebook; keep_in_session=false) + end - @async schedule(server_task, InterruptException(); error=true) + close(server) end end # testset diff --git a/tsconfig.json b/tsconfig.json index 325a962efa..710ed84a27 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,15 +2,17 @@ "compilerOptions": { "target": "ES2021", "module": "ES2020", - "lib": ["ES2021", "DOM", "WebWorker"], + "lib": ["ES2021", "DOM", "WebWorker", "DOM.Iterable"], "allowJs": true, "checkJs": true, "noEmit": true, "strict": false, "noImplicitThis": true, "alwaysStrict": true, - "esModuleInterop": true + "esModuleInterop": true, + "strictNullChecks": true, + "skipDefaultLibCheck": true }, - "include": ["frontend/**/*.js", "node_modules/**/*.js"], - "exclude": [] + "include": ["frontend/**/*.js", "node_modules/**/*.js", "frontend/Desktop.d.ts"], + "exclude": ["frontend/components/CellInput/tests/"] }